markTestSkipped('Cannot run test, base class "SoapClient" does not exist!'); return; } $this->addFile( 'somefile.php', 'analyzeFile('somefile.php', new \Psalm\Context()); } /** * @return iterable,error_levels?:string[]}> */ public function providerValidCodeParse() { return [ 'notInCallMapTest' => [ ' [ ' [ 'barBar();', ], 'staticInvocation' => [ ' [ ' [ ' [ 'sub(new DateInterval("P1D")); $b = (new DateTimeImmutable())->modify("+3 hours");', 'assertions' => [ '$yesterday' => 'MyDate|false', '$b' => 'DateTimeImmutable', ], ], 'magicCall' => [ 'bar();', ], 'canBeCalledOnMagic' => [ 'maybeUndefinedMethod();', 'assertions' => [], 'error_levels' => ['PossiblyUndefinedMethod'], ], 'canBeCalledOnMagicWithMethod' => [ 'bar();', 'assertions' => [], ], 'invokeCorrectType' => [ ' [ 'createElement("foo"); if ($node instanceof DOMElement) { $newnode = $doc->appendChild($node); $newnode->setAttribute("bar", "baz"); }', ], 'nonStaticSelfCall' => [ 'call());', ], 'simpleXml' => [ '"); $a = $xml->asXML(); $b = $xml->asXML("foo.xml");', 'assertions' => [ '$a' => 'false|string', '$b' => 'bool', ], ], 'datetimeformatNotFalse' => [ 'format($format); if (false !== $formatted) {} function takesString(string $s) : void {} takesString($formatted);', ], 'domElement' => [ 'getElementsByTagName("bar"); $b = $a->item(0); if (!$b) { return null; } return $b->getAttribute("bat"); }', ], 'domElementIteratorOrEmptyArray' => [ 'loadXML($XML); $elements = rand(0, 1) ? $dom->getElementsByTagName("bar") : []; foreach ($elements as $element) { $element->getElementsByTagName("bat"); } }', ], 'reflectionParameter' => [ 'getType(); if ($type === null) { return "mixed"; } return $type->getName(); }', ], 'PDOMethod' => [ 'sqliteCreateFunction("md5rev", "md5_and_reverse", 1);', ], 'dontConvertedMaybeMixedAfterCall' => [ ' $b */ function foo(array $a, array $b) : void { $c = array_merge($b, $a); foreach ($c as $d) { $d->foo(); if ($d instanceof B) {} } }', [], 'error_levels' => ['MixedAssignment', 'MixedMethodCall'], ], 'methodResolution' => [ 'getId()); (is_object($a) && method_exists($a, "getS")) ? (string)$a->getS() : ""; return $user->getId(); }', ], 'defineVariableCreatedInArgToMixed' => [ 'foo($b = (int) 5)) { echo $b; } }', [], 'error_levels' => ['MixedMethodCall', 'MissingParamType'], ], 'staticCallAfterMethodExists' => [ ' [ 'bar();', ], 'pdoStatementSetFetchMode' => [ 'setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $stmt = $db->prepare("select \"a\" as a"); $stmt->setFetchMode(PDO::FETCH_CLASS, A::class); $stmt->execute(); /** @psalm-suppress MixedAssignment */ $a = $stmt->fetch();', ], 'datePeriodConstructor' => [ ' [ 'bar(); } }' ], 'callMethodAfterCheckingExistenceInClosure' => [ 'bar(); })(); } }' ], 'callManyMethodsAfterCheckingExistence' => [ 'foo(); $object->bar(); }' ], 'callManyMethodsAfterCheckingExistenceChained' => [ 'foo(); $object->bar(); } }' ], 'callManyMethodsOnKnownObjectAfterCheckingExistenceChained' => [ 'foo(); $object->bar(); } }' ], 'preserveMethodExistsType' => [ ' [ ' $foo */ function foo(string $foo): string { if (!method_exists($foo, "something")) { return ""; } return $foo; }' ], ]; } /** * @return iterable */ public function providerInvalidCodeParse() { return [ 'staticInvocation' => [ ' 'InvalidStaticInvocation', ], 'parentStaticCall' => [ ' 'InvalidStaticInvocation', ], 'mixedMethodCall' => [ 'barBar();', 'error_message' => 'MixedMethodCall', 'error_levels' => [ 'MissingPropertyType', 'MixedAssignment', ], ], 'invalidMethodCall' => [ 'someMethod();', 'error_message' => 'InvalidMethodCall', ], 'possiblyInvalidMethodCall' => [ 'methodOfA(); } }', 'error_message' => 'PossiblyInvalidMethodCall', ], 'selfNonStaticInvocation' => [ ' 'NonStaticSelfCall', ], 'noParent' => [ ' 'ParentNotFound', ], 'coercedClass' => [ ' 'LessSpecificReturnStatement', 'error_levels' => ['MixedInferredReturnType', 'MixedReturnStatement', 'TypeCoercion', 'MixedMethodCall'], ], 'undefinedVariableStaticCall' => [ ' 'UndefinedGlobalVariable', ], 'staticCallOnString' => [ ' 'MixedAssignment', ], 'possiblyNullFunctionCall' => [ 'foo();', 'error_message' => 'InvalidScope', ], 'possiblyFalseReference' => [ 'bar();', 'error_message' => 'PossiblyFalseReference', ], 'undefinedParentClass' => [ ' 'MissingDependency - src' . DIRECTORY_SEPARATOR . 'somefile.php:7', ], 'variableMethodCallOnArray' => [ '$b();', 'error_message' => 'InvalidMethodCall', ], 'intVarStaticCall' => [ ' 'UndefinedClass', ], 'intVarNewCall' => [ ' 'UndefinedClass', ], 'invokeTypeMismatch' => [ ' 'InvalidScalarArgument', ], 'explicitInvokeTypeMismatch' => [ '__invoke(1);', 'error_message' => 'InvalidScalarArgument', ], 'undefinedMethodPassedAsArg' => [ 'foo(bar());', 'error_message' => 'UndefinedFunction', ], 'noIntersectionMethod' => [ 'zugzug(); }', 'error_message' => 'UndefinedInterfaceMethod - src' . DIRECTORY_SEPARATOR . 'somefile.php:7:29 - Method (B&A)::zugzug does not exist', ], 'noInstanceCallAsStatic' => [ ' 'InvalidStaticInvocation', ], 'noExceptionOnMissingClass' => [ ' */ protected $bar; public function foo(string $s): void { $bar = $this->bar; $bar::baz(); } }', 'error_message' => 'UndefinedClass', ], 'checkMixedMethodCallStaticMethodCallArg' => [ 'bar(B::bat()); }', 'error_message' => 'UndefinedMethod', ], 'complainAboutUndefinedPropertyOnMixedCall' => [ 'bar($this->d); } }', 'error_message' => 'UndefinedThisPropertyFetch', ], 'complainAboutUndefinedPropertyOnMixedCallConcatOp' => [ 'bar("bat" . $this->baz); } }', 'error_message' => 'UndefinedThisPropertyFetch', ], 'alreadyHasmethod' => [ 'foo(); } }', 'error_message' => 'RedundantCondition', ], 'possiblyNullOrMixedArg' => [ 'foo); }', 'error_message' => 'PossiblyNullArgument', ], 'callOnVoid' => [ 'foo()->bar();', 'error_message' => 'NullReference' ], ]; } }