brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.4 KiB · 553c45c Raw
92 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "IncDecInConditionsCheck.h"10#include "../utils/Matchers.h"11#include "clang/AST/ASTContext.h"12#include "clang/ASTMatchers/ASTMatchFinder.h"13 14using namespace clang::ast_matchers;15 16namespace clang::tidy::bugprone {17 18namespace {19 20AST_MATCHER(BinaryOperator, isLogicalOperator) { return Node.isLogicalOp(); }21 22AST_MATCHER(UnaryOperator, isUnaryPrePostOperator) {23  return Node.isPrefix() || Node.isPostfix();24}25 26AST_MATCHER(CXXOperatorCallExpr, isPrePostOperator) {27  return Node.getOperator() == OO_PlusPlus ||28         Node.getOperator() == OO_MinusMinus;29}30 31} // namespace32 33void IncDecInConditionsCheck::registerMatchers(MatchFinder *Finder) {34  auto OperatorMatcher = expr(35      anyOf(binaryOperator(anyOf(isComparisonOperator(), isLogicalOperator())),36            cxxOperatorCallExpr(isComparisonOperator())));37 38  auto IsInUnevaluatedContext =39      expr(anyOf(hasAncestor(expr(matchers::hasUnevaluatedContext())),40                 hasAncestor(typeLoc())));41 42  Finder->addMatcher(43      expr(44          OperatorMatcher, unless(isExpansionInSystemHeader()),45          unless(hasAncestor(OperatorMatcher)), expr().bind("parent"),46 47          forEachDescendant(48              expr(anyOf(unaryOperator(isUnaryPrePostOperator(),49                                       hasUnaryOperand(expr().bind("operand"))),50                         cxxOperatorCallExpr(51                             isPrePostOperator(),52                             hasUnaryOperand(expr().bind("operand")))),53                   unless(IsInUnevaluatedContext),54                   hasAncestor(55                       expr(equalsBoundNode("parent"),56                            hasDescendant(57                                expr(unless(equalsBoundNode("operand")),58                                     matchers::isStatementIdenticalToBoundNode(59                                         "operand"),60                                     unless(IsInUnevaluatedContext))61                                    .bind("second")))))62                  .bind("operator"))),63      this);64}65 66void IncDecInConditionsCheck::check(const MatchFinder::MatchResult &Result) {67  SourceLocation ExprLoc;68  bool IsIncrementOp = false;69 70  if (const auto *MatchedDecl =71          Result.Nodes.getNodeAs<CXXOperatorCallExpr>("operator")) {72    ExprLoc = MatchedDecl->getExprLoc();73    IsIncrementOp = (MatchedDecl->getOperator() == OO_PlusPlus);74  } else if (const auto *MatchedDecl =75                 Result.Nodes.getNodeAs<UnaryOperator>("operator")) {76    ExprLoc = MatchedDecl->getExprLoc();77    IsIncrementOp = MatchedDecl->isIncrementOp();78  } else79    return;80 81  diag(ExprLoc,82       "%select{decrementing|incrementing}0 and referencing a variable in a "83       "complex condition can cause unintended side-effects due to C++'s order "84       "of evaluation, consider moving the modification outside of the "85       "condition to avoid misunderstandings")86      << IsIncrementOp;87  diag(Result.Nodes.getNodeAs<Expr>("second")->getExprLoc(),88       "variable is referenced here", DiagnosticIDs::Note);89}90 91} // namespace clang::tidy::bugprone92