Skip to content

suppression: a message of a sniff stands for its own row of the table - #2

Closed
JanTvrdik wants to merge 13 commits into
dg:masterfrom
JanTvrdik:jt-suppression-message-code
Closed

JanTvrdik wants to merge 13 commits into
dg:masterfrom
JanTvrdik:jt-suppression-message-code

Conversation

@JanTvrdik

@JanTvrdik JanTvrdik commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

A suppression comment that names a message code of a sniff, and not the sniff itself, was neither honored nor migrated:

public $First_Name; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps

Translator::findPaths() knew Squiz.NamingConventions.ValidVariableName, but not its message codes, so PluginRegistry::expandSuppressedName() returned nothing and the report stayed. phpcs prints these codes with -s, so projects write them often (the code base we are moving to DressCode has 33 of this one).

The table already has rows for single messages (Squiz.WhiteSpace.OperatorSpacing.Unary, Squiz.Commenting.FunctionComment.DuplicateReturn). This PR adds rows for the naming messages whose check DressCode has:

message decision
Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps naming.property
Squiz.NamingConventions.ValidVariableName.NotCamelCaps, .StringNotCamelCaps naming.variable
PSR1.Methods.CamelCapsMethodName.NotCamelCaps naming.method
Generic.NamingConventions.UpperCaseConstantName.ClassConstantNotUpperCase naming.constant (phpcs reports every const with it)

A suppression now silences what its message was about and nothing more: MemberNotCamelCaps silences naming.property, not naming.variable. A message without a row still silences nothing, as before. migrate-suppressions and suppressionComments read the same method, so they follow.

What the rows leave out:

  • UpperCaseConstantName.ConstantNotUpperCase gets no row: phpcs reports it only for define(), which DressCode does not check.
  • ValidVariableName.NotCamelCaps is also what phpcs reports for a promoted constructor parameter, which DressCode checks under naming.property, so such a suppression does not silence it. The row does not add naming.property, because a ruleset enabling NotCamelCaps alone would then check every property.

The rows also reach dresscode import:

  • A ruleset that enables a message alone (<rule ref="PSR1.Methods.CamelCapsMethodName.NotCamelCaps"> with an exclude pattern) now translates to its decision instead of "cannot enable alone".
  • A message excluded while the ruleset turns its sniff on by name (ValidVariableName on, .MemberNotCamelCaps excluded) would give a keep that the sniff's own set overrides, so naming.property would silently stay camelCase. translateDisabled() now says instead that the excluded message cannot leave out what its sniff sets, the warning it gives for a message without a row. This also adds the warning to a row that existed: SwitchDeclaration on by name with .SpaceBeforeColonCASE excluded, which kept spacing.switchCase without a word. Where the sniff comes in through a standard (PSR12 with .SpaceBeforeColonCASE excluded), the keep still wins, as before.
  • PSR12 with PSR1.Methods.CamelCapsMethodName.NotCamelCaps excluded keeps naming.method as before, but the warning is now the one of a sniff turned off ("naming.method also stands for …").

Tests: tests/DressCode/Config/PluginRegistry.phpt (the new rows, a row that existed, a message without a row), tests/DressCode/Interop/Translator.phpt (a message enabled alone, a message excluded while its sniff is on by name).

Locally, all checks give the same results as on master: the forbiddenPhpdocLines fixture fails, and PHPStan reports the error in tests/bootstrap.php, plus three errors in NativeType.php and PhpdocTypeNotationVisitor.php with a fresh composer install (phpstan/phpdoc-parser 2.4.0). Upstream CI has not run on this PR yet.

Co-Authored-By: Claude Code

https://claude.ai/code/session_01D1mfZTuCXTAaFC39NM1xdk

dg added 12 commits October 28, 2026 02:24
…ich init proposes for a project formatted by Pint

PER Coding Style with what Pint 1.32 decides otherwise and without what it leaves to the author: the concatenation
without spaces, `! $x`, `new Foo`, `fn ($x) =>`, the trailing comma in arrays alone, a blank line before `return`
and `continue`, the enum cases kept together, the names in doc comments imported, and no construct spread for its
width. A standard of the core beside the others, so the reference, explain and init list it with them; init writes
it where the project requires laravel/pint, the standard of the preset a pint.json names, laravel without one.
dresscode init measures the code of a project and writes the configuration that fits it, each decision with its description.
… in the style the project keeps

dresscode upgrade lays the set deprecations, with --modernize also modernizations, over the presets the configuration
uses and beneath its own decisions and overrides, so that what the project keeps stays kept, lets in the plugins of
the packages of upgrading data, adds the types of the code and fixes. Without a configuration file it takes the
directory as a whole and no style. With one it keeps the scope, the target, the types, fixRisky, the baseline and the
maps, and of the style only the decisions the code keeps: a check without the types and the sets runs first, every
decision it finds violated anywhere is left out, and the run is narrowed by only to the rest, the sets and the packages
whose data reach the project, which a worker gets through --only. It takes --only, --fix-risky and --ask-risky, and
the summary names upgrade --ask-risky for the risky fixes left. The upgrade goes to the lowest versions of PHP and of
the libraries the project allows; the console says which libraries it takes, which packages are installed newer than
that, whose declarations then say nothing of what it deprecates, advising composer update --prefer-lowest, and,
where it rewrote a file, to run it again.
…beside DressCode

A package of upgrading data says which packages it is about under extra.dresscode.packages, and
UpgradingTester::collectPackageProblems() refuses a list that is not exactly the packages its upgrading files are
about. upgrade learns of the packages from Packagist, asked once a day and remembered in the cache directory, for now
of the vendor dresscode alone, and PackageDiscovery finds those installed beside DressCode by their type
dresscode-plugin, not only those of the project. A project requiring one of their libraries itself, not one where it
comes with another library, gets a missing package installed first: composer require into the installation of
DressCode, or require --dev into the project where its lock holds DressCode, in a terminal after asking and without
one only with --yes, otherwise it refuses with the command to run. The command then runs anew in a new process, whose
autoloader knows the installed packages and the plugin dresscode/upgrade-nette brings.
The configurations and the suppressions of PHP CS Fixer, PHP_CodeSniffer and Slevomat translated to the decisions of DressCode.
… the workers included

`--profile <file>` writes as JSON where the time of a run went, in nanoseconds: the phases (the start of the process,
the start of the container of PHPStan or of a derived one and its scopes, the parse, the passes, the gaps, the print,
the cycle collection, the run as a whole), every rule by the time of its callbacks, how often they ran and how often
they changed the tree, every gap rule by the time of its claims, every file with its size, rounds and passes, and the
peak memory of every process. A worker measures its own files and hands that over with every result and the parent
adds it up, so the totals do not depend on the number of workers. A run with the option leaves the result cache out,
a file served from the cache having nothing to measure.

It says where the time of a run goes, not only how much of it: a comparison of two revisions then names the rule or
the claim that moved. Without the option the engine only asks whether there is a profiler, and wraps a claim in
a measurement only when there is one.
Copilot AI balanced review requested due to automatic review settings October 28, 2026 21:18

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues were identified for the suppression-lookup changes.

No open issues 🎉

What changed in this PR

This PR makes DressCode honor PHP_CodeSniffer suppression comments that name a sniff’s message code, and enables migrate-suppressions to translate those comments through the same lookup.

Changes:

  • Falls back from an untranslated four-part message code to its parent sniff’s decisions, while preserving explicit message-code translations.
  • Adds regression coverage for a recognized sniff message and an unknown name.
File Description
tests/​DressCode/​Config/​PluginRegistry.phpt Tests message-code fallback and unknown-name handling.
src/​Config/​PluginRegistry.php Implements and documents parent-sniff fallback for suppression lookup.

Review effort: Balanced

@JanTvrdik
JanTvrdik marked this pull request as draft October 28, 2026 21:47
@JanTvrdik JanTvrdik changed the title suppression: a message code of a sniff silences the decisions of its sniff suppression: a message of a sniff stands for its own row of the table Oct 28, 2026
…, the naming messages of ValidVariableName, CamelCapsMethodName and UpperCaseConstantName getting one

A message without a row still stands for nothing. A message excluded while the configuration turns its sniff on by name says it cannot leave out what that sniff sets as well.

Co-Authored-By: Claude Code
Claude-Session: https://claude.ai/code/session_01D1mfZTuCXTAaFC39NM1xdk
@JanTvrdik
JanTvrdik force-pushed the jt-suppression-message-code branch from 6c6bda3 to c78d42d Compare October 28, 2026 22:15
@JanTvrdik
JanTvrdik marked this pull request as ready for review October 28, 2026 22:20
@dg
dg force-pushed the master branch 2 times, most recently from 89af10b to 332227b Compare October 29, 2026 01:55
@dg

dg commented Oct 29, 2026

Copy link
Copy Markdown
Owner

Thank you! Merged into master with one change: a message excluded while its sniff is turned on by name now makes what it stands for keep, the same as when the sniff comes from a standard, instead of keeping the sniff's value with a warning. A project with ValidVariableName on and MemberNotCamelCaps excluded keeps its snake_case properties, which is what it asked for.

@dg dg closed this Oct 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants