diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index ae29efb84c..36aabc5886 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -744,6 +744,23 @@ jobs: ../../bin/phpstan clear-result-cache ../bashunit -a exit_code "0" "../../bin/phpstan analyse --error-format=raw -c with-full-baseline.neon" ../bashunit -a exit_code "0" "../../bin/phpstan analyse --error-format=raw -c with-full-baseline.neon" + - script: | + cd e2e/baseline-trait-context-own-error + # A using class may report its own error with the same message and identifier + # as an error deduplicated directly into the trait: --generate-baseline records + # the class's own occurrence under the class path and the deduplicated error + # under the trait path. The trait-pathed entry hides the deduplicated error for + # every using class, so the class-pathed entry accounts only for the class's + # own occurrence: the generated baseline holds on re-run, with both an empty + # and a primed result cache. + ../../bin/phpstan clear-result-cache + ../../bin/phpstan --generate-baseline=baseline.neon + ../bashunit -a contains 'path: src/AMailer.php' "$(cat baseline.neon)" + ../bashunit -a contains 'path: src/SomeTrait.php' "$(cat baseline.neon)" + ../bashunit -a not_contains 'BMailer.php' "$(cat 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/baseline-trait-context-own-error/.gitignore b/e2e/baseline-trait-context-own-error/.gitignore new file mode 100644 index 0000000000..0fd5c01d90 --- /dev/null +++ b/e2e/baseline-trait-context-own-error/.gitignore @@ -0,0 +1 @@ +baseline.neon diff --git a/e2e/baseline-trait-context-own-error/phpstan.neon b/e2e/baseline-trait-context-own-error/phpstan.neon new file mode 100644 index 0000000000..5412eca929 --- /dev/null +++ b/e2e/baseline-trait-context-own-error/phpstan.neon @@ -0,0 +1,6 @@ +parameters: + level: 4 + paths: + - src + parallel: + maximumNumberOfProcesses: 1 diff --git a/e2e/baseline-trait-context-own-error/src/AMailer.php b/e2e/baseline-trait-context-own-error/src/AMailer.php new file mode 100644 index 0000000000..36d565f13c --- /dev/null +++ b/e2e/baseline-trait-context-own-error/src/AMailer.php @@ -0,0 +1,24 @@ +getTraitContexts(); if (count($traitContexts) > 0) { $errorTraitFilePath = $error->getTraitFilePath(); + + // An entry scoped to the trait file hides the deduplicated error for every + // using class: it takes precedence over the class-scoped entries, which then + // account only for the errors reported in the class files themselves. This + // is what --generate-baseline records when a using class has its own + // occurrence of the same error (same message and identifier). + if ($errorTraitFilePath !== null) { + $normalizedTraitFilePath = $this->fileHelper->normalizePath($errorTraitFilePath); + if (isset($this->ignoreErrorsByFile[$normalizedTraitFilePath])) { + $matchingTraitFileIgnoreErrors = $ignoreErrorsByFileAndIdentifier[$normalizedTraitFilePath][$identifierKey] + ??= self::filterIgnoreErrorsByIdentifier($this->ignoreErrorsByFile[$normalizedTraitFilePath], $identifier); + foreach ($matchingTraitFileIgnoreErrors as $ignoreError) { + $i = $ignoreError['index']; + $ignore = $ignoreError['ignoreError']; + if (!$processIgnoreError($error, $i, $ignore)) { + $ignoredErrors[] = [$error, $ignore]; + continue 2; + } + } + } + } + $remainingContexts = $traitContexts; foreach (array_keys($traitContexts) as $contextFilePath) { $contextError = $error->asReportedInTraitContext($contextFilePath);