,error_levels?:string[]}> */ public function providerValidCodeParse(): iterable { return [ 'simplePureFunction' => [ ' [ ' [ '$1", $output); return $output; }' ], 'implicitAnnotations' => [ 'setOptions($options); $this->setDefaultOptions($this->getOptions()); } function getOptions(): array { return $this->options; } public final function setOptions(array $options): void { $this->options = $options; } public final function setDefaultOptions(array $defaultOptions): void { $this->defaultOptions = $defaultOptions; } }', ], 'canCreateObjectWithNoExternalMutations' => [ 'count = $count; } public function increment() : void { $this->count++; } public function incrementByTwo() : void { $this->count = $this->count + 2; } public function incrementByFive() : void { $this->count += 5; } } /** @psalm-pure */ function makesACounter(int $i) : Counter { $c = new Counter($i); $c->increment(); $c->incrementByTwo(); $c->incrementByFive(); return $c; }', ], 'canCreateImmutableObject' => [ 's = $s; } public function getShort() : string { return substr($this->s, 0, 5); } } /** @psalm-pure */ function makeA(string $s) : A { $a = new A($s); if ($a->getShort() === "bar") { return new A("foo"); } return $a; }' ], 'assertIsPureInProductionn' => [ ' [ ' [ ' [ ' $b; }); return $ar[0] ?? 0; }', ], 'allowPureToString' => [ ' [ 'getMessage(); } echo getMessage(new Exception("test"));' ], 'exceptionGetCode' => [ 'getCode(); } echo getCode(new Exception("test"));' ], 'exceptionGetFile' => [ 'getFile(); } echo getFile(new Exception("test"));' ], 'exceptionGetLine' => [ 'getLine(); } echo getLine(new Exception("test"));' ], 'exceptionGetTrace' => [ 'getTrace(); } echo count(getTrace(new Exception("test")));' ], 'exceptionGetPrevious' => [ 'getPrevious(); } echo gettype(getPrevious(new Exception("test")));' ], 'exceptionGetTraceAsString' => [ 'getTraceAsString(); } echo getTraceAsString(new Exception("test"));' ], 'callingMethodInThrowStillPure' => [ ' 9000) { throw MyException::hello(); } if ($sum > 90001) { throw new MyException(); } return $sum; }' ], 'countMethodCanBePure' => [ ' [ 'other = $other; } /** * @psalm-mutation-free * @psalm-assert !null $this->other */ public function checkNotNullNested(): bool { if ($this->other === null) { throw new RuntimeException("oops"); } return !!$this->other->other; } public function foo() : void {} public function doSomething(): void { $this->checkNotNullNested(); $this->other->foo(); } }' ], 'allowPropertyAccessOnImmutableClass' => [ 'a = $a; } } /** @psalm-pure */ function filterOdd(A $a) : bool { if ($a->a % 2 === 0) { return true; } return false; }', ], 'allowPropertyAccessOnImmutableClassAfterCloneModification' => [ 'a = $a; } } /** @psalm-pure */ function filterOdd(A $a) : bool { $a = clone $a; $a->a += 5; if ($a->a % 2 === 0) { return true; } return false; }', ], 'allowPureInConstrucctorThis' => [ 'isValidPort($portNumber)) { throw new Exception(); } $this->portNumber = $portNumber; } /** * @psalm-pure */ private function isValidPort(int $portNumber): bool { return $portNumber >= 1 && $portNumber <= 1000; } }' ], ]; } /** * @return iterable */ public function providerInvalidCodeParse(): iterable { return [ 'impurePropertyAssignment' => [ 'a = $i; if ($i % 2 === 0 || $a->a === 2) { return $i; } return null; }', 'error_message' => 'ImpurePropertyAssignment', ], 'impureMethodCall' => [ 'a++; } } /** @psalm-pure */ function filterOdd(int $i, A $a) : ?int { $a->foo(); if ($i % 2 === 0 || $a->a === 2) { return $i; } return null; }', 'error_message' => 'ImpureMethodCall', ], 'impureFunctionCall' => [ ' 'ImpureFunctionCall', ], 'impureConstructorCall' => [ 'a++; } } /** @psalm-pure */ function filterOdd(int $i, A $a) : ?int { $b = new B($a); if ($i % 2 === 0 || $a->a === 2) { return $i; } return null; }', 'error_message' => 'ImpureMethodCall', ], 'canCreateObjectWithNoExternalMutations' => [ 'count = $count; } public function increment() : void { $this->count += rand(0, 5); } } /** @psalm-pure */ function makesACounter(int $i) : Counter { $c = new Counter($i); $c->increment(); return $c; }', 'error_message' => 'ImpureMethodCall', ], 'useOfStaticMakesFunctionImpure' => [ ' 'ImpureStaticVariable', ], 'preventImpureArrayMapClosure' => [ ' 'ImpureFunctionCall', ], 'sortFunctionImpure' => [ ' $b; }); return $ar[0] ?? 0; }', 'error_message' => 'ImpureFunctionCall', ], 'impureByRef' => [ ' 'ImpureByReferenceAssignment' ], 'staticPropertyFetch' => [ ' 'ImpureStaticProperty', ], 'staticPropertyAssignment' => [ ' 'ImpureStaticProperty', ], 'preventImpureToStringViaComparison' => [ ' 'ImpureMethodCall' ], 'preventImpureToStringViaConcatenation' => [ ' 'ImpureMethodCall' ], 'countCanBeImpure' => [ ' 'ImpureFunctionCall', ], 'propertyFetchIsNotPure' => [ 'foo; } }', 'error_message' => 'ImpurePropertyFetch', ], 'preventPropertyAccessOnMutableClass' => [ 'a = $a; } } /** @psalm-pure */ function filterOdd(A $a) : bool { if ($a->a % 2 === 0) { return true; } return false; }', 'error_message' => 'ImpurePropertyFetch', ], 'preventIssetOnMutableClassKnownProperty' => [ 'a = $a; } } /** @psalm-pure */ function filterOdd(A $a) : bool { if (isset($a->a)) { return true; } return false; }', 'error_message' => 'ImpurePropertyFetch', ], 'preventIssetOnMutableClassUnknownProperty' => [ 'a = $a; } } /** @psalm-pure */ function filterOdd(A $a) : bool { if (isset($a->b)) { return true; } return false; }', 'error_message' => 'ImpurePropertyFetch', ], 'impureThis' => [ ' 'ImpureVariable', ], 'iterableIsNotPure' => [ ' $pieces * * @psalm-pure */ function foo(iterable $pieces): string { foreach ($pieces as $piece) { return $piece; } return "jello"; }', 'error_message' => 'ImpureMethodCall', ], ]; } }