Adds a new clang-tidy check that detects postfix increments and decrements that can be swapped for their prefix counterparts. Tried to be as thorough as possible with detecting if the result of the operation is used by a parent. I ran this check over llvm and clang lib and the result would build OK.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
- Build Status
Buildable 43763 Build 44747: arc lint + arc unit
Event Timeline
clang-tools-extra/docs/clang-tidy/checks/llvm-prefer-preincrement.rst | ||
---|---|---|
30 ↗ | (On Diff #237480) | Please highlight default value with single back-ticks. |
It'll be reasonable to submit patches generated by check into trunk. May be after branching release.
I only have some naming nits
- incriment -> increment
- decriment -> decrement
Maybe rename the check llvm-prefer-preincrement -> llvm-prefer-pre-increment
and rename the files and classes PreferPreincrementCheck -> PreferPreIncrementCheck
clang-tools-extra/clang-tidy/llvm/PreferPreincrementCheck.cpp | ||
---|---|---|
38 ↗ | (On Diff #237490) | Does the checker give a lot of false positives? |
clang-tools-extra/clang-tidy/llvm/PreferPreincrementCheck.cpp | ||
---|---|---|
38 ↗ | (On Diff #237490) | First time I tried it there were lots of false positives. But after adding all those Stmt checks it appears to do a rather good job |
clang-tools-extra/docs/clang-tidy/checks/performance-prefer-pre-increment.rst | ||
---|---|---|
9 | Please fix check name. |
Unit tests: pass. 61775 tests passed, 0 failed and 780 were skipped.
clang-tidy: fail. Please fix clang-tidy findings.
clang-format: fail. Please format your changes with clang-format by running git-clang-format HEAD^ or applying this patch.
Build artifacts: diff.json, clang-tidy.txt, clang-format.patch, CMakeCache.txt, console-log.txt, test-results.xml
Happy to see this check!
clang-tools-extra/docs/ReleaseNotes.rst | ||
---|---|---|
188–191 | Are we really really sure this is the correct relation direction? |
Unit tests: pass. 61861 tests passed, 0 failed and 781 were skipped.
clang-tidy: unknown.
clang-format: fail. Please format your changes with clang-format by running git-clang-format HEAD^ or applying this patch.
Build artifacts: diff.json, clang-format.patch, CMakeCache.txt, console-log.txt, test-results.xml
clang-tools-extra/docs/ReleaseNotes.rst | ||
---|---|---|
188–191 | You're probably right, I added this to llvm first, then thought about alias. Which module should its primary be |
clang-tools-extra/docs/ReleaseNotes.rst | ||
---|---|---|
188–191 | I would agree with performance module. |
Unit tests: pass. 61861 tests passed, 0 failed and 781 were skipped.
clang-tidy: unknown.
clang-format: fail. Please format your changes with clang-format by running git-clang-format HEAD^ or applying this patch.
Build artifacts: diff.json, clang-format.patch, CMakeCache.txt, console-log.txt, test-results.xml
Unit tests: pass. 61943 tests passed, 0 failed and 783 were skipped.
clang-tidy: unknown.
clang-format: fail. Please format your changes with clang-format by running git-clang-format HEAD^ or applying this patch.
Build artifacts: diff.json, clang-format.patch, CMakeCache.txt, console-log.txt, test-results.xml
Unit tests: fail. 61939 tests passed, 5 failed and 782 were skipped.
failed: libc++.std/language_support/cmp/cmp_partialord/partialord.pass.cpp failed: libc++.std/language_support/cmp/cmp_strongeq/cmp.strongeq.pass.cpp failed: libc++.std/language_support/cmp/cmp_strongord/strongord.pass.cpp failed: libc++.std/language_support/cmp/cmp_weakeq/cmp.weakeq.pass.cpp failed: libc++.std/language_support/cmp/cmp_weakord/weakord.pass.cpp
clang-tidy: fail. clang-tidy found 0 errors and 1 warnings. 0 of them are added as review comments below (why?).
clang-format: fail. Please format your changes with clang-format by running git-clang-format HEAD^ or applying this patch.
Build artifacts: diff.json, clang-tidy.txt, clang-format.patch, CMakeCache.txt, console-log.txt, test-results.xml
Pre-merge checks is in beta. Report issue. Please join beta or enable it for your project.
Unit tests: fail. 62129 tests passed, 5 failed and 807 were skipped.
failed: libc++.std/language_support/cmp/cmp_partialord/partialord.pass.cpp failed: libc++.std/language_support/cmp/cmp_strongeq/cmp.strongeq.pass.cpp failed: libc++.std/language_support/cmp/cmp_strongord/strongord.pass.cpp failed: libc++.std/language_support/cmp/cmp_weakeq/cmp.weakeq.pass.cpp failed: libc++.std/language_support/cmp/cmp_weakord/weakord.pass.cpp
clang-tidy: fail. clang-tidy found 0 errors and 1 warnings. 0 of them are added as review comments below (why?).
clang-format: pass.
Build artifacts: diff.json, clang-tidy.txt, clang-format.patch, CMakeCache.txt, console-log.txt, test-results.xml
Pre-merge checks is in beta. Report issue. Please join beta or enable it for your project.
Gonna throw it out there, those pre merge fails aren't anything to do with this patch
Yeah, the libc++ failures are not your fault :)
My 2 cents added.
clang-tools-extra/clang-tidy/performance/PreferPreIncrementCheck.cpp | ||
---|---|---|
63 ↗ | (On Diff #239988) | Why would you deactivate the check for c-code? |
86 ↗ | (On Diff #239988) | i think pre and post instead of capitalized. |
clang-tools-extra/test/clang-tidy/checkers/performance-prefer-pre-increment-disable-cpp-opcalls.cpp | ||
11 ↗ | (On Diff #239988) | Please extract the common iterator class into a header and include it in the tests. this is done in other tests as well, just grep for include. |
44 ↗ | (On Diff #239988) | Test-cases that I would like to see:
|
- Address some nits, more test cases need adding though
clang-tools-extra/clang-tidy/performance/PreferPreIncrementCheck.cpp | ||
---|---|---|
63 ↗ | (On Diff #239988) | I only deactivate operator calls for c-code as they aren't a thing in c. The unary operation expr still runs in c-code |
clang-tools-extra/test/clang-tidy/checkers/performance-prefer-pre-increment-disable-cpp-opcalls.cpp | ||
44 ↗ | (On Diff #239988) | There are test cases for only post fix operator overloading. basically it doesn't warn or provided a fix it as that isn't valid. I feel like there could be a seperate check that detects classes that overload operator++(int) but not operator++() but thats not what this check is for. |
Unit tests: fail. 62197 tests passed, 1 failed and 815 were skipped.
failed: libc++.std/thread/thread_mutex/thread_mutex_requirements/thread_timedmutex_requirements/thread_timedmutex_class/lock.pass.cpp
clang-tidy: fail. clang-tidy found 0 errors and 1 warnings. 0 of them are added as review comments below (why?).
clang-format: pass.
Build artifacts: diff.json, clang-tidy.txt, clang-format.patch, CMakeCache.txt, console-log.txt, test-results.xml
Pre-merge checks is in beta. Report issue. Please join beta or enable it for your project.
- Added test case when the inc and dec operators are found in a base class
clang-tools-extra/test/clang-tidy/checkers/performance-prefer-pre-increment-disable-cpp-opcalls.cpp | ||
---|---|---|
44 ↗ | (On Diff #239988) | Currently the base class provided operator overloads match normally. For template dependent code it gets a little hazy. Basically if the type isn't known the operator will always appear as a UnaryOperator, maybe its safest to proceed by disabling fixes if the type isn't known, and maybe add an option to override that behaviour, WDYT? |
Unit tests: pass. 62198 tests passed, 0 failed and 815 were skipped.
clang-tidy: fail. clang-tidy found 0 errors and 1 warnings. 0 of them are added as review comments below (why?).
clang-format: fail. Please format your changes with clang-format by running git-clang-format HEAD^ or applying this patch.
Build artifacts: diff.json, clang-tidy.txt, clang-format.patch, CMakeCache.txt, console-log.txt, test-results.xml
Pre-merge checks is in beta. Report issue. Please join beta or enable it for your project.
Running this over llvm with only clang and clang-tools-extra enabled this was the output. ninja check-all ran successfully with no errors. Didn't try transform TransformCxxOpCalls or TransformDependentType as they can be more dangerous
Sorry for missing this review, i simply hadn't time :/
All my concerns are addressed and I think this is LGTM after rebasing.
If it was 1997, I'd say yes, but I am not aware of any optimizer that does so poorly with pre/post increment to suggest this is actually a performance-related check still today. Do we have any evidence that at O1 or higher this has any impact whatsoever on performance? If not, then I'd say the alias shouldn't be there (because the check could be noisy on correct code bases).
clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp | ||
---|---|---|
56 | I think the name is a bit unfortunate -- the check handles more than just incrementing. But there's not really a good neutral word like "crement" that covers both actions. "Adjustment" sort of comes close, but would be kind of awful for a check name. Alternative ideas are welcome here. | |
clang-tools-extra/clang-tidy/performance/PreferPreIncrementCheck.cpp | ||
21 ↗ | (On Diff #299443) | Oh, neat, we have unaryOperator(hasOperatorName("++")) but that doesn't quite cut it here. :-D |
37–38 ↗ | (On Diff #299443) | Overloaded operators are a similar concern about changing the behavior of the expression. I think it's reasonably safe to assume that pre and post increment/decrement will typically do the same operations, but perhaps we should skip any overloaded operators that aren't idiomatic or aren't paired? e.g., struct S { S operator++(int); }; // Only post-fix available, don't diagnose struct T { int& operator++(); int operator++(int); }; // Not idiomatic return types, don't diagnose struct U { S& operator++(); T operator++(int); }; // Oh god, this just hurts, don't diagnose |
42 ↗ | (On Diff #299443) | I think hasParent(cxxThrowExpr()) is already covered by hasParent(expr()), right? Also, this may not be quite right -- what about a case like this: sizeof(i++) where there's no performance reason to prefer one or the other? |
88 ↗ | (On Diff #299443) | Typo: occurances -> occurrences |
90 ↗ | (On Diff #299443) | clang-tidy diagnostics are not capitalized like that -- also, this diagnostic doesn't really say what's wrong with the user's code. How about: pre-%0 may have better performance characteristics than post-%0 or something along those lines? |
clang-tools-extra/docs/ReleaseNotes.rst | ||
188–191 | I'm rather opposed to putting it in the performance module without evidence that this actually impacts performance. I find that this module tends to be really chatty already, and this check is likely to trigger *a lot* on real world code bases, so I want to make sure it's justified as a performance issue (looking around online suggests that this is not the case any longer in most situations and this has become more of a readability issue than a performance one). | |
clang-tools-extra/docs/clang-tidy/checks/performance-prefer-pre-increment.rst | ||
8 | isnt used which -> isn't used and |
I think the name is a bit unfortunate -- the check handles more than just incrementing. But there's not really a good neutral word like "crement" that covers both actions. "Adjustment" sort of comes close, but would be kind of awful for a check name. Alternative ideas are welcome here.