This is an archive of the discontinued LLVM Phabricator instance.

Fix false positive in magic number checker
ClosedPublic

Authored by 0x8000-0000 on Dec 18 2019, 8:02 PM.

Details

Summary

Fix false positive in magic number checker

https://bugs.llvm.org/show_bug.cgi?id=40640: cppcoreguidelines-avoid-magic-numbers should not warn about enum class

Test case code reduced by Pavel Kryukov.

Diff Detail

Event Timeline

0x8000-0000 created this revision.Dec 18 2019, 8:02 PM
Herald added a project: Restricted Project. · View Herald TranscriptDec 18 2019, 8:02 PM
Herald added a subscriber: cfe-commits. · View Herald Transcript
0x8000-0000 marked an inline comment as done.
0x8000-0000 added inline comments.
clang-tools-extra/clang-tidy/readability/MagicNumbersCheck.cpp
127

127-130 are the new lines. The rest were moved about by clang-format. Please let me know if I should revert the format.

Please mention fix in Release Notes.

Eugene.Zelenko edited reviewers, added: hokein; removed: Eugene.Zelenko.Dec 19 2019, 7:12 AM
0x8000-0000 edited the summary of this revision. (Show Details)

Update release notes.

aaron.ballman added inline comments.Dec 20 2019, 12:40 PM
clang-tools-extra/clang-tidy/readability/MagicNumbersCheck.cpp
129

So will this no longer treat *any* C-style cast as being a magic number? e.g., int i; i = (int)12;

0x8000-0000 marked an inline comment as done.Dec 20 2019, 4:01 PM
0x8000-0000 added inline comments.
clang-tools-extra/clang-tidy/readability/MagicNumbersCheck.cpp
129

Sadly, it would seem so.

if (ValueArray[(int)4] > ValueArray[1]) produces the following AST:

|   | | | `-ArraySubscriptExpr 0x11545f0 <col:7, col:24> 'int' lvalue
|   | | |   |-ImplicitCastExpr 0x11545d8 <col:7> 'int *' <ArrayToPointerDecay>
|   | | |   | `-DeclRefExpr 0x1154558 <col:7> 'int [5]' lvalue Var 0x1153cb0 'ValueArray' 'int [5]'                                                           
|   | | |   `-CStyleCastExpr 0x11545b0 <col:18, col:23> 'int' <NoOp>
|   | | |     `-IntegerLiteral 0x1154578 <col:23> 'int' 4

While the test case we're trying to avoid is:

`-TemplateSpecializationType 0x1169ee0 'holder<(Letter)9U>' sugar holder
  |-TemplateArgument expr
  | `-ConstantExpr 0x1169dc0 <col:59> 'Letter' 9
  |   `-SubstNonTypeTemplateParmExpr 0x1169da0 <col:59> 'Letter'
  |     `-CStyleCastExpr 0x1169d78 <col:59> 'Letter' <IntegralCast>
  |       `-IntegerLiteral 0x1169d48 <col:59> 'unsigned int' 9
  `-RecordType 0x1169ec0 'holder<Letter::J>'
    `-ClassTemplateSpecialization 0x1169de0 'holder'

Now, the question is - do we care? How many people use a C cast with a bare integer?

I suppose I can add a check for the grandparent node to be SubstNonTypeTemplateParmExpr, in order to filter this out?

0x8000-0000 marked an inline comment as done.Dec 20 2019, 5:45 PM
0x8000-0000 added inline comments.
clang-tools-extra/clang-tidy/readability/MagicNumbersCheck.cpp
129

An interesting fact is that the C-style cast does not produce a warning now anyway (even before applying this change.) and I don't have any idea why.

Adding these lines does not create a test failure:

+  79   if (((int)4) > IntSquarer[10])                                                                                                                         
+  80     return 0;

Add a test file for expected failures

0x8000-0000 marked an inline comment as done.Dec 20 2019, 8:12 PM
0x8000-0000 added inline comments.
clang-tools-extra/test/clang-tidy/checkers/readability-magic-numbers-todo.cpp
9

This test fails even with clang-tidy-9.

$ clang-tidy-9 --checks="-*,readability-magic-numbers" clang-tools-extra/test/clang-tidy/checkers/readability-magic-numbers-todo.cpp

/home/florin/tools/llvm-project/clang-tools-extra/test/clang-tidy/checkers/readability-magic-numbers-todo.cpp:9:35: warning: 10 is a magic number; consider replacing it with a named constant [readability-magic-numbers]
  if (((int)4) > ProcessSomething(10))
                                  ^

Nothing about the "4" here.

My take: this change fixes a user-reported bug, and does not cause any known regressions. I think we should integrate this.

My take: this change fixes a user-reported bug, and does not cause any known regressions. I think we should integrate this.

I sort of wonder whether we want to document this as a blessed approach to silencing the warning. I'm not certain if it's too obtuse or not, but I notice the check has no documented ways to silence the diagnostic aside from using the correct kind of magic number or adding it to a list of excluded magic numbers.

My take: this change fixes a user-reported bug, and does not cause any known regressions. I think we should integrate this.

I sort of wonder whether we want to document this as a blessed approach to silencing the warning. I'm not certain if it's too obtuse or not, but I notice the check has no documented ways to silence the diagnostic aside from using the correct kind of magic number or adding it to a list of excluded magic numbers.

You mean Hyrum's Law is not sufficient?

The check can be silenced with the regular NOLINT, or with defining and using a constant/enum. Using this "backdoor" way seems even more cumbersome and confusing than the NOLINT. At least with NOLINT it is clear what you're doing, and somebody else can grep for it and fix it if it is appropriate.

aaron.ballman added a comment.EditedDec 22 2019, 9:22 AM

My take: this change fixes a user-reported bug, and does not cause any known regressions. I think we should integrate this.

I sort of wonder whether we want to document this as a blessed approach to silencing the warning. I'm not certain if it's too obtuse or not, but I notice the check has no documented ways to silence the diagnostic aside from using the correct kind of magic number or adding it to a list of excluded magic numbers.

You mean Hyrum's Law is not sufficient?

The check can be silenced with the regular NOLINT, or with defining and using a constant/enum. Using this "backdoor" way seems even more cumbersome and confusing than the NOLINT. At least with NOLINT it is clear what you're doing, and somebody else can grep for it and fix it if it is appropriate.

My concern is that NOLINT is insufficient. Consider: foo(12, 42, 18); where the 42 is not desired to be warned about due to domain-specific knowledge but the 12 and 18 are.

However, I am not convinced that you're wrong either -- casting is cumbersome. But it's also a somewhat well-used workaround to silence warnings (casting to void silencing unused value warnings being a common example).

For right now, we can leave it as a bug -- we can decide to bless the approach later.

aaron.ballman accepted this revision.Dec 22 2019, 9:26 AM

LGTM aside from some minor nits.

clang-tools-extra/test/clang-tidy/checkers/readability-magic-numbers-todo.cpp
2

You might as well move this onto the previous line; it just looks strange here.

clang-tools-extra/test/clang-tidy/checkers/readability-magic-numbers.cpp
219

prove -> Prove

and add a full stop to the end of the comment.

This revision is now accepted and ready to land.Dec 22 2019, 9:26 AM
0x8000-0000 marked 2 inline comments as done.Dec 22 2019, 9:34 AM

My take: this change fixes a user-reported bug, and does not cause any known regressions. I think we should integrate this.

I sort of wonder whether we want to document this as a blessed approach to silencing the warning. I'm not certain if it's too obtuse or not, but I notice the check has no documented ways to silence the diagnostic aside from using the correct kind of magic number or adding it to a list of excluded magic numbers.

You mean Hyrum's Law is not sufficient?

The check can be silenced with the regular NOLINT, or with defining and using a constant/enum. Using this "backdoor" way seems even more cumbersome and confusing than the NOLINT. At least with NOLINT it is clear what you're doing, and somebody else can grep for it and fix it if it is appropriate.

My concern is that NOLINT is insufficient. Consider: foo(12, 42, 18); where the 42 is not desired to be warned about due to domain-specific knowledge but the 12 and 18 are.

However, I am not convinced that you're wrong either -- casting is cumbersome. But it's also a somewhat well-used workaround to silence warnings (casting to void silencing unused value warnings being a common example).

For right now, we can leave it as a bug -- we can decide to bless the approach later.

Fair enough; I'm aiming for good precision and recall by default.

Minor comment fixes; capitalization, full stop.

@aaron.ballman updated as suggested; please commit/integrate when you have a moment. Thank you!

aaron.ballman closed this revision.Dec 24 2019, 7:04 AM

@aaron.ballman updated as suggested; please commit/integrate when you have a moment. Thank you!

Happy to do so, thank you for the fix! I've commit in c16b3ec597d277b5a7397db308f8ec730f3330a3