brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.6 KiB · 7c58676 Raw
129 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 "DerivedMethodShadowingBaseMethodCheck.h"10#include "clang/ASTMatchers/ASTMatchFinder.h"11#include "clang/ASTMatchers/ASTMatchers.h"12 13using namespace clang::ast_matchers;14 15namespace clang::tidy::bugprone {16 17static bool sameBasicType(const ParmVarDecl *Lhs, const ParmVarDecl *Rhs) {18  return Lhs && Rhs &&19         Lhs->getType()20                 .getCanonicalType()21                 .getNonReferenceType()22                 .getUnqualifiedType() == Rhs->getType()23                                              .getCanonicalType()24                                              .getNonReferenceType()25                                              .getUnqualifiedType();26}27 28static bool namesCollide(const CXXMethodDecl &Lhs, const CXXMethodDecl &Rhs) {29  if (Lhs.getNameAsString() != Rhs.getNameAsString())30    return false;31  if (Lhs.isConst() != Rhs.isConst())32    return false;33  if (Lhs.getNumParams() != Rhs.getNumParams())34    return false;35  for (unsigned int It = 0; It < Lhs.getNumParams(); ++It)36    if (!sameBasicType(Lhs.getParamDecl(It), Rhs.getParamDecl(It)))37      return false;38  return true;39}40 41namespace {42 43AST_MATCHER(CXXMethodDecl, nameCollidesWithMethodInBase) {44  const CXXRecordDecl *DerivedClass = Node.getParent();45  for (const auto &Base : DerivedClass->bases()) {46    llvm::SmallVector<const CXXBaseSpecifier *, 8> Stack;47    Stack.push_back(&Base);48    while (!Stack.empty()) {49      const CXXBaseSpecifier *CurrentBaseSpec = Stack.back();50      Stack.pop_back();51 52      if (CurrentBaseSpec->getAccessSpecifier() ==53          clang::AccessSpecifier::AS_private)54        continue;55 56      const CXXRecordDecl *CurrentRecord =57          CurrentBaseSpec->getType()->getAsCXXRecordDecl();58      if (!CurrentRecord)59        continue;60 61      // For multiple inheritance, we ignore only the bases that come from the62      // std:: namespace63      if (CurrentRecord->isInStdNamespace())64        continue;65 66      for (const auto &BaseMethod : CurrentRecord->methods()) {67        if (namesCollide(*BaseMethod, Node)) {68          const ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder);69          Builder->setBinding("base_method",70                              clang::DynTypedNode::create(*BaseMethod));71          return true;72        }73      }74 75      for (const auto &SubBase : CurrentRecord->bases())76        Stack.push_back(&SubBase);77    }78  }79  return false;80}81 82// Same as clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp,83// similar matchers are used elsewhere in LLVM84AST_MATCHER(CXXMethodDecl, isOutOfLine) { return Node.isOutOfLine(); }85 86} // namespace87 88DerivedMethodShadowingBaseMethodCheck::DerivedMethodShadowingBaseMethodCheck(89    StringRef Name, ClangTidyContext *Context)90    : ClangTidyCheck(Name, Context) {}91 92void DerivedMethodShadowingBaseMethodCheck::registerMatchers(93    MatchFinder *Finder) {94  Finder->addMatcher(95      cxxMethodDecl(96          unless(anyOf(isOutOfLine(), isStaticStorageClass(), isImplicit(),97                       cxxConstructorDecl(), isOverride(), isPrivate(),98                       // isFinal(), //included with isOverride,99                       // Templates are not handled yet100                       ast_matchers::isTemplateInstantiation(),101                       ast_matchers::isExplicitTemplateSpecialization())),102          ofClass(cxxRecordDecl(isDerivedFrom(cxxRecordDecl()))103                      .bind("derived_class")),104          nameCollidesWithMethodInBase())105          .bind("shadowing_method"),106      this);107}108 109void DerivedMethodShadowingBaseMethodCheck::check(110    const MatchFinder::MatchResult &Result) {111  const auto *ShadowingMethod =112      Result.Nodes.getNodeAs<CXXMethodDecl>("shadowing_method");113  const auto *DerivedClass =114      Result.Nodes.getNodeAs<CXXRecordDecl>("derived_class");115  const auto *BaseMethod = Result.Nodes.getNodeAs<CXXMethodDecl>("base_method");116 117  if (!ShadowingMethod || !DerivedClass || !BaseMethod)118    llvm_unreachable("Required binding not found");119 120  diag(ShadowingMethod->getBeginLoc(),121       "'%0' shadows method with the same name in class %1")122      << ShadowingMethod->getQualifiedNameAsString() << BaseMethod->getParent();123  diag(BaseMethod->getBeginLoc(), "previous definition of %0 is here",124       DiagnosticIDs::Note)125      << ShadowingMethod;126}127 128} // namespace clang::tidy::bugprone129