-
-
Notifications
You must be signed in to change notification settings - Fork 73
Improve handling of disable/enable/ignore directives #123
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
base: 4.x
Are you sure you want to change the base?
Conversation
Thanks for porting this over @anomiex ! I will look at this at a later point in time and am tentatively earmarking this PR for the 4.0.0 release as it constitutes a bigger change than I deem responsible for the 3.x branch. |
Since it sounds like 4.0.0 is probably coming fairly soon after 3.8.0 now, that seems fine with me. 👍 Also, since 4.0.0 is dropping old PHP support, I'm going to ignore the failing PHP 5.4 test. 🙂 Too bad it cancelled the rest of the tests after that one failed. |
5ea7447
to
7338e5a
Compare
Links in the link lists have to be unique and as all issue/PR sources (this repo, Squizlabs repo, PEAR repo) use numeric issue references, there will be duplicate/overlapping numbers at some point. To prevent this, I'm proposing the following change: * Links to _this repo_ will continue to use simple issue number links, i.e. `[#123]`. This will keep things most straight forward for new content being added to the changelog. * Links to the _Squizlabs repo_ will get a `sq` prefix in the link reference. This means the link reference will need to be added where the link is used, i.e `[#123][sq-123]`. * Links to the _PEAR repo_ will get a `pear` prefix in the link reference. Again, this means the link reference will need to be added where the link is used, i.e `[#123][pear-123]`. This commit makes it so for all existing issue/PR links in the changelog. Related to 244
Links in the link lists have to be unique and as all issue/PR sources (this repo, Squizlabs repo, PEAR repo) use numeric issue references, there will be duplicate/overlapping numbers at some point. To prevent this, I'm proposing the following change: * Links to _this repo_ will continue to use simple issue number links, i.e. `[#123]`. This will keep things most straight forward for new content being added to the changelog. * Links to the _Squizlabs repo_ will get a `sq` prefix in the link reference. This means the link reference will need to be added where the link is used, i.e `[#123][sq-123]`. * Links to the _PEAR repo_ will get a `pear` prefix in the link reference. Again, this means the link reference will need to be added where the link is used, i.e `[#123][pear-123]`. This commit makes it so for all existing issue/PR links in the changelog. Related to 244
@anomiex It's been a while, but 4.0 has finally been recreated in the new With that (mostly) done, I'd like to have a good look at this PR next week. |
The current method, listing codes to disable and a list of exceptions to that list, still has trouble with some cases. For example, disabling a standard, re-enabling a category within that standard, then ignoring or disabling a sniff within that category cannot be handled. We'd need a list of exceptions to the exceptions, and possibly a list of exceptions to that list too, and figuring out how to keep those lists up to date as new directives are encountered could prove to be confusing. Since the standard→category→sniff→code hierarchy is supposed to be thought of as a tree, let's store the ignore list that way instead. Manipulating the branches of the tree is straightforward no matter what directives are encountered. In this implementation I've favored speed over space: there are cases where we could prune a subtree that would evaluate to "ignore" or "don't ignore" for any possible input, but detecting that doesn't seem worth the time when it's not likely there will be so many enable or disable directives that the wasted space will be a problem. Fixes PHPCSStandards#111
Did you want me to rebase this on master or on the 4.x branch? 🙂 |
@anomiex Against the 4.x branch please as this PR was earmarked for the 4.0 release. |
Ok. Let's see if I can do it without getting GitHub all confused. 😅 |
7338e5a
to
9a0ee0c
Compare
Whew, GitHub didn't get confused into thinking there were 1000 commits added. 😀 |
Nice ;-) As you've probably figured out - I found that if you change the base branch ahead of pushing the rebased branch, it seems to work smoothly (and CI works properly then too). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@anomiex Thank you for this PR and for your patience.
I've had a good look now and I've left a number of remarks inline, some nitpicks, some about conventions etc.
Aside from that, I have a couple of questions regarding the implementation, for which I'd like to understand your reasoning for the choices made.
- The class has some static constructors, but the code in the
Tokenizer
class still usesclone $ignoring
. How about aIgnoreList::get[New]InstanceFrom($ignoring)
method which doesclone $this
? What is your opinion on this ? - The
IgnoreList
has a "ValueObject" feel to it, but isn't a value object currently. Any particular reason for that ? - Should there be any validation in the
set()
method that the sniff code being ignored is actually a potentially valid error code ? I.e. max 4 parts. - In the
set()
method, some sub-arrays get a.default
key, some don't. This feels error prone. Is there a reason to set the sub-arrays like this ? - Am I correct in saying that the
isAll()
method only works by the grace of the top-level always having the.default
key ? - I'm a bit concerned about the performance implications of this PR what with
isAll()
being called for every single message being added (providing anything is being ignored). Did you run any performance checks on this PR ?
Nitpick: what is the logic behind the method order in the IgnoreList
class ? If I look at the methods, it feels like set()
should come before check()
?
Other than that:
The tests nowadays follow the directory structure of the source code more closely.
So with IgnoreList
class being in the Util
subdirectory, the IgnoreListTest
class(es) should be in a tests/Core/Util/IgnoreList
subdirectory.
And while not (yet) required, as a rule of thumb, each test class should only contain tests for one method, or one "set" of methods, to reduce code churn for when PHPUnit 12 will start to be supported.
In practice, this means that preferably @covers
tags should be at class level and all tests in the class should "cover" the same code (which will be required in PHPUnit 12).
In this case, that would mean splitting the test class into three/four classes, though I'm okay with leaving this for now and doing that when the PHPUnit 12 compat PR will be done.
For the record:
- ✅ Confirmed that the new tests in the
ErrorSuppressionTest
class would fail without this fix and pass with. - ✅ Checked code coverage for the changed and new code.
Doesn't matter to me. Done.
I've never been all that big a fan of strictly doing value objects. If you really want I could convert it (it would just mean having
Other than the
The
there's no need to flag While we could add it in, there would be zero benefit while it would make
Yes, as written it needs the top-level We could work around that in both cases if we wanted, by changing the
Most of the time The question made me realize another test case that I could add, though:
Current code doesn't honor the enable on the second line, while this PR does. As for performance, I ran 4.x and this PR over Automattic/jetpack with the config deleted so it produced tons of messages (almost 1.8 million 😀). Took 4:48.61 for 4.x and 4:47.36 for this PR, which seems close enough to say there's no performance impact either way. Then a second run with 4.x took 5:03:26. 🤷
First the static methods, then the check and set, then the methods to check for ignoring nothing or everything. No particular reason for |
Description
The current method, listing codes to disable and a list of exceptions to that list, still has trouble with some cases. For example, disabling a standard, re-enabling a category within that standard, then ignoring or disabling a sniff within that category cannot be handled. We'd need a list of exceptions to the exceptions, and possibly a list of exceptions to that list too, and figuring out how to keep those lists up to date as new directives are encountered could prove to be confusing.
Since the standard→category→sniff→code hierarchy is supposed to be thought of as a tree, let's store the ignore list that way instead. Manipulating the branches of the tree is straightforward no matter what directives are encountered.
In this implementation I've favored speed over space: there are cases where we could prune a subtree that would evaluate to "ignore" or "don't ignore" for any possible input, but detecting that doesn't seem worth the time when it's not likely there will be so many enable or disable directives that the wasted space will be a problem.
Suggested changelog entry
Fixed bug #111: Improve handling of disable/enable/ignore directives
Related issues/external references
Follow up on squizlabs/PHP_CodeSniffer#1986
Fixes #111
Fixes squizlabs/PHP_CodeSniffer#3889
Closes squizlabs/PHP_CodeSniffer#3891
Types of changes
Technically this could be considered a breaking change, since
PHP_CodeSniffer\Tokenizers\Tokenizer->ignoredLines
happens to be public and this changes the values stored there. Is that really a public API though?PR checklist