use_phpdoc_method_without_magic_or_parent = true; $this->addFile( 'somefile.php', 'getString(); $child->setInteger(4); /** @psalm-suppress MixedAssignment */ $b = $child->setString(5); $c = $child->getBool("hello"); $d = $child->getArray(); $e = $child->getCallable();' ); $this->analyzeFile('somefile.php', new Context()); } /** * @return void */ public function testAnnotationWithoutCallConfig() { $this->expectExceptionMessage('UndefinedMethod'); $this->expectException(\Psalm\Exception\CodeException::class); Config::getInstance()->use_phpdoc_method_without_magic_or_parent = false; $this->addFile( 'somefile.php', 'getString();' ); $context = new Context(); $this->analyzeFile('somefile.php', $context); } /** * @return void */ public function testOverrideParentClassRetunType() { Config::getInstance()->use_phpdoc_method_without_magic_or_parent = true; $this->addFile( 'somefile.php', 'analyzeFile('somefile.php', $context); $this->assertSame('Child', (string) $context->vars_in_scope['$child']); } /** * @return iterable,error_levels?:string[]}> */ public function providerValidCodeParse() { return [ 'validSimpleAnnotations' => [ 'getString(); $child->setInteger(4); /** @psalm-suppress MixedAssignment */ $b = $child->setString(5); $c = $child->getBool("hello"); $d = $child->getArray(); $child->setArray(["boo"]); $e = $child->getCallable(); $child->setMixed("hello"); $child->setMixed(4); $child->setImplicitMixed("hello"); $child->setImplicitMixed(4);', 'assertions' => [ '$a' => 'string', '$b' => 'mixed', '$c' => 'bool', '$d' => 'array', '$e' => 'callable():string', ], ], 'validAnnotationWithDefault' => [ 'setArray(["boo"]); $child->setArray(["boo"], 8);', ], 'validStaticAnnotationWithDefault' => [ ' [ '$a' => 'string', ], ], 'validAnnotationWithVariadic' => [ 'setInts(1, 2, 3, 4);', ], 'validUnionAnnotations' => [ 'setBool("hello", true); $c = $child->setBool("hello", "true"); $child->setAnotherArray(["boo"]);', 'assertions' => [ '$b' => 'bool', '$c' => 'bool', ], ], 'namespacedValidAnnotations' => [ 'setBool("hello", true); $c = $child->setBool("hello", "true");', ], 'globalMethod' => [ ' [ 'work()); } }', ], 'magicMethodOverridesParentWithMoreSpecificType' => [ ' [ 'hasMany("User", ["id" => "user_id"]) ->viaTable("account_to_user", ["account_id" => "id"]); return $query; } }', ], 'magicMethodReturnSelf' => [ 'getThis();', [ '$a' => 'C', '$b' => 'C', ], ], 'allowMagicMethodStatic' => [ 'getStatic(); $d = (new D)->getStatic();', [ '$c' => 'C', '$d' => 'D', ], ], 'validSimplePsalmAnnotations' => [ 'getString(); $child->setInteger(4);', 'assertions' => [ '$a' => 'string', ], ], 'overrideMethodAnnotations' => [ 'getString(); $child->setInteger(4);', 'assertions' => [ '$a' => 'string', ], ], 'alwaysAllowAnnotationOnInterface' => [ 'sayHello();', ], 'inheritInterfacePseudoMethodsFromParent' => [ 'getClassMetadata()); test(concreteEm()->getClassMetadata()); test2(em()->getOtherMetadata()); test2(concreteEm()->getOtherMetadata());', ], ]; } /** * @return iterable */ public function providerInvalidCodeParse() { return [ 'annotationWithBadDocblock' => [ ' 'InvalidDocblock', ], 'annotationWithByRefParam' => [ ' 'InvalidDocblock', ], 'annotationWithSealed' => [ 'getString(); $child->foo();', 'error_message' => 'UndefinedMethod - src' . DIRECTORY_SEPARATOR . 'somefile.php:14:29 - Method Child::foo does not exist', ], 'annotationInvalidArg' => [ 'setString("five");', 'error_message' => 'InvalidScalarArgument', ], 'unionAnnotationInvalidArg' => [ 'setBool("hello", 5);', 'error_message' => 'InvalidScalarArgument', ], 'validAnnotationWithInvalidVariadicCall' => [ 'setInts([1, 2, 3]);', 'error_message' => 'InvalidArgument', ], 'magicMethodOverridesParentWithDifferentReturnType' => [ ' 'ImplementedReturnTypeMismatch - src/somefile.php:11:33', ], 'magicMethodOverridesParentWithDifferentParamType' => [ ' 'ImplementedParamTypeMismatch - src/somefile.php:11:21', ], ]; } }