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 auto IgnoreImplicitMemberCallSingleStep = [](Expr *E) {
56 if (
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 auto CondExprWithAssign = anyOf(AssignOpNoParens, AssignOpFromEmbeddedExpr);
88 auto OpCondExprWithAssign =
89 anyOf(AssignOpMaybeParens, AssignOpFromEmbeddedExpr);
94 auto FoundControlStmt = mapAnyOf(ifStmt, whileStmt, doStmt, forStmt)
95 .with(hasCondition(CondExprWithAssign));
98 auto FoundConditionalOperator =
99 mapAnyOf(conditionalOperator, binaryConditionalOperator)
100 .with(hasCondition(OpCondExprWithAssign));
101 auto FoundLogicalOp = binaryOperator(
102 hasAnyOperatorName(
"&&",
"||"),
103 eachOf(hasLHS(OpCondExprWithAssign), hasRHS(OpCondExprWithAssign)));
105 auto FoundSelectionStmt =
106 stmt(anyOf(FoundControlStmt, FoundConditionalOperator, FoundLogicalOp))
109 Finder->addMatcher(FoundSelectionStmt,
this);
113 const MatchFinder::MatchResult &Result) {
114 const auto *FoundAssignment = Result.Nodes.getNodeAs<Stmt>(
"assignment");
115 assert(FoundAssignment);
117 const auto *ParentStmt = Result.Nodes.getNodeAs<Stmt>(
"parent");
118 const StringRef CondStr =
119 llvm::TypeSwitch<const Stmt *, const char *>(ParentStmt)
120 .Case([](
const IfStmt *) {
return "condition of 'if' statement"; })
121 .Case<WhileStmt, DoStmt, ForStmt>(
122 [](
const Stmt *) {
return "condition of a loop"; })
123 .Case([](
const ConditionalOperator *) {
124 return "condition of a ternary operator";
126 .Case([](
const BinaryOperator *) {
127 return "operand of a logical operator";
129 .DefaultUnreachable();
131 const SourceLocation OpLoc =
132 llvm::TypeSwitch<const Stmt *, SourceLocation>(FoundAssignment)
133 .Case<BinaryOperator, CXXOperatorCallExpr>(
134 [](
const auto *Op) {
return Op->getOperatorLoc(); })
135 .Default(FoundAssignment->getBeginLoc());
136 diag(OpLoc,
"assignment within %0 may indicate programmer error")
137 << FoundAssignment->getSourceRange() << CondStr;
138 diag(OpLoc,
"if it should be an assignment, move it out of the condition",
139 DiagnosticIDs::Note);
140 diag(OpLoc,
"if it is meant to be an equality check, change '=' to '=='",
141 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++ -*-===//