The notorious #526074: False suggestion: table names should be enclosed in {curly_brackets} issue amply demonstrates that Coder needs a mechanism to deal with false positives, because these are very demotivating for people who would be inclined to establish a zero-tolerance policy on their own code.
There already exists a mechanism for white-listing warnings, but it is based on listing file names and line numbers. Aside of the fact that it's currently too buggy to be usable (see #1626420: Meta: get Coder and qa.d.o to work), it's very hard to maintain, because line numbers obviously change whenever a file is touched. This is most objectionable when running Coder as part of the testbot to check patches, because it causes warnings to pop up that have previously been white-listed by the maintainer and that are completely unrelated to the patch.
One way to fix this problem would be to use inline comments (either above-the-line or at-the-end-of-the-line). This has the advantage that the "ignore" is right where the problem is, so it'll never get lost, and it can be double-checked at any time. The downside is that it's ugly. — Those of us who might strive for perfection (zero tolerance) should not be forced to deface their code with Coder ignores.
I would propose calculating hashes of the offending lines (based on the content of the line without leading space, and possibly the context, i.e. the name of the enclosing class or function). Coder could display these hashes as part of each message, and we could then put them where we currently put the line numbers.
This would not be perfect, but I'd rather accept a rare false ignore over having to fight with Coder all of the time. I would position Coder as a helpful tool — a friend rather than a nasty drill sergeant — that gracefully steps aside when it reaches its limitations.
Comments
Comment #1
douggreen commentedI've always considered lint a model. I don't know where the official lint documentation lives, but I just found some documentation as http://www.thinkage.ca/english/gcos/expl/lint/manu/manu.html. This paragraph seems very appropriate
"Before we begin, we should note that it is inevitable that LINT will miss some problems and will also complain about code that turns out to be valid. The designers have tried to chart a course between too much laxness (which may miss significant irregularities) and too much nit-picking (which produces quantities of irrelevant output that you will likely ignore). Thus we have designed this version of LINT to report situations that are usually signs of errors. While odd constructions and unusual programming style can confuse LINT from time to time, the majority of material that LINT locates should deserve the programmer's attention."
Lint use's inline comments to help it, and I still frequently use the "// FALLTHROUGH" comment just because it's a good comment IMO. I would prefer the inline comment method to ignore coder warnings, just because it will be easier to maintain. Rather than a warning number or hashes though, I would prefer a readable short name. But I have always been against the idea that people should change their code just because coder says something.
The comment above that says "I would position Coder as a helpful tool — a friend rather than a nasty drill sergeant — that gracefully steps aside when it reaches its limitations." ... might mean that coder has grown beyond it's initial usage. I haven't spoken at a DrupalCon about coder in a long time (maybe four years), but when I did, I always said that "You are smarter than coder" and you should ignore warnings that you knew were wrong. The lint paragraph I quoted above says it best. That said, ... I don't want coder to be a Drill Sergeant, but given it's widespread usage, and the desire to run it on qa.d.o, I do think it's time to follow the lint model one step further and add inline comments.
Comment #2
salvisInline comments do have their advantages over separate comments — I can live with them, as long as they're //line comments. PhpStorm uses /*block comments*/, which is very nasty.
Comment #3
douggreen commentedI've taken a stab at a new ignore system. Every rule now has a rule name, by default this is the array index, so by default it's a number. But the rule names can be set. We can either stay with the numbering system, or go through all of the reviews and give them mnemonic names. If we stick with the numbering system, we'll just have to make sure that all new rules are added to the end.
Then in the code, above the line you want to ignore, add a comment like:
// @ignore upgrade7x_74
I've added ignores to coder itself so others can see how to define them.
Is the string "@ignore" appropriate, or should we use something else? I like the @ sign directory, but could see using # if this confuses doxygen. I played with using @coder or @coder-ignore or @coder-review and concluded that @ignore was more readable.
See http://drupalcode.org/project/coder.git/commit/d888ab6
Comment #4
douggreen commentedNote that the above will also handle the Drupal Code Sniffer "sniffer" review inside coder and properly ignore warnings.
Comment #5
stella commentedThat looks great! I never intended the original ignore system to be the final version, just a proof of concept more than anything else. I didn't go with the comment method as I didn't want to deal with the lack of comments for certain #sources.
+1 for inline comments and +1 for @ignore rather than @coder-ignore or anything else, it's short and sweet and quite clear what it does.
However, from looking at the code committed I see that the // @ignore comment is on the line before the line to be ignored. I had kinda expected it to be on the same line, but as long as it's documented, that's fine with me.
Just a few questions:
Also, it'd be great if we could add simpletests for this.
Comment #6
jhodgdonA few thoughts:
-
// @ignorecomments will not bother Doxygen. Doxygen and the API module are only parsing comments in/** */.- +1 for putting it on the line before, which is our standard for comments in general... possibly could it be:
to ignore the next N lines?
- THIS SOUNDS GREAT!!!! And it's definitely needed. I've just resorted to putting normal comments in my code in my contrib modules for places like this, to remind myself to ignore the warnings and not change anything, but of course the warnings still come up.
Comment #7
douggreen commentedI'll implement whatever the community agrees to. But the way I wrote this code, it actually ignores it on the current line and the next line. I was concerned that inline comments on the current line is actually against our current coding standards. And if we add // @ignore on that line it would generate it's own coding standards violations.
Comment #8
jhodgdonI agree totally that comments on the same line violate our usual coding standards.
So, would it be possible to do:
Comment #9
salvisYes, the standard also says there needs to be a period at the end...
Ignore comments are a different kind of comments, and I would definitely prefer to be able to put them at the end of the line where they're less obtrusive.
I like
// @ignore rule_name Nand it makes sense to put that on a line of its own when N>1, but for no N, putting it at the end of the line should be possible.
If we have to swallow the bitter pill and put the ignores into our code, then I'd like to have a benefit in exchange: use rule names rather than rule numbers, so that they are at least decipherable for normal humans.
Comment #10
jhodgdonYes, are there better rule names we could use?
I'm against the idea of having the // @ignore comments at the end of the line -- it makes them harder to see/scan if the line of code is long. Also if we have the multi-line option, it makes them not very uniform... I think it's easier to remember the coding standard if it says "Put it on the line before in all cases" than "Sometimes this and sometimes that", and I'm definitely all for simpler coding standards rather than having a lot of conditionals and exceptions.
Comment #11
douggreen commented@jhodgdon, yes this would be possible:
But I'd prefer to use a semi-colon, because currently whitespace or commas allow multiple rules ignores, as-in:
What do you think of the following, where no :N implies this line and the next line.
@salvis, I too would like more readable names. And I would likely commit a change that someone else made. But I'm really loath to personally go through all of our old upgrade reviews and assigning names. There are 325 current reviews in coder, not including contrib modules that implement hook_coder (such as coder tough love). I've already converted the few cases where a name is required (in rules callbacks that generate several different warnings, all have the same rules index number, and thus need an explicit name).
Also, I don't think we can give explicit names to the sniffer rules, these have to rely on some numbering. I choose an md5 hash of the string. For example, sniffer_83576421b5a32494aa5b58e538d68370 is the rule that says "Missing parameter type at position 1". Of course, there will be a different hash the warning says "Missing parameter type at position 2." Thus, if people start relying on DCS and start adding ignores for DCS, these are going to have hashes in them. And FWIW, the name of this review is currently "sniffer". I'm open to other names, like DCS or codesniffer. I didn't like DCS because I don't think it has any name recognition yet, but if I'm wrong, that's probably what it should be called.
Comment #12
salvisI see. But if the "names" are cryptic (numbers or even hashes) that's all the more reason to put them at the end of the line. I'd really hate having that kind of junk prominently sprinkled in with my code.
And, if humans cannot interpret the ignores, then it would be useful to have an option for turning the ignore mechanism off, so that we can investigate the ignores without having to manually remove them from the code.
Colon is fine with me (you mentioned semi-colon, but I think you meant colon).
Comment #13
douggreen commentedTwo more thoughts: (a) if we're going to ask people to add @ignore's to their code, I/we/coder can give reasonable looking @ignore names, so I think we should fix those 325 rules, (b) I personally think adding it to the line above is fine, this looks a lot like a lint pragma statement to me, it's a "pre-processor" to me, but honestly, we need to get many more core developers to weigh in on their preference before making a decision for core.
Comment #14
douggreen commentedIMO, before doing anything here, it would be best to get @dries, @webchick, @catch, @gabor, @crell, @chx, and probably a few others to render an opinion.
Comment #15
douggreen commentedI've asked @klausi to comment here. I'm concerned that putting inline comments on the same line as the ignore will cause problems with DCS when run outside the coder framework, such as from eclipse.
Comment #16
douggreen commentedComment #17
salvisYes, getting the heavyweights on board is the way to go.
Comment #18
douggreen commentedThe suggestion for N is really about scope. So this is what I propose,
// @ignore rule[:scope], ...
Where rule is a mnemonic rule name and scope is either "file", "function", "comment", or any numeric number representing a number of lines. By default, the scope applies to the current line and the next line. To make it apply to the current line and the next two lines, you'd use :2.
The ... implies that you can put as many of these on a line as you like.
After a nights sleep, I now feel that if core wants to add ignore rules, or how they want to add them, seems like a separate issue. We should implement the above, see how it works, how we feel about it, then suggest it for core. IMO, we shouldn't make any coding standards decisions right now. But we should implement something, try it out in contrib in a few modules, possibly tweak it based on that experience, then offer a solution to core.
Comment #19
douggreen commentedMarking as "needs work" to indicate I need to implement the above.
Comment #20
douggreen commentedI've implemented the scoping logic for function, file, class, comment, and a numeric number of lines. It still needs tests (and tests currently seem a bit broken --- ugh, they were working just a couple days ago, sorry).
Comment #21
jhodgdon+1 on #18 -- and I think you are right that you can do this in Coder and Core can decide whether it wants these things in the code (I think they will, since there's an effort in place to get Core to pass coder review, and there will always be exceptions).
Also +1 on the idea in #13: making the machine names of the rules more human-readable.
Thanks douggreen for taking this on!
Comment #22
salvisOk, I'll try it on some of my modules when it's ready.
What is the "comment" scope?
Would it make sense to add "+" and "-" for turning on and off? That could be a more robust alternative to specifying a number of lines.
Comment #23
klausiPHP_Codesniffer has this syntax:
That completely ignores all sniffs on the part between the tags. See also http://pear.php.net/manual/en/package.php.php-codesniffer.advanced-usage...
PHP_CodeSniffer just introduced something interesting in 1.3.6, see http://pear.php.net/package/PHP_CodeSniffer/download/
Very handy. At least for drupal code sniffer stuff we can just use that right away.
Comment #24
douggreen commentedA few quick examples:
This is comment scope:
This would also work for coder, but would likely have doxygen problems:
This is a function scope:
You can also enable function (or class scope) from anywhere within the function and class.
Comment #25
jhodgdonThis example could definitely be a problem for the API module:
because I think we need the /** */ comment to be directly before the function declaration, with nothing in between.
So even if it works for Coder, I would be in favor of advocating that people put the @ignore rule:function comment somewhere inside the function body (preferably at the top, just after the declaration line. Similarly for classes -- suggest that people put it at the top. (I realize Coder might be fine either way, but let's also consider that human readers might want to know about this and suggest people adopt a good practice).
Comment #26
douggreen commentedwfm, I think I've implemented something flexible, that's not too expensive on the lexical analysis, and you are welcome to come up with any standards you like ;) Once you set those standards, we can even make coder enforce them!
Comment #27
douggreen commentedI've just committed some tests. I haven't converted all of the rules numbers to mnemonics. But I've converted enough of them that someone else can probably complete the task. I've done it for druplart, production, sql, and style. So ... anyone wishing to test this, just be aware that some of the rules names will change when this is done.
Comment #28
alberto56 commentedI had some trouble figuring out how to use this feature. If anyone else is having problems, you can take a look at this thread: #1784954: Put the 2.x-dev snapshot on the project homepage
Cheers,
Albert.
Comment #29
douggreen commentedI just changed the sniffer ignore names from an md5 hash to something based on the sniffer source.
This makes much more readable names, such as:
See http://drupalcode.org/project/coder.git/commit/2671dc8
Comment #30
fgmThis should also handle @ignore in the handling of .info files: reopening because this was missed in the discussion above. Sample issue: the spurious upgrade7x_1 warning about listing all files.
Comment #31
Mołot commentedIgnore currently does not work for http://drupal.org/project/coder_tough_love plugin. But shouldn't this functionality be built into review module itself, without any need for plugin-site support?
Comment #32
shrop commentedAre @ignore rules at a place where this document can be updated? See the section on "Ignore warnings". I don't mind helping do that, but I am not 100% sure I know all of the possible formats, thought I am using the most simple iteration in a project right now, @ignore .
Comment #33
webel commentedJust feedback to the maintainers that I have just discovered this @ignore discussion, and it may help me address my concerns recently reported in many other Coder issues
(reduce the annoyance factor for those rules I don't agree with, and for those rules not yet well tuned for object-oriented code), Webel
Comment #34
klausiCoder 7.x is frozen now and will not receive updates. Coder 8.x-2.x can be used to check code for any Drupal version, Coder 8.x-2.x also supports the phpcbf command to automatically fix conding standard errors. Please check if this issue is still relevant and reopen against that version if necessary.