[PATCH] Add readability-simplify-boolean-expr check to clang-tidy

Alexander Kornienko alexfh at google.com
Mon Mar 2 11:45:50 PST 2015


================
Comment at: clang-tidy/readability/SimplifyBooleanExpr.cpp:20
@@ +19,3 @@
+
+StringRef getText(const MatchFinder::MatchResult &Result, SourceRange Range) {
+  return Lexer::getSourceText(CharSourceRange::getTokenRange(Range),
----------------
LegalizeAdulthood wrote:
> alexfh wrote:
> > Is this function used only once? Maybe inline it then?
> I'm getting conflicting reviews here.
> 
> One reviewer wants me not to write inline on small functions and you're asking me to write `inline`.
> 
> I honestly don't care which, but please tell me which request I should follow :-).
We're talking about different ways to inline a function. I mean inlining on the source code level: take the function body and use it in the single place that invokes it.

Sorry for the ambiguity ;)

================
Comment at: clang-tidy/readability/SimplifyBooleanExpr.cpp:54
@@ +53,3 @@
+CXXBoolLiteralExpr const *getBoolLiteral(MatchFinder::MatchResult const &Result,
+                                         const char *const Id) {
+  CXXBoolLiteralExpr const *Literal =
----------------
LegalizeAdulthood wrote:
> alexfh wrote:
> > Please use `StringRef` instead of `const char*` wherever it makes sense.
> I'm happy to do that with some guidelines on what "makes sense".  In this case it is character literals coming down from the place where you were saying you preferred `const char Id[] = ...`.
> 
> What am I gaining by using `StringRef` here?
"Makes sense" here means roughly "everywhere where you pass a string, and not a raw pointer to const char". 

> What am I gaining by using StringRef here?

Peace of mind (in some sense): when you see a StringRef argument, you know that there is no expensive copying or calculation of the length going on (except where you create a StringRef from a char pointer) . Just use StringRef everywhere where you need a constant string (or a fragment of a string), and there's a buffer with sufficient lifetime (string literal, std::string) somewhere.

You also get fewer code review comments to deal with ;)

================
Comment at: clang-tidy/readability/SimplifyBooleanExpr.cpp:57
@@ +56,3 @@
+      Result.Nodes.getNodeAs<CXXBoolLiteralExpr>(Id);
+  return Literal &&
+                 Result.SourceManager->isMacroBodyExpansion(
----------------
LegalizeAdulthood wrote:
> alexfh wrote:
> > nit: It looks better with parentheses and makes operator precedence clear:
> > 
> >     return (Literal &&
> >             Result.SourceManager->isMacroBodyExpansion(Literal->getLocStart()))
> >                ? nullptr
> >                : Literal;
> > 
> Talk to clang-format.  I'm not using any of my own whitespace preferences, just ramming it through clang-format and taking what it gives me.
clang-format doesn't add or remove parentheses. But if you add parentheses here yourself, you'll get the formatting as in the comment above.

So I ask you to add parentheses and re-run clang-format on this line.

Sorry again for not being clear.

================
Comment at: clang-tidy/readability/SimplifyBooleanExpr.cpp:66
@@ +65,3 @@
+SimpleReturnsBool(bool Value, char const *const Id = nullptr) {
+  return returnStmt(has(boolLiteral(equals(Value)).bind(Id ? Id : "ignored")));
+}
----------------
LegalizeAdulthood wrote:
> alexfh wrote:
> > How about putting this into the `ReturnsBool` function?
> > 
> >   auto SimpleReturnsBool =
> >       returnStmt(has(boolLiteral(equals(Value)).bind(Id ? Id : "ignored")));
> I went through a couple iterations on this where I had some auto lambdas and then went to named functions with explicit return types.  For this one I don't think the auto is less readable.
Note, there's no lambda needed, and no function as well. You just need a certain matcher to use in a more complex matcher. `auto SomeMatcher = someMatcher(...);` is just the simplest way to write it. The function would make sense if you called it with different arguments, e.g.:

    return anyOf(
        SimpleReturnsBool(Value, SomeId),
        compoundStmt(statementCountIs(1), has(SimpleReturnsBool(Value, SomeOtherId))));

Otherwise, it's just simpler and more readable without a separate function:

    auto SimpleReturnsBool =                                                          
        returnStmt(has(boolLiteral(equals(Value)).bind(Id ? Id : "ignored")));        
    return anyOf(SimpleReturnsBool,                                                   
                 compoundStmt(statementCountIs(1), has(SimpleReturnsBool)));          

================
Comment at: clang-tidy/readability/SimplifyBooleanExpr.cpp:304
@@ +303,3 @@
+          : "";
+  const auto Replacement = "return " + StringRef(Negated ? "!" : "") + "(" +
+                           getText(Result, *If->getCond()) + ")" + Terminator;
----------------
LegalizeAdulthood wrote:
> alexfh wrote:
> > And here the use of auto is simply dangerous: this creates a Twine object that is only supposed to be used as a temporary (because if your `getText()` returned `std::string`, the Twine object would point to a deleted memory region right after the end of the expression). Please use `std::string` instead.
> My head is spinning with all this farbling around between `std::string`, `StringRef` and `Twine`.  Is the proper usage of these string classes documented somewhere so that I can refer to it while preparing a patch and spend less time churning the patch just to make these adjustments?
Some documentation is here:
http://llvm.org/docs/ProgrammersManual.html#passing-strings-the-stringref-and-twine-classes

You can also read class comments on StringRef and Twine.

What's important here, is that any `StringRef + something` that compiles yields a Twine. And one dangerous case is `StringRef + temporary std::string`. This creates a Twine pointing to a temporary `std::string`. The temporary string gets deleted right at the end of the expression, and the Twine continues to point to the deleted memory. So one should (almost) never store a Twine. The correct way to use it is:

  std::string Result = (llvm::Twine("...") + "..." + someFunctionReturningAStdStringOrAStringRef() + ...).str();

http://reviews.llvm.org/D7648

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/






More information about the cfe-commits mailing list