-
Notifications
You must be signed in to change notification settings - Fork 0
Drop loose-comparison rule; add PHPStan + Psalm fixture guardrail #42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
c1c14d7
Drop loose-comparison rule; add PHPStan + Psalm fixture guardrail
MidnightDesign 2a6c0dd
Enforce SA overlap via per-fixture AND intersection
MidnightDesign c80a8c5
Make canary fixtures dual-purpose (CS + SA verification)
MidnightDesign f95db8c
Capture SA tool stderr for canary-missing diagnostics
MidnightDesign 45e7383
Restrict SA-overlap gate to one matrix entry
MidnightDesign 9d3c2aa
Fail fast in SA-overlap gate when a canary fixture is missing
MidnightDesign ac1a400
Merge branch 'master' into drop-lint-overlapping-rules
MidnightDesign d3f4298
Use explicit mktemp template for BSD/macOS portability
MidnightDesign d5c5a81
Surface jq failures in SA-overlap gate output
MidnightDesign f880d44
Document policy on not duplicating linter rules in README
MidnightDesign File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| #!/usr/bin/env bash | ||
| # CI gate: assert that PHPStan ∩ Psalm (over fixtures) equals exactly the set | ||
| # of fixtures registered below as "dropped-rule canaries". | ||
| # | ||
| # Each entry in EXPECTED_REL is a fixture demonstrating a pattern whose CS | ||
| # rule we dropped because lint already catches it. Two invariants: | ||
| # 1. Each canary MUST be flagged by both PHPStan and Psalm. Missing entries | ||
| # mean SA configs drifted, a tool crashed, or the JSON schema changed — | ||
| # fail loudly rather than silently letting fixtures through. | ||
| # 2. NO other fixture may appear in the intersection. A new fixture flagged | ||
| # by both SAs is "lint territory" — drop or rewrite it instead of adding | ||
| # a CS rule. | ||
| # | ||
| # Each canary also lives in tests/fixtures/valid/ so RulesTest::valid asserts | ||
| # the CS side: phpcs and php-cs-fixer must NOT flag it (= the CS rule really | ||
| # is disabled). | ||
| set -uo pipefail | ||
|
|
||
| if ! command -v jq >/dev/null 2>&1; then | ||
| echo "ERROR: jq is required but was not found in PATH." >&2 | ||
| echo "Install jq (e.g., 'apt-get install jq' or 'brew install jq')." >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| cd "$(dirname "$0")/.." | ||
|
|
||
| EXPECTED_REL=( | ||
| tests/fixtures/valid/loose-comparison.php | ||
| ) | ||
|
|
||
| for f in "${EXPECTED_REL[@]}"; do | ||
| if [ ! -f "$f" ]; then | ||
| echo "ERROR: registered canary fixture does not exist: $f" >&2 | ||
| echo "Update EXPECTED_REL in $(basename "$0") if the fixture was renamed or removed." >&2 | ||
| exit 1 | ||
| fi | ||
| done | ||
|
|
||
| expected="$(for f in "${EXPECTED_REL[@]}"; do realpath "$f"; done | sort -u)" | ||
|
|
||
| phpstan_stderr="$(mktemp "${TMPDIR:-/tmp}/check-sa-overlap.phpstan.XXXXXX")" | ||
| psalm_stderr="$(mktemp "${TMPDIR:-/tmp}/check-sa-overlap.psalm.XXXXXX")" | ||
| trap 'rm -f "$phpstan_stderr" "$psalm_stderr"' EXIT | ||
|
|
||
| phpstan_json="$(vendor/bin/phpstan analyse \ | ||
| --configuration tests/phpstan.neon \ | ||
| --error-format=json \ | ||
| --no-progress 2>"$phpstan_stderr" || true)" | ||
|
|
||
| psalm_json="$(vendor/bin/psalm \ | ||
| --config tests/psalm.xml \ | ||
| --output-format=json \ | ||
| --no-progress 2>"$psalm_stderr" || true)" | ||
|
|
||
| phpstan_files="$(printf '%s' "$phpstan_json" | jq -r '.files? | keys[]?' 2>>"$phpstan_stderr" | sort -u)" | ||
| psalm_files="$(printf '%s' "$psalm_json" | jq -r '.[]?.file_path // empty' 2>>"$psalm_stderr" | sort -u)" | ||
|
|
||
| intersection="$(comm -12 <(printf '%s\n' "$phpstan_files") <(printf '%s\n' "$psalm_files") | sed '/^$/d')" | ||
|
|
||
| missing="$(comm -23 <(printf '%s\n' "$expected") <(printf '%s\n' "$intersection"))" | ||
| extra="$(comm -13 <(printf '%s\n' "$expected") <(printf '%s\n' "$intersection"))" | ||
|
|
||
| if [ -n "$missing" ]; then | ||
| echo "ERROR: expected canary fixtures missing from PHPStan ∩ Psalm:" | ||
| printf '%s\n' "$missing" | sed 's/^/ - /' | ||
| echo | ||
| echo "PHPStan flagged:" | ||
| printf '%s\n' "${phpstan_files:-(nothing)}" | ||
| echo | ||
| echo "Psalm flagged:" | ||
| printf '%s\n' "${psalm_files:-(nothing)}" | ||
| echo | ||
| echo "PHPStan stderr:" | ||
| cat "$phpstan_stderr" 2>/dev/null || echo "(empty)" | ||
| echo | ||
| echo "Psalm stderr:" | ||
| cat "$psalm_stderr" 2>/dev/null || echo "(empty)" | ||
| echo | ||
| echo "SA configs may have drifted too lax, a tool may have crashed, or the JSON schema changed." | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [ -n "$extra" ]; then | ||
| echo "ERROR: the following fixtures are flagged by BOTH PHPStan and Psalm:" | ||
| printf '%s\n' "$extra" | sed 's/^/ - /' | ||
| echo | ||
| echo "Both major static analyzers already catch these patterns. A CS rule for" | ||
| echo "them duplicates lint work users already have. Drop the fixture (and any" | ||
| echo "corresponding CS rule), or rewrite it so only one SA catches it." | ||
| echo | ||
| echo "If this is a deliberate rule drop, also register the fixture in" | ||
| echo "EXPECTED_REL in this script." | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "OK: PHPStan ∩ Psalm matches the registered canary set exactly." | ||
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| // Dual-purpose fixture for the loose-comparison rule drop: | ||
| // - CS side: phpcs and php-cs-fixer must leave this alone (the rules are | ||
| // disabled — see Eventjet/ruleset.xml and php-cs-fixer-rules.php). | ||
| // - SA side: PHPStan and Psalm must both flag it — tests/check-sa-overlap.sh | ||
| // enforces that, which is what justifies dropping the CS rule. | ||
|
|
||
| $foo = 'foo' == 'bar'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| # PHPStan config for the test fixtures. | ||
| # | ||
| # This project is a coding-standard package, not an application. We don't lint | ||
| # our sniff/fixer sources with PHPStan (yet). PHPStan runs over the fixtures so | ||
| # that if someone adds a fixture demonstrating something PHPStan already catches, | ||
| # CI fails — that's the signal "this is lint territory, don't add a CS rule for it". | ||
| # | ||
| # If we ever want PHPStan to check the production sources too, add a separate | ||
| # config at the repository root. | ||
|
|
||
| parameters: | ||
| level: max | ||
| paths: | ||
| - fixtures | ||
| # Fixtures are isolated code snippets that routinely declare consts purely | ||
| # to exercise a syntactic pattern, with no consumer. classConstant.unused | ||
| # fires on that shape and is not a lint bug we want to catch in fixtures. | ||
| ignoreErrors: | ||
| - identifier: classConstant.unused | ||
|
|
||
| includes: | ||
| - ../vendor/phpstan/phpstan-phpunit/extension.neon | ||
| - ../vendor/phpstan/phpstan-phpunit/rules.neon | ||
| - ../vendor/phpstan/phpstan-strict-rules/rules.neon |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| <?xml version="1.0"?> | ||
| <!-- | ||
| Psalm config for the test fixtures. | ||
|
|
||
| This project is a coding-standard package, not an application. We don't run | ||
| Psalm against our sniff/fixer sources (yet). Psalm runs over the fixtures so | ||
| that if someone adds a fixture demonstrating something Psalm already catches, | ||
| CI fails — that's the signal "this is lint territory, don't add a CS rule for it". | ||
|
|
||
| Unused-symbol issues (UnusedClass, UnusedVariable, PossiblyUnusedMethod) and | ||
| structural opinions (ClassMustBeFinal, MissingOverrideAttribute, | ||
| MissingClassConstType) are suppressed because fixtures are isolated code | ||
| snippets, not real consumers — they will always look "unused" or "non-final". | ||
|
|
||
| If we ever want Psalm to check the production sources too, add a separate | ||
| config at the repository root. | ||
| --> | ||
| <psalm | ||
| errorLevel="1" | ||
| findUnusedBaselineEntry="true" | ||
| strictBinaryOperands="true" | ||
| > | ||
| <projectFiles> | ||
| <directory name="fixtures"/> | ||
| </projectFiles> | ||
| <issueHandlers> | ||
| <ClassMustBeFinal errorLevel="suppress"/> | ||
| <MissingOverrideAttribute errorLevel="suppress"/> | ||
| <UnusedClass errorLevel="suppress"/> | ||
| <UnusedVariable errorLevel="suppress"/> | ||
| <PossiblyUnusedMethod errorLevel="suppress"/> | ||
| <MissingClassConstType errorLevel="suppress"/> | ||
| </issueHandlers> | ||
| </psalm> |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.