105130a6bSDmitri Gribenko //===--- AssignmentInIfConditionCheck.cpp - clang-tidy --------------------===// 205130a6bSDmitri Gribenko // 305130a6bSDmitri Gribenko // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 405130a6bSDmitri Gribenko // See https://llvm.org/LICENSE.txt for license information. 505130a6bSDmitri Gribenko // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 605130a6bSDmitri Gribenko // 705130a6bSDmitri Gribenko //===----------------------------------------------------------------------===// 805130a6bSDmitri Gribenko 905130a6bSDmitri Gribenko #include "AssignmentInIfConditionCheck.h" 1005130a6bSDmitri Gribenko #include "clang/AST/ASTContext.h" 112a0870c9SNathan James #include "clang/AST/RecursiveASTVisitor.h" 1205130a6bSDmitri Gribenko #include "clang/ASTMatchers/ASTMatchFinder.h" 1305130a6bSDmitri Gribenko 1405130a6bSDmitri Gribenko using namespace clang::ast_matchers; 1505130a6bSDmitri Gribenko 167d2ea6c4SCarlos Galvez namespace clang::tidy::bugprone { 1705130a6bSDmitri Gribenko 1805130a6bSDmitri Gribenko void AssignmentInIfConditionCheck::registerMatchers(MatchFinder *Finder) { 196bd98b4fSNathan James Finder->addMatcher(translationUnitDecl(), this); 2005130a6bSDmitri Gribenko } 2105130a6bSDmitri Gribenko 2205130a6bSDmitri Gribenko void AssignmentInIfConditionCheck::check( 236bd98b4fSNathan James const ast_matchers::MatchFinder::MatchResult &Result) { 246bd98b4fSNathan James class Visitor : public RecursiveASTVisitor<Visitor> { 256bd98b4fSNathan James AssignmentInIfConditionCheck &Check; 266bd98b4fSNathan James 276bd98b4fSNathan James public: 286bd98b4fSNathan James explicit Visitor(AssignmentInIfConditionCheck &Check) : Check(Check) {} 296bd98b4fSNathan James bool VisitIfStmt(IfStmt *If) { 306bd98b4fSNathan James class ConditionVisitor : public RecursiveASTVisitor<ConditionVisitor> { 316bd98b4fSNathan James AssignmentInIfConditionCheck &Check; 326bd98b4fSNathan James 336bd98b4fSNathan James public: 346bd98b4fSNathan James explicit ConditionVisitor(AssignmentInIfConditionCheck &Check) 356bd98b4fSNathan James : Check(Check) {} 366bd98b4fSNathan James 376bd98b4fSNathan James // Dont traverse into any lambda expressions. 386bd98b4fSNathan James bool TraverseLambdaExpr(LambdaExpr *, DataRecursionQueue * = nullptr) { 396bd98b4fSNathan James return true; 4005130a6bSDmitri Gribenko } 416bd98b4fSNathan James 42*b9852ff5SPiotr Zegar // Dont traverse into any requires expressions. 43*b9852ff5SPiotr Zegar bool TraverseRequiresExpr(RequiresExpr *, 44*b9852ff5SPiotr Zegar DataRecursionQueue * = nullptr) { 45*b9852ff5SPiotr Zegar return true; 46*b9852ff5SPiotr Zegar } 47*b9852ff5SPiotr Zegar 486bd98b4fSNathan James bool VisitBinaryOperator(BinaryOperator *BO) { 496bd98b4fSNathan James if (BO->isAssignmentOp()) 506bd98b4fSNathan James Check.report(BO); 516bd98b4fSNathan James return true; 526bd98b4fSNathan James } 536bd98b4fSNathan James 546bd98b4fSNathan James bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr *OCE) { 556bd98b4fSNathan James if (OCE->isAssignmentOp()) 566bd98b4fSNathan James Check.report(OCE); 576bd98b4fSNathan James return true; 586bd98b4fSNathan James } 596bd98b4fSNathan James }; 606bd98b4fSNathan James 616bd98b4fSNathan James ConditionVisitor(Check).TraverseStmt(If->getCond()); 626bd98b4fSNathan James return true; 636bd98b4fSNathan James } 646bd98b4fSNathan James }; 656bd98b4fSNathan James Visitor(*this).TraverseAST(*Result.Context); 666bd98b4fSNathan James } 676bd98b4fSNathan James 6832d88239SNathan James void AssignmentInIfConditionCheck::report(const Expr *AssignmentExpr) { 6932d88239SNathan James SourceLocation OpLoc = 7032d88239SNathan James isa<BinaryOperator>(AssignmentExpr) 7132d88239SNathan James ? cast<BinaryOperator>(AssignmentExpr)->getOperatorLoc() 7232d88239SNathan James : cast<CXXOperatorCallExpr>(AssignmentExpr)->getOperatorLoc(); 7332d88239SNathan James 7432d88239SNathan James diag(OpLoc, "an assignment within an 'if' condition is bug-prone") 7532d88239SNathan James << AssignmentExpr->getSourceRange(); 7632d88239SNathan James diag(OpLoc, 7705130a6bSDmitri Gribenko "if it should be an assignment, move it out of the 'if' condition", 7805130a6bSDmitri Gribenko DiagnosticIDs::Note); 7932d88239SNathan James diag(OpLoc, "if it is meant to be an equality check, change '=' to '=='", 8005130a6bSDmitri Gribenko DiagnosticIDs::Note); 8105130a6bSDmitri Gribenko } 8205130a6bSDmitri Gribenko 837d2ea6c4SCarlos Galvez } // namespace clang::tidy::bugprone 84