From 6b3759a266a56d1bd6282a899782c72c33519dc1 Mon Sep 17 00:00:00 2001 From: Matt Brown Date: Fri, 27 Apr 2018 15:00:22 -0400 Subject: [PATCH] Fix #699 - prevent stubs from overriding known functions --- src/Psalm/Visitor/DependencyFinderVisitor.php | 22 ++++++++++ tests/AnnotationTest.php | 4 +- tests/ConfigTest.php | 40 +++++++++++++++++++ tests/stubs/polyfill.php | 11 +++++ 4 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 tests/stubs/polyfill.php diff --git a/src/Psalm/Visitor/DependencyFinderVisitor.php b/src/Psalm/Visitor/DependencyFinderVisitor.php index a3ae8f47e..d86993e2c 100644 --- a/src/Psalm/Visitor/DependencyFinderVisitor.php +++ b/src/Psalm/Visitor/DependencyFinderVisitor.php @@ -514,6 +514,28 @@ class DependencyFinderVisitor extends PhpParser\NodeVisitorAbstract implements P $this->file_storage->declaring_constants[$const->name->name] = $this->file_path; } } + } elseif ($this->codebase->register_global_functions && $node instanceof PhpParser\Node\Stmt\If_) { + if ($node->cond instanceof PhpParser\Node\Expr\BooleanNot) { + if ($node->cond->expr instanceof PhpParser\Node\Expr\FuncCall + && $node->cond->expr->name instanceof PhpParser\Node\Name + ) { + if ($node->cond->expr->name->parts === ['function_exists'] + && isset($node->cond->expr->args[0]) + && $node->cond->expr->args[0]->value instanceof PhpParser\Node\Scalar\String_ + && function_exists($node->cond->expr->args[0]->value->value) + ) { + return PhpParser\NodeTraverser::DONT_TRAVERSE_CHILDREN; + } + + if ($node->cond->expr->name->parts === ['class_exists'] + && isset($node->cond->expr->args[0]) + && $node->cond->expr->args[0]->value instanceof PhpParser\Node\Scalar\String_ + && class_exists($node->cond->expr->args[0]->value->value, false) + ) { + return PhpParser\NodeTraverser::DONT_TRAVERSE_CHILDREN; + } + } + } } } diff --git a/tests/AnnotationTest.php b/tests/AnnotationTest.php index b8a9e5e7f..82af918eb 100644 --- a/tests/AnnotationTest.php +++ b/tests/AnnotationTest.php @@ -894,7 +894,7 @@ class AnnotationTest extends TestCase $arr["a"]()', ], - 'magicMethodAnnotation' => [ + 'magicMethodValidAnnotations' => [ 'getString(); $child->setInteger(4); + /** @psalm-suppress MixedAssignment */ $b = $child->setString(5); $c = $child->getBool("hello"); $d = $child->getArray(); @@ -927,7 +928,6 @@ class AnnotationTest extends TestCase '$d' => 'array', '$e' => 'callable():string', ], - 'error_levels' => ['MixedAssignment'], ], ]; } diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php index 1fca7cce3..67cedef8f 100644 --- a/tests/ConfigTest.php +++ b/tests/ConfigTest.php @@ -19,6 +19,14 @@ class ConfigTest extends TestCase public static function setUpBeforeClass() { self::$config = new TestConfig(); + + if (!defined('PSALM_VERSION')) { + define('PSALM_VERSION', '2.0.0'); + } + + if (!defined('PHP_PARSER_VERSION')) { + define('PHP_PARSER_VERSION', '4.0.0'); + } } /** @@ -437,6 +445,38 @@ class ConfigTest extends TestCase $this->analyzeFile($file_path, new Context()); } + /** + * @return void + */ + public function testPolyfilledFunction() + { + $this->project_checker = $this->getProjectCheckerWithConfig( + TestConfig::loadFromXML( + dirname(__DIR__), + ' + + + + + + + + + ' + ) + ); + + $file_path = getcwd() . '/src/somefile.php'; + + $this->addFile( + $file_path, + 'analyzeFile($file_path, new Context()); + } + /** * @return void */ diff --git a/tests/stubs/polyfill.php b/tests/stubs/polyfill.php new file mode 100644 index 000000000..bff9ce6db --- /dev/null +++ b/tests/stubs/polyfill.php @@ -0,0 +1,11 @@ +