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(NodeMatch: translationUnitDecl(), Action: 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 | bool VisitBinaryOperator(BinaryOperator *BO) { |
43 | if (BO->isAssignmentOp()) |
44 | Check.report(BO); |
45 | return true; |
46 | } |
47 | |
48 | bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr *OCE) { |
49 | if (OCE->isAssignmentOp()) |
50 | Check.report(OCE); |
51 | return true; |
52 | } |
53 | }; |
54 | |
55 | ConditionVisitor(Check).TraverseStmt(If->getCond()); |
56 | return true; |
57 | } |
58 | }; |
59 | Visitor(*this).TraverseAST(AST&: *Result.Context); |
60 | } |
61 | |
62 | void AssignmentInIfConditionCheck::report(const Expr *AssignmentExpr) { |
63 | SourceLocation OpLoc = |
64 | isa<BinaryOperator>(Val: AssignmentExpr) |
65 | ? cast<BinaryOperator>(Val: AssignmentExpr)->getOperatorLoc() |
66 | : cast<CXXOperatorCallExpr>(Val: AssignmentExpr)->getOperatorLoc(); |
67 | |
68 | diag(Loc: OpLoc, Description: "an assignment within an 'if' condition is bug-prone" ) |
69 | << AssignmentExpr->getSourceRange(); |
70 | diag(Loc: OpLoc, |
71 | Description: "if it should be an assignment, move it out of the 'if' condition" , |
72 | Level: DiagnosticIDs::Note); |
73 | diag(Loc: OpLoc, Description: "if it is meant to be an equality check, change '=' to '=='" , |
74 | Level: DiagnosticIDs::Note); |
75 | } |
76 | |
77 | } // namespace clang::tidy::bugprone |
78 | |