clang-tools 24.0.0git
AssignmentInIfConditionCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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
10#include "clang/AST/ASTContext.h"
11#include "clang/AST/RecursiveASTVisitor.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13
14using namespace clang::ast_matchers;
15
16namespace clang::tidy::bugprone {
17
19 Finder->addMatcher(translationUnitDecl(), this);
20}
21
23 const ast_matchers::MatchFinder::MatchResult &Result) {
24 class Visitor : public RecursiveASTVisitor<Visitor> {
26
27 public:
28 explicit Visitor(AssignmentInIfConditionCheck &Check) : Check(Check) {}
29 bool VisitIfStmt(IfStmt *If) {
30 class ConditionVisitor : public RecursiveASTVisitor<ConditionVisitor> {
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 // Only traverse the result expression of a statement expression,
49 // looking through labels and attributes on the last statement.
50 bool TraverseStmtExpr(StmtExpr *SE,
51 DataRecursionQueue *Queue = nullptr) {
52 if (auto *Last =
53 dyn_cast_if_present<ValueStmt>(SE->getSubStmt()->body_back()))
54 return TraverseStmt(Last->getExprStmt(), Queue);
55 return true;
56 }
57
58 bool VisitBinaryOperator(BinaryOperator *BO) {
59 if (BO->isAssignmentOp())
60 Check.report(BO);
61 return true;
62 }
63
64 bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr *OCE) {
65 if (OCE->isAssignmentOp())
66 Check.report(OCE);
67 return true;
68 }
69 };
70
71 ConditionVisitor(Check).TraverseStmt(If->getCond());
72 return true;
73 }
74 };
75 Visitor(*this).TraverseAST(*Result.Context);
76}
77
78void AssignmentInIfConditionCheck::report(const Expr *AssignmentExpr) {
79 const SourceLocation OpLoc =
80 isa<BinaryOperator>(AssignmentExpr)
81 ? cast<BinaryOperator>(AssignmentExpr)->getOperatorLoc()
82 : cast<CXXOperatorCallExpr>(AssignmentExpr)->getOperatorLoc();
83
84 diag(OpLoc, "an assignment within an 'if' condition is bug-prone")
85 << AssignmentExpr->getSourceRange();
86 diag(OpLoc,
87 "if it should be an assignment, move it out of the 'if' condition",
88 DiagnosticIDs::Note);
89 diag(OpLoc, "if it is meant to be an equality check, change '=' to '=='",
90 DiagnosticIDs::Note);
91}
92
93} // namespace clang::tidy::bugprone
void registerMatchers(ast_matchers::MatchFinder *Finder) override
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
AssignmentInIfConditionCheck(StringRef Name, ClangTidyContext *Context)