10#include "clang/AST/IgnoreExpr.h"
11#include "clang/AST/StmtVisitor.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13#include "llvm/ADT/TypeSwitch.h"
20class ConditionValueCanPropagateFrom
21 :
public ConstStmtVisitor<ConditionValueCanPropagateFrom, void> {
23 llvm::SmallVector<const Expr *, 2> ExprToProcess;
25 void VisitBinaryOperator(
const BinaryOperator *BO) {
27 ExprToProcess.push_back(BO->getRHS()->IgnoreParenImpCasts());
29 void VisitAbstractConditionalOperator(
const AbstractConditionalOperator *CO) {
30 ExprToProcess.push_back(CO->getFalseExpr()->IgnoreParenImpCasts());
31 ExprToProcess.push_back(CO->getTrueExpr()->IgnoreParenImpCasts());
36 ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
38 ConditionValueCanPropagateFrom Visitor;
40 while (!Visitor.ExprToProcess.empty()) {
41 const Expr *E = Visitor.ExprToProcess.pop_back_val();
42 ast_matchers::internal::BoundNodesTreeBuilder Result;
43 if (InnerMatcher.matches(*E, Finder, &Result)) {
45 Builder->addMatch(Result);
54 ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
55 const auto IgnoreImplicitMemberCallSingleStep = [](Expr *E) {
56 if (
const auto *C = dyn_cast<CXXMemberCallExpr>(E)) {
57 Expr *ExprNode =
C->getImplicitObjectArgument();
58 if (ExprNode->getSourceRange() == E->getSourceRange())
60 ExprNode = ExprNode->IgnoreParenImpCasts();
61 if (ExprNode->getSourceRange() == E->getSourceRange())
67 const Expr *IgnoreE = IgnoreExprNodes(&Node, IgnoreImplicitSingleStep,
68 IgnoreImplicitCastsExtraSingleStep,
69 IgnoreImplicitMemberCallSingleStep);
71 return InnerMatcher.matches(*IgnoreE, Finder, Builder);
79 MatchFinder *Finder) {
80 auto AssignOpNoParens = ignoringImplicitAsWritten(
81 binaryOperation(hasOperatorName(
"=")).bind(
"assignment"));
82 auto AssignOpMaybeParens = ignoringParenImpCasts(
83 binaryOperation(hasOperatorName(
"=")).bind(
"assignment"));
84 auto AssignOpFromEmbeddedExpr = expr(ignoringParenImpCasts(
85 conditionValueCanPropagateFrom(AssignOpMaybeParens)));
87 const auto CondExprWithAssign =
88 anyOf(AssignOpNoParens, AssignOpFromEmbeddedExpr);
89 const auto OpCondExprWithAssign =
90 anyOf(AssignOpMaybeParens, AssignOpFromEmbeddedExpr);
95 auto FoundControlStmt = mapAnyOf(ifStmt, whileStmt, doStmt, forStmt)
96 .with(hasCondition(CondExprWithAssign));
99 auto FoundConditionalOperator =
100 mapAnyOf(conditionalOperator, binaryConditionalOperator)
101 .with(hasCondition(OpCondExprWithAssign));
102 auto FoundLogicalOp = binaryOperator(
103 hasAnyOperatorName(
"&&",
"||"),
104 eachOf(hasLHS(OpCondExprWithAssign), hasRHS(OpCondExprWithAssign)));
106 const auto FoundSelectionStmt =
107 stmt(anyOf(FoundControlStmt, FoundConditionalOperator, FoundLogicalOp))
110 Finder->addMatcher(FoundSelectionStmt,
this);
114 const MatchFinder::MatchResult &Result) {
115 const auto *FoundAssignment = Result.Nodes.getNodeAs<Stmt>(
"assignment");
116 assert(FoundAssignment);
118 const auto *ParentStmt = Result.Nodes.getNodeAs<Stmt>(
"parent");
119 const StringRef CondStr =
120 llvm::TypeSwitch<const Stmt *, const char *>(ParentStmt)
121 .Case([](
const IfStmt *) {
return "condition of 'if' statement"; })
122 .Case<WhileStmt, DoStmt, ForStmt>(
123 [](
const Stmt *) {
return "condition of a loop"; })
124 .Case([](
const ConditionalOperator *) {
125 return "condition of a ternary operator";
127 .Case([](
const BinaryOperator *) {
128 return "operand of a logical operator";
130 .DefaultUnreachable();
132 const SourceLocation OpLoc =
133 llvm::TypeSwitch<const Stmt *, SourceLocation>(FoundAssignment)
134 .Case<BinaryOperator, CXXOperatorCallExpr>(
135 [](
const auto *Op) {
return Op->getOperatorLoc(); })
136 .Default(FoundAssignment->getBeginLoc());
137 diag(OpLoc,
"assignment within %0 may indicate programmer error")
138 << FoundAssignment->getSourceRange() << CondStr;
139 diag(OpLoc,
"if it should be an assignment, move it out of the condition",
140 DiagnosticIDs::Note);
141 diag(OpLoc,
"if it is meant to be an equality check, change '=' to '=='",
142 DiagnosticIDs::Note);
void registerMatchers(ast_matchers::MatchFinder *Finder) override
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
AST_MATCHER_P(Stmt, isStatementIdenticalToBoundNode, std::string, ID)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//