xref: /llvm-project/clang-tools-extra/clang-tidy/bugprone/AssignmentInIfConditionCheck.cpp (revision b9852ff5fc4986c6cf8c4ecd1eb5726d55a08ea3)
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