This is an archive of the discontinued LLVM Phabricator instance.

[clang-tidy] Recognize labelled statements when simplifying boolean exprs
ClosedPublic

Authored by LegalizeAdulthood on Jan 3 2019, 5:32 PM.

Details

Summary

[clang-tidy] Recognize labelled statements when simplifying boolean exprs

Inside a switch the caseStmt() and defaultStmt() have a nested statement
associated with them. Similarly, labelStmt() has a nested statement.
These statements were being missed when looking for a compound-if of the
form "if (x) return true; return false;" when the if is nested under one
of these labelling constructs.

Enhance the matchers to look for these nested statements using some
private matcher hasSubstatement() traversal matcher on case, default
and label statements. Add the private matcher hasSubstatementSequence()
to match the compound "if (x) return true; return false;" pattern.

  • Add unit tests for private matchers and corresponding test infrastructure
  • Add corresponding test file readability-simplify-bool-expr-case.cpp.
  • Fix variable name copy/paste error in readability-simplify-bool-expr.cpp.
  • Drop the asserts, which were used only for debugging matchers.
  • Run clang-format on the whole check.
  • Move local functions out of anonymous namespace and declare state, per LLVM style guide
  • Declare labels constexpr
  • Declare visitor arguments as pointer to const
  • Drop braces around simple control statements per LLVM style guide
  • Prefer explicit arguments over default arguments to methods

Fixes #27078

Diff Detail

Event Timeline

LegalizeAdulthood retitled this revision from Handle case/default statements when simplifying boolean expressions to [clang-tidy] Handle case/default statements when simplifying boolean expressions.Jan 4 2019, 2:06 PM
LegalizeAdulthood edited reviewers, added: alexfh, hokein, aaron.ballman, JonasToth; removed: cfe-commits.
LegalizeAdulthood set the repository for this revision to rCTE Clang Tools Extra.
LegalizeAdulthood added a subscriber: cfe-commits.
JonasToth added inline comments.Jan 5 2019, 5:42 AM
clang-tidy/readability/SimplifyBooleanExprCheck.cpp
386 ↗(On Diff #180184)

const on values is uncommon in clang-tidy code. Please keep that consistent.

743 ↗(On Diff #180184)

double space

745 ↗(On Diff #180184)

redundant empty comment line

747 ↗(On Diff #180184)

I think this assertion does not hold true from the matcher.
The matcher requires only hasDescendent(ifStmt()), but that does not ensure the first stmt is the ifStmt.

e.g.

case 10: {
  loggingCall();
  if(foo) ...

Is this excluded?
}

aaron.ballman added inline comments.Jan 5 2019, 10:43 AM
clang-tidy/readability/SimplifyBooleanExprCheck.cpp
511 ↗(On Diff #180184)

binding -> Binding

529 ↗(On Diff #180184)

binding -> Binding

Also, there is no "case statement" involved here. ;-)

533–540 ↗(On Diff #180184)

The check duplication here is unfortunate -- can you factor out the hasDescendant() bits into a variable that is reused, and perhaps use anyOf(caseStmt(stuff()), defaultStmt(stuff())) rather than separate functions?

718 ↗(On Diff #180184)

Don't use an identifier with the same name as a type, please.

719 ↗(On Diff #180184)

Add a message to the assertion (same with the other ones).

LegalizeAdulthood marked 10 inline comments as done.Jan 5 2019, 2:17 PM
LegalizeAdulthood added inline comments.
clang-tidy/readability/SimplifyBooleanExprCheck.cpp
386 ↗(On Diff #180184)

I can change the code, but I don't understand the push back.

"That's the way it's done elsewhere" just doesn't seem like good reasoning.

I write const on values to signify that they are computed once and only once. What is gained by removing that statement of once-and-only-once?

533–540 ↗(On Diff #180184)

I'm not a fan of duplication, either.

However, I have to know if it's a CaseStmt or DefaultStmt in the replacement code and that's tied to the id, so I'm not sure how to collapse it further.

719 ↗(On Diff #180184)

I'm not sure what you're asking for. I based these asserts off the existing assert in the file.

743 ↗(On Diff #180184)

What exactly is the problem?

745 ↗(On Diff #180184)

Meh, it's not redundant. It's there to aid readability of a big block of text by visually separating it from the associated code.

Why is this a problem?

747 ↗(On Diff #180184)

Look more carefully at the AST. CaseStmt has exactly one child. That child can either be a compound statement block (which was already correctly handled by the check) or it can be a single statement. This change enhances the check to handle the single statement child of the CaseStmt and DefaultStmt.

riccibruno added inline comments.
clang-tidy/readability/SimplifyBooleanExprCheck.cpp
719 ↗(On Diff #180184)

Something like assert((SwitchCase != nullptr) && "Some appropriate message blablabla!");
Keep the parentheses around the operands of != even if they are not strictly needed
since otherwise some bots will complain.

LegalizeAdulthood marked an inline comment as done.

Update from review comments

LegalizeAdulthood marked 3 inline comments as done.Jan 5 2019, 3:56 PM
LegalizeAdulthood added inline comments.
clang-tidy/readability/SimplifyBooleanExprCheck.cpp
719 ↗(On Diff #180184)

OK, I can do that; I wasn't sure if it was being suggested that I use some custom assert macro that took the message as a parameter.

LegalizeAdulthood marked an inline comment as done.

Update from review comments

LegalizeAdulthood marked 4 inline comments as done.

No really, update from review comments :)

aaron.ballman added inline comments.Jan 6 2019, 7:41 AM
clang-tidy/readability/SimplifyBooleanExprCheck.cpp
386 ↗(On Diff #180184)

"That's the way it's done elsewhere" just doesn't seem like good reasoning.

Keeping the code consistent with the vast majority of the remainder of the project is valid reasoning. I am echoing the request to drop the top-level const. We don't use this pattern for non-pointer/reference types and there's not a whole lot gained by using it inconsistently.

533–540 ↗(On Diff #180184)

You can bind to the castStmt() and defaultStmt() matchers to see what you get back, no? e.g., anyOf(caseStmt(stuff()).bind("which"), defaultStmt(stuff()).bind("which")) and in the check, you can use isa<> on the node named "which" to see whether you matched the case or the default label.

JonasToth added inline comments.Jan 7 2019, 8:41 AM
clang-tidy/readability/SimplifyBooleanExprCheck.cpp
386 ↗(On Diff #180184)

Plus we do have a clang-tidy check (in the pipeline) that could do that automatically if the LLVM projects decides to go that route. So we won't suffer in the future, if we add the const.

745 ↗(On Diff #180184)

Its subjective, I wouldn't do it so I thought you might have overlooked it, if we prefer this its fine from my side.

alexfh added inline comments.Jan 23 2019, 4:55 AM
clang-tidy/readability/SimplifyBooleanExprCheck.cpp
517 ↗(On Diff #180385)

Please put the more expensive matcher (hasDescendant may be *really* expensive) last. Same below.

LegalizeAdulthood marked 4 inline comments as done.Mar 20 2019, 12:39 PM
LegalizeAdulthood added inline comments.
clang-tidy/readability/SimplifyBooleanExprCheck.cpp
386 ↗(On Diff #180184)

You haven't addressed my point, which is that const is for values that don't change. Instead, you're just repeating "we haven't done it that way" instead of refuting the utility of const.

LegalizeAdulthood marked 2 inline comments as done.Jan 23 2022, 12:46 PM
LegalizeAdulthood retitled this revision from [clang-tidy] Handle case/default statements when simplifying boolean expressions to [clang-tidy] Recognize labelled statements when simplifying boolean exprs.
LegalizeAdulthood edited the summary of this revision. (Show Details)

Revive this patch on top-of-tree

LegalizeAdulthood edited the summary of this revision. (Show Details)Jan 23 2022, 2:00 PM

A large portion of the changes, especially in the checks implementation file, appear to be NFC stylistic or formatting only fixes. While these changes are generally good, they shouldn't be a part of this patch. Instead they should be committed in their own NFC patch.
This makes it much easier to review the relevant changes needed to implement this new behaviour.

A large portion of the changes, especially in the checks implementation file, appear to be NFC stylistic or formatting only fixes. While these changes are generally good, they shouldn't be a part of this patch. Instead they should be committed in their own NFC patch.
This makes it much easier to review the relevant changes needed to implement this new behaviour.

It's going to be a significant amount of work to tease everything
apart and this patch has already been waiting literally for years.
Every time I put something up for review I get told "do this because
the style guide says so", so I anticipated those things and fixed them
pre-emptively.

Honestly, we need to make our review process more productive,
not less.

clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp
72–74

FYI

These tabs here (and elsewhere) are phantoms somehow
introduced into the diff by Phabricator. My local diff file
that I uploaded has zero tabs in it anywhere.

clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp
72–74

When I look more carefully, I see it's one column to the left of the
first column in the file.... so it's trying to somehow say that this line
had increased indent in the diff?

I thought it was a TAB indicator and another reviewer thought so as well.

But it isn't a TAB at all :)

A large portion of the changes, especially in the checks implementation file, appear to be NFC stylistic or formatting only fixes. While these changes are generally good, they shouldn't be a part of this patch. Instead they should be committed in their own NFC patch.
This makes it much easier to review the relevant changes needed to implement this new behaviour.

It's going to be a significant amount of work to tease everything
apart and this patch has already been waiting literally for years.

I don't think you need to tease it apart for this patch, but FWIW, I agree that this is much harder to review in this state.

Every time I put something up for review I get told "do this because
the style guide says so", so I anticipated those things and fixed them
pre-emptively.

The rule of thumb is: if you have significant NFC changes, do them first and push the changes (often doesn't even require a review because it's NFC, but that depends on what comfort level you have about the changes being NFC), and then do the functional changes on top of the improved code. Reviewers will ask you to update style for the lines of code you're touching when appropriate, but we (generally) shouldn't be asking you to fix style issues in code you're not touching. (Oddly, we touch on this in #2 at https://llvm.org/docs/DeveloperPolicy.html#obtaining-commit-access which is not where I'd expect that information to live.)

FWIW, I looked through the changes and don't have major concerns. A second set of eyes approving this would be appreciated, but this LGTM.

clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp
72–74

Yeah, that's caught me a few times as well. The >> seems to mean "indentation changed" not "tab inserted".

423–448

I'd prefer the NOLINT comment be removed (we don't typically add those, same as clang-format comments or other special markings).

The rule of thumb is: if you have significant NFC changes,
do them first and push the changes (often doesn't even
require a review because it's NFC, but that depends on
what comfort level you have about the changes being NFC),
and then do the functional changes on top of the improved
code.

This is reasonable, but is it written down anywhere so that people
don't have to through this trial by fire every time? :)

LegalizeAdulthood marked 2 inline comments as done.

Update from review comments

aaron.ballman accepted this revision.Jan 26 2022, 1:15 PM

The rule of thumb is: if you have significant NFC changes,
do them first and push the changes (often doesn't even
require a review because it's NFC, but that depends on
what comfort level you have about the changes being NFC),
and then do the functional changes on top of the improved
code.

This is reasonable, but is it written down anywhere so that people
don't have to through this trial by fire every time? :)

Yup, in about the most obtuse place you could image: https://llvm.org/docs/DeveloperPolicy.html#obtaining-commit-access. We could probably stand to update https://llvm.org/docs/DeveloperPolicy.html to be more explicit about this and document it in a much more obvious place. (I agree with the complaint about us doing a poor job of writing these kinds of expectations down.)

Oops, forgot to accept the last time I said I thought this looked good. Please still give a day or two before landing in case @JonasToth or @alexfh have further comments or concerns.

This revision is now accepted and ready to land.Jan 26 2022, 1:15 PM
kwk added inline comments.
clang-tools-extra/unittests/clang-tidy/ReadabilityModuleTest.cpp
1

@LegalizeAdulthood I'm doing standalone builds of the LLVM projects and we're seeing an error that this file cannot be found. I wonder why this even worked before because we're essentially checking out (or better extract) clang into /clang-15.0.0-src/ and clang-extra-tools into clang-extra-tools-15.0.0-src. So no matter how smart you design your -I include path flags, there`ll never be a ../../clang that contains the file to be included here. @tstellar does this ring a bell? I've looked at this with @serge-sans-paille today and be both thought this cannot work. Here's the logfile

of this build (which might be unreachable in a few days): https://download.copr.fedorainfracloud.org/results/@fedora-llvm-team/llvm-snapshots/fedora-35-x86_64/04639555-clang/builder-live.log.gz

Herald added a project: Restricted Project. · View Herald TranscriptJul 18 2022, 8:28 AM
njames93 added inline comments.Jul 18 2022, 9:53 AM
clang-tools-extra/unittests/clang-tidy/ReadabilityModuleTest.cpp
1

TBH I think this include, allTestClangConfigs below and the CMakeLists edits should have been removed in D125026. I'll put a patch up to address this.