1 //===--- AssignmentInIfConditionCheck.cpp - clang-tidy --------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "AssignmentInIfConditionCheck.h" 10 #include "clang/AST/ASTContext.h" 11 #include "clang/AST/RecursiveASTVisitor.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 13 14 using namespace clang::ast_matchers; 15 16 namespace clang::tidy::bugprone { 17 18 void AssignmentInIfConditionCheck::registerMatchers(MatchFinder *Finder) { 19 Finder->addMatcher(translationUnitDecl(), this); 20 } 21 22 void AssignmentInIfConditionCheck::check( 23 const ast_matchers::MatchFinder::MatchResult &Result) { 24 class Visitor : public RecursiveASTVisitor<Visitor> { 25 AssignmentInIfConditionCheck &Check; 26 27 public: 28 explicit Visitor(AssignmentInIfConditionCheck &Check) : Check(Check) {} 29 bool VisitIfStmt(IfStmt *If) { 30 class ConditionVisitor : public RecursiveASTVisitor<ConditionVisitor> { 31 AssignmentInIfConditionCheck &Check; 32 33 public: 34 explicit ConditionVisitor(AssignmentInIfConditionCheck &Check) 35 : Check(Check) {} 36 37 // Dont traverse into any lambda expressions. 38 bool TraverseLambdaExpr(LambdaExpr *, DataRecursionQueue * = nullptr) { 39 return true; 40 } 41 42 // Dont traverse into any requires expressions. 43 bool TraverseRequiresExpr(RequiresExpr *, 44 DataRecursionQueue * = nullptr) { 45 return true; 46 } 47 48 bool VisitBinaryOperator(BinaryOperator *BO) { 49 if (BO->isAssignmentOp()) 50 Check.report(BO); 51 return true; 52 } 53 54 bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr *OCE) { 55 if (OCE->isAssignmentOp()) 56 Check.report(OCE); 57 return true; 58 } 59 }; 60 61 ConditionVisitor(Check).TraverseStmt(If->getCond()); 62 return true; 63 } 64 }; 65 Visitor(*this).TraverseAST(*Result.Context); 66 } 67 68 void AssignmentInIfConditionCheck::report(const Expr *AssignmentExpr) { 69 SourceLocation OpLoc = 70 isa<BinaryOperator>(AssignmentExpr) 71 ? cast<BinaryOperator>(AssignmentExpr)->getOperatorLoc() 72 : cast<CXXOperatorCallExpr>(AssignmentExpr)->getOperatorLoc(); 73 74 diag(OpLoc, "an assignment within an 'if' condition is bug-prone") 75 << AssignmentExpr->getSourceRange(); 76 diag(OpLoc, 77 "if it should be an assignment, move it out of the 'if' condition", 78 DiagnosticIDs::Note); 79 diag(OpLoc, "if it is meant to be an equality check, change '=' to '=='", 80 DiagnosticIDs::Note); 81 } 82 83 } // namespace clang::tidy::bugprone 84