34 auto OperatorMatcher = expr(
35 anyOf(binaryOperator(anyOf(isComparisonOperator(), isLogicalOperator())),
36 cxxOperatorCallExpr(isComparisonOperator())));
38 auto IsInUnevaluatedContext =
39 expr(anyOf(hasAncestor(expr(matchers::hasUnevaluatedContext())),
40 hasAncestor(typeLoc())));
43 hasAncestor(lambdaExpr(hasAncestor(expr(equalsBoundNode(
"parent")))));
47 OperatorMatcher, unless(hasAncestor(OperatorMatcher)),
48 expr().bind(
"parent"),
51 expr(anyOf(unaryOperator(isUnaryPrePostOperator(),
52 hasUnaryOperand(expr().bind(
"operand"))),
55 hasUnaryOperand(expr().bind(
"operand")))),
56 unless(IsInUnevaluatedContext), unless(IsInLambda),
58 expr(equalsBoundNode(
"parent"),
60 expr(unless(equalsBoundNode(
"operand")),
61 matchers::isStatementIdenticalToBoundNode(
63 unless(IsInUnevaluatedContext))
70 SourceLocation ExprLoc;
71 bool IsIncrementOp =
false;
73 if (
const auto *MatchedDecl =
74 Result.Nodes.getNodeAs<CXXOperatorCallExpr>(
"operator")) {
75 ExprLoc = MatchedDecl->getExprLoc();
76 IsIncrementOp = (MatchedDecl->getOperator() == OO_PlusPlus);
77 }
else if (
const auto *MatchedDecl =
78 Result.Nodes.getNodeAs<UnaryOperator>(
"operator")) {
79 ExprLoc = MatchedDecl->getExprLoc();
80 IsIncrementOp = MatchedDecl->isIncrementOp();
86 "%select{decrementing|incrementing}0 and referencing a variable in a "
87 "complex condition can cause unintended side-effects due to C++'s order "
88 "of evaluation, consider moving the modification outside of the "
89 "condition to avoid misunderstandings")
91 diag(Result.Nodes.getNodeAs<Expr>(
"second")->getExprLoc(),
92 "variable is referenced here", DiagnosticIDs::Note);