brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.1 KiB · 7ef8ef3 Raw
121 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 "StaticAccessedThroughInstanceCheck.h"10#include "clang/AST/ASTContext.h"11#include "clang/ASTMatchers/ASTMatchFinder.h"12#include "llvm/ADT/StringRef.h"13 14using namespace clang::ast_matchers;15 16namespace clang::tidy::readability {17 18namespace {19AST_MATCHER(CXXMethodDecl, isStatic) { return Node.isStatic(); }20} // namespace21 22static unsigned getNameSpecifierNestingLevel(QualType QType) {23  unsigned NameSpecifierNestingLevel = 1;24  for (NestedNameSpecifier Qualifier = QType->getPrefix(); /**/;25       ++NameSpecifierNestingLevel) {26    switch (Qualifier.getKind()) {27    case NestedNameSpecifier::Kind::Null:28      return NameSpecifierNestingLevel;29    case NestedNameSpecifier::Kind::Global:30    case NestedNameSpecifier::Kind::MicrosoftSuper:31      return NameSpecifierNestingLevel + 1;32    case NestedNameSpecifier::Kind::Namespace:33      Qualifier = Qualifier.getAsNamespaceAndPrefix().Prefix;34      continue;35    case NestedNameSpecifier::Kind::Type:36      Qualifier = Qualifier.getAsType()->getPrefix();37      continue;38    }39    llvm_unreachable("unhandled nested name specifier kind");40  }41}42 43void StaticAccessedThroughInstanceCheck::storeOptions(44    ClangTidyOptions::OptionMap &Opts) {45  Options.store(Opts, "NameSpecifierNestingThreshold",46                NameSpecifierNestingThreshold);47}48 49void StaticAccessedThroughInstanceCheck::registerMatchers(MatchFinder *Finder) {50  Finder->addMatcher(51      memberExpr(hasDeclaration(anyOf(cxxMethodDecl(isStatic()),52                                      varDecl(hasStaticStorageDuration()),53                                      enumConstantDecl())))54          .bind("memberExpression"),55      this);56}57 58void StaticAccessedThroughInstanceCheck::check(59    const MatchFinder::MatchResult &Result) {60  const auto *MemberExpression =61      Result.Nodes.getNodeAs<MemberExpr>("memberExpression");62 63  if (MemberExpression->getBeginLoc().isMacroID())64    return;65 66  const Expr *BaseExpr = MemberExpression->getBase();67 68  const QualType BaseType =69      BaseExpr->getType()->isPointerType()70          ? BaseExpr->getType()->getPointeeType().getUnqualifiedType()71          : BaseExpr->getType().getUnqualifiedType();72 73  const ASTContext *AstContext = Result.Context;74  PrintingPolicy PrintingPolicyWithSuppressedTag(AstContext->getLangOpts());75  PrintingPolicyWithSuppressedTag.SuppressTagKeyword = true;76  PrintingPolicyWithSuppressedTag.SuppressUnwrittenScope = true;77 78  PrintingPolicyWithSuppressedTag.PrintAsCanonical =79      !BaseExpr->getType()->isTypedefNameType();80 81  std::string BaseTypeName =82      BaseType.getAsString(PrintingPolicyWithSuppressedTag);83 84  // Ignore anonymous structs/classes which will not have an identifier85  const RecordDecl *RecDecl = BaseType->getAsCXXRecordDecl();86  if (!RecDecl || RecDecl->getIdentifier() == nullptr)87    return;88 89  // Do not warn for CUDA built-in variables.90  if (StringRef(BaseTypeName).starts_with("__cuda_builtin_"))91    return;92 93  SourceLocation MemberExprStartLoc = MemberExpression->getBeginLoc();94  auto CreateFix = [&] {95    return FixItHint::CreateReplacement(96        CharSourceRange::getCharRange(MemberExprStartLoc,97                                      MemberExpression->getMemberLoc()),98        BaseTypeName + "::");99  };100 101  {102    auto Diag =103        diag(MemberExprStartLoc, "static member accessed through instance");104 105    if (getNameSpecifierNestingLevel(BaseType) > NameSpecifierNestingThreshold)106      return;107 108    if (!BaseExpr->HasSideEffects(*AstContext,109                                  /* IncludePossibleEffects =*/true)) {110      Diag << CreateFix();111      return;112    }113  }114 115  diag(MemberExprStartLoc, "member base expression may carry some side effects",116       DiagnosticIDs::Level::Note)117      << BaseExpr->getSourceRange() << CreateFix();118}119 120} // namespace clang::tidy::readability121