diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index f5989b740b8..09ddd3bede0 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -297,6 +297,31 @@ jobs: ../bashunit -a contains 'FooTrait.php:10:Strict comparison using === between int<0, max> and false will always evaluate to false.' "$OUTPUT" ../bashunit -a contains 'FooTrait.php (in context of class E2EInTrait\Bar):18:Strict comparison using === between E2EInTrait\Bar and null will always evaluate to false.' "$OUTPUT" ../bashunit -a contains 'FooTrait.php (in context of class E2EInTrait\Foo):18:Strict comparison using === between E2EInTrait\Foo and null will always evaluate to false.' "$OUTPUT" + - script: | + cd e2e/bug-14718 + # https://github.com/phpstan/phpstan/issues/14718 + # An inline @phpstan-ignore on an error deduplicated directly into the trait must + # suppress it, consistently with both an empty and a primed result cache. + ../../bin/phpstan clear-result-cache + ../bashunit -a exit_code "0" "../../bin/phpstan --error-format=raw" + ../bashunit -a exit_code "0" "../../bin/phpstan --error-format=raw" + # With the ignore removed, the error is reported directly in the trait file. + sed -i 's# // @phpstan-ignore identical.alwaysFalse##' src/FooTrait.php + ../../bin/phpstan clear-result-cache + OUTPUT=$(../bashunit -a exit_code "1" "../../bin/phpstan --error-format=raw") + ../bashunit -a contains 'FooTrait.php:10:Strict comparison using === between int<0, max> and false will always evaluate to false.' "$OUTPUT" + # An ignoreErrors path may target the error by the trait file or by the using-class + # file - both keep working (no BC break). + ../../bin/phpstan clear-result-cache + ../bashunit -a exit_code "0" "../../bin/phpstan analyse --error-format=raw -c ignore-trait-path.neon" + ../../bin/phpstan clear-result-cache + ../bashunit -a exit_code "0" "../../bin/phpstan analyse --error-format=raw -c ignore-class-path.neon" + # A generated baseline suppresses the error on re-run, with both an empty and a + # primed result cache (the issue reported baseline generation as impossible). + ../../bin/phpstan --generate-baseline=baseline.neon + ../../bin/phpstan clear-result-cache + ../bashunit -a exit_code "0" "../../bin/phpstan analyse --error-format=raw -c with-baseline.neon" + ../bashunit -a exit_code "0" "../../bin/phpstan analyse --error-format=raw -c with-baseline.neon" - script: | cd e2e/result-cache-meta-extension composer install diff --git a/e2e/bug-14718/.gitignore b/e2e/bug-14718/.gitignore new file mode 100644 index 00000000000..6690328b14d --- /dev/null +++ b/e2e/bug-14718/.gitignore @@ -0,0 +1 @@ +/baseline.neon diff --git a/e2e/bug-14718/ignore-class-path.neon b/e2e/bug-14718/ignore-class-path.neon new file mode 100644 index 00000000000..f7c33389dcb --- /dev/null +++ b/e2e/bug-14718/ignore-class-path.neon @@ -0,0 +1,7 @@ +includes: + - phpstan.neon +parameters: + ignoreErrors: + - + identifier: identical.alwaysFalse + path: src/Foo.php diff --git a/e2e/bug-14718/ignore-trait-path.neon b/e2e/bug-14718/ignore-trait-path.neon new file mode 100644 index 00000000000..c988c58e5ed --- /dev/null +++ b/e2e/bug-14718/ignore-trait-path.neon @@ -0,0 +1,7 @@ +includes: + - phpstan.neon +parameters: + ignoreErrors: + - + identifier: identical.alwaysFalse + path: src/FooTrait.php diff --git a/e2e/bug-14718/phpstan.neon b/e2e/bug-14718/phpstan.neon new file mode 100644 index 00000000000..c308dcf5421 --- /dev/null +++ b/e2e/bug-14718/phpstan.neon @@ -0,0 +1,4 @@ +parameters: + level: 8 + paths: + - src diff --git a/e2e/bug-14718/src/Bar.php b/e2e/bug-14718/src/Bar.php new file mode 100644 index 00000000000..11a8023e727 --- /dev/null +++ b/e2e/bug-14718/src/Bar.php @@ -0,0 +1,10 @@ +getFilePath(); + $file = $tempCollectorError->getTraitFilePath() ?? $tempCollectorError->getFilePath(); $linesToIgnore = $allLinesToIgnore[$file] ?? []; $unmatchedLineIgnores = $allUnmatchedLineIgnores[$file] ?? []; $localIgnoresProcessorResult = $this->localIgnoresProcessor->process( diff --git a/src/Analyser/Error.php b/src/Analyser/Error.php index 107db06f08a..526594ed2fe 100644 --- a/src/Analyser/Error.php +++ b/src/Analyser/Error.php @@ -118,7 +118,7 @@ public function removeTraitContext(): self $this->line, $this->canBeIgnored, $this->filePath, - null, + $this->traitFilePath, $this->tip, $this->nodeLine, $this->nodeType, diff --git a/tests/PHPStan/Analyser/ErrorTest.php b/tests/PHPStan/Analyser/ErrorTest.php index e59abafff36..d4408a741d1 100644 --- a/tests/PHPStan/Analyser/ErrorTest.php +++ b/tests/PHPStan/Analyser/ErrorTest.php @@ -16,6 +16,23 @@ public function testError(): void $this->assertSame(10, $error->getLine()); } + public function testRemoveTraitContextKeepsTraitFilePath(): void + { + $error = new Error('Message', 'trait.php (in context of class C)', 11, true, 'user.php', 'trait.php'); + $this->assertSame('user.php', $error->getFilePath()); + $this->assertSame('trait.php', $error->getTraitFilePath()); + + $withoutTraitContext = $error->removeTraitContext(); + // The error is now reported directly in the trait: the displayed file is + // the trait, and traitFilePath is kept so the editor URL and the + // trait-file ignore lookups resolve to the trait (#14718). filePath stays + // the using-class file, so an ignoreErrors path keyed on either the trait + // or the using-class file keeps matching (no BC break). + $this->assertSame('trait.php', $withoutTraitContext->getFile()); + $this->assertSame('user.php', $withoutTraitContext->getFilePath()); + $this->assertSame('trait.php', $withoutTraitContext->getTraitFilePath()); + } + public static function dataValidIdentifier(): iterable { yield ['a'];