1010#include " clang/ASTMatchers/ASTMatchFinder.h"
1111#include " clang/Lex/Lexer.h"
1212#include " llvm/ADT/ScopeExit.h"
13- #include " llvm/ADT/Twine.h"
1413#include < array>
1514#include < optional>
1615#include < utility>
@@ -19,16 +18,14 @@ using namespace clang::ast_matchers;
1918
2019namespace clang ::tidy::performance {
2120
22- static std::string tryPrintVariable (const BinaryOperator *BO) {
21+ static const NamedDecl *
22+ getLHSNamedDeclIfCompoundAssign (const BinaryOperator *BO) {
2323 if (BO->isCompoundAssignmentOp ()) {
2424 const auto *DelcRefLHS =
2525 dyn_cast<DeclRefExpr>(BO->getLHS ()->IgnoreImpCasts ());
26- if (DelcRefLHS)
27- return (" variable '" +
28- llvm::Twine (DelcRefLHS->getDecl ()->getNameAsString ()) + " '" )
29- .str ();
26+ return DelcRefLHS ? DelcRefLHS->getDecl () : nullptr ;
3027 }
31- return " values " ;
28+ return nullptr ;
3229}
3330
3431static bool hasExplicitParentheses (const Expr *E, const SourceManager &SM,
@@ -52,19 +49,6 @@ static bool hasExplicitParentheses(const Expr *E, const SourceManager &SM,
5249 (NextTok && NextTok->is (tok::r_paren));
5350}
5451
55- template <typename AstNode>
56- static bool isInTemplateFunction (const AstNode *AN, ASTContext &Context) {
57- DynTypedNodeList Parents = Context.getParents (*AN);
58- for (const DynTypedNode &Parent : Parents) {
59- if (const auto *FD = Parent.template get <FunctionDecl>())
60- return FD->isTemplateInstantiation () ||
61- FD->getTemplatedKind () != FunctionDecl::TK_NonTemplate;
62- if (const auto *S = Parent.template get <Stmt>())
63- return isInTemplateFunction (S, Context);
64- }
65- return false ;
66- }
67-
6852constexpr std::array<std::pair<llvm::StringRef, llvm::StringRef>, 8U >
6953 OperatorsTransformation{{{" |" , " ||" },
7054 {" |=" , " ||" },
@@ -101,9 +85,9 @@ void BoolBitwiseOperationCheck::registerMatchers(MatchFinder *Finder) {
10185 binaryOperator (
10286 unless (isExpansionInSystemHeader ()),
10387 hasAnyOperatorName (" |" , " &" , " |=" , " &=" ),
104- hasEitherOperand (expr (ignoringImpCasts ( hasType (booleanType () )))),
105- optionally (hasAncestor ( // to simple implement transformations like
106- // `a&&b|c` -> `a&&(b||c)`
88+ hasEitherOperand (expr (hasType (booleanType ()))),
89+ optionally (hasParent ( // to simple implement transformations like
90+ // `a&&b|c` -> `a&&(b||c)`
10791 binaryOperator ().bind (" p" ))))
10892 .bind (" op" ),
10993 this );
@@ -113,25 +97,27 @@ void BoolBitwiseOperationCheck::check(const MatchFinder::MatchResult &Result) {
11397 const auto *MatchedExpr = Result.Nodes .getNodeAs <BinaryOperator>(" op" );
11498
11599 auto DiagEmitterProc = [MatchedExpr, this ] {
100+ const NamedDecl *ND = getLHSNamedDeclIfCompoundAssign (MatchedExpr);
116101 return diag (MatchedExpr->getOperatorLoc (),
117- " use logical operator '%0' for boolean %1 instead of "
118- " bitwise operator '%2'" )
119- << translate (MatchedExpr->getOpcodeStr ())
120- << tryPrintVariable (MatchedExpr) << MatchedExpr->getOpcodeStr ();
102+ " use logical operator '%0' for boolean %select{variable "
103+ " %2|values}1 instead of "
104+ " bitwise operator '%3'" )
105+ << translate (MatchedExpr->getOpcodeStr ()) << (ND == nullptr ) << ND
106+ << MatchedExpr->getOpcodeStr ();
121107 };
122108 auto DiagEmitter = llvm::make_scope_exit (DiagEmitterProc);
123109
124- if (isInTemplateFunction (MatchedExpr, *Result.Context ))
125- return ;
126-
127110 const bool HasVolatileOperand = llvm::any_of (
128111 std::array{MatchedExpr->getLHS (), MatchedExpr->getRHS ()},
129112 [](const Expr *E) {
130113 return E->IgnoreImpCasts ()->getType ().isVolatileQualified ();
131114 });
115+ if (HasVolatileOperand)
116+ return ;
117+
132118 const bool HasSideEffects =
133119 MatchedExpr->getRHS ()->HasSideEffects (*Result.Context , StrictMode);
134- if (HasVolatileOperand || HasSideEffects)
120+ if (HasSideEffects)
135121 return ;
136122
137123 SourceLocation Loc = MatchedExpr->getOperatorLoc ();
@@ -189,16 +175,11 @@ void BoolBitwiseOperationCheck::check(const MatchFinder::MatchResult &Result) {
189175 auto ReplaceOperator = FixItHint::CreateReplacement (TokenRange, FixSpelling);
190176
191177 std::optional<BinaryOperatorKind> ParentOpcode;
192- if (const auto *Parent = Result.Nodes .getNodeAs <BinaryOperator>(" p" );
193- Parent && llvm::any_of (std::array{Parent->getLHS (), Parent->getRHS ()},
194- [&](const Expr *E) {
195- return dyn_cast<BinaryOperator>(
196- E->IgnoreImpCasts ()) == MatchedExpr;
197- }))
178+ if (const auto *Parent = Result.Nodes .getNodeAs <BinaryOperator>(" p" ); Parent)
198179 ParentOpcode = Parent->getOpcode ();
199180
200181 const auto *RHS =
201- dyn_cast<BinaryOperator>(MatchedExpr->getRHS ()->IgnoreParenCasts ());
182+ dyn_cast<BinaryOperator>(MatchedExpr->getRHS ()->IgnoreImpCasts ());
202183 std::optional<BinaryOperatorKind> RHSOpcode;
203184 if (RHS)
204185 RHSOpcode = RHS->getOpcode ();
0 commit comments