brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.3 KiB · 3d3fc78 Raw
150 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 "ChainedComparisonCheck.h"10#include "clang/AST/ASTContext.h"11#include "clang/ASTMatchers/ASTMatchFinder.h"12#include "llvm/ADT/SmallString.h"13#include "llvm/ADT/SmallVector.h"14#include <algorithm>15 16using namespace clang::ast_matchers;17 18namespace clang::tidy::bugprone {19static bool isExprAComparisonOperator(const Expr *E) {20  if (const auto *Op = dyn_cast_or_null<BinaryOperator>(E->IgnoreImplicit()))21    return Op->isComparisonOp();22  if (const auto *Op =23          dyn_cast_or_null<CXXOperatorCallExpr>(E->IgnoreImplicit()))24    return Op->isComparisonOp();25  return false;26}27 28namespace {29AST_MATCHER(BinaryOperator,30            hasBinaryOperatorAChildComparisonOperatorWithoutParen) {31  return isExprAComparisonOperator(Node.getLHS()) ||32         isExprAComparisonOperator(Node.getRHS());33}34 35AST_MATCHER(CXXOperatorCallExpr,36            hasCppOperatorAChildComparisonOperatorWithoutParen) {37  return llvm::any_of(Node.arguments(), isExprAComparisonOperator);38}39 40struct ChainedComparisonData {41  llvm::SmallString<256U> Name;42  llvm::SmallVector<const Expr *, 32U> Operands;43 44  explicit ChainedComparisonData(const Expr *Op) { extract(Op); }45 46private:47  void add(const Expr *Operand);48  void add(llvm::StringRef Opcode);49  void extract(const Expr *Op);50  void extract(const BinaryOperator *Op);51  void extract(const CXXOperatorCallExpr *Op);52};53 54} // namespace55 56void ChainedComparisonData::add(const Expr *Operand) {57  if (!Name.empty())58    Name += ' ';59  Name += 'v';60  Name += std::to_string(Operands.size());61  Operands.push_back(Operand);62}63 64void ChainedComparisonData::add(llvm::StringRef Opcode) {65  Name += ' ';66  Name += Opcode;67}68 69void ChainedComparisonData::extract(const BinaryOperator *Op) {70  const Expr *LHS = Op->getLHS()->IgnoreImplicit();71  if (isExprAComparisonOperator(LHS))72    extract(LHS);73  else74    add(LHS);75 76  add(Op->getOpcodeStr());77 78  const Expr *RHS = Op->getRHS()->IgnoreImplicit();79  if (isExprAComparisonOperator(RHS))80    extract(RHS);81  else82    add(RHS);83}84 85void ChainedComparisonData::extract(const CXXOperatorCallExpr *Op) {86  const Expr *FirstArg = Op->getArg(0U)->IgnoreImplicit();87  if (isExprAComparisonOperator(FirstArg))88    extract(FirstArg);89  else90    add(FirstArg);91 92  add(getOperatorSpelling(Op->getOperator()));93 94  const Expr *SecondArg = Op->getArg(1U)->IgnoreImplicit();95  if (isExprAComparisonOperator(SecondArg))96    extract(SecondArg);97  else98    add(SecondArg);99}100 101void ChainedComparisonData::extract(const Expr *Op) {102  if (!Op)103    return;104 105  if (const auto *BinaryOp = dyn_cast<BinaryOperator>(Op)) {106    extract(BinaryOp);107    return;108  }109 110  if (const auto *OverloadedOp = dyn_cast<CXXOperatorCallExpr>(Op)) {111    if (OverloadedOp->getNumArgs() == 2U)112      extract(OverloadedOp);113  }114}115 116void ChainedComparisonCheck::registerMatchers(MatchFinder *Finder) {117  const auto OperatorMatcher = expr(anyOf(118      binaryOperator(isComparisonOperator(),119                     hasBinaryOperatorAChildComparisonOperatorWithoutParen()),120      cxxOperatorCallExpr(121          isComparisonOperator(),122          hasCppOperatorAChildComparisonOperatorWithoutParen())));123 124  Finder->addMatcher(125      expr(OperatorMatcher, unless(hasParent(OperatorMatcher))).bind("op"),126      this);127}128 129void ChainedComparisonCheck::check(const MatchFinder::MatchResult &Result) {130  const auto *MatchedOperator = Result.Nodes.getNodeAs<Expr>("op");131 132  ChainedComparisonData Data(MatchedOperator);133  if (Data.Operands.empty())134    return;135 136  diag(MatchedOperator->getBeginLoc(),137       "chained comparison '%0' may generate unintended results, use "138       "parentheses to specify order of evaluation or a logical operator to "139       "separate comparison expressions")140      << llvm::StringRef(Data.Name).trim() << MatchedOperator->getSourceRange();141 142  for (std::size_t Index = 0U; Index < Data.Operands.size(); ++Index) {143    diag(Data.Operands[Index]->getBeginLoc(), "operand 'v%0' is here",144         DiagnosticIDs::Note)145        << Index << Data.Operands[Index]->getSourceRange();146  }147}148 149} // namespace clang::tidy::bugprone150