1 //===--- StaticAccessedThroughInstanceCheck.cpp - clang-tidy---------------===// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "StaticAccessedThroughInstanceCheck.h" 10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 12 13 using namespace clang::ast_matchers; 14 15 namespace clang { 16 namespace tidy { 17 namespace readability { 18 getNameSpecifierNestingLevel(const QualType & QType)19static unsigned getNameSpecifierNestingLevel(const QualType &QType) { 20 if (const ElaboratedType *ElType = QType->getAs<ElaboratedType>()) { 21 const NestedNameSpecifier *NestedSpecifiers = ElType->getQualifier(); 22 unsigned NameSpecifierNestingLevel = 1; 23 do { 24 NameSpecifierNestingLevel++; 25 NestedSpecifiers = NestedSpecifiers->getPrefix(); 26 } while (NestedSpecifiers); 27 28 return NameSpecifierNestingLevel; 29 } 30 return 0; 31 } 32 storeOptions(ClangTidyOptions::OptionMap & Opts)33void StaticAccessedThroughInstanceCheck::storeOptions( 34 ClangTidyOptions::OptionMap &Opts) { 35 Options.store(Opts, "NameSpecifierNestingThreshold", 36 NameSpecifierNestingThreshold); 37 } 38 registerMatchers(MatchFinder * Finder)39void StaticAccessedThroughInstanceCheck::registerMatchers(MatchFinder *Finder) { 40 Finder->addMatcher( 41 memberExpr(hasDeclaration(anyOf(cxxMethodDecl(isStaticStorageClass()), 42 varDecl(hasStaticStorageDuration()))), 43 unless(isInTemplateInstantiation())) 44 .bind("memberExpression"), 45 this); 46 } 47 check(const MatchFinder::MatchResult & Result)48void StaticAccessedThroughInstanceCheck::check( 49 const MatchFinder::MatchResult &Result) { 50 const auto *MemberExpression = 51 Result.Nodes.getNodeAs<MemberExpr>("memberExpression"); 52 53 if (MemberExpression->getBeginLoc().isMacroID()) 54 return; 55 56 const Expr *BaseExpr = MemberExpression->getBase(); 57 58 // Do not warn for overlaoded -> operators. 59 if (isa<CXXOperatorCallExpr>(BaseExpr)) 60 return; 61 62 QualType BaseType = 63 BaseExpr->getType()->isPointerType() 64 ? BaseExpr->getType()->getPointeeType().getUnqualifiedType() 65 : BaseExpr->getType().getUnqualifiedType(); 66 67 const ASTContext *AstContext = Result.Context; 68 PrintingPolicy PrintingPolicyWithSupressedTag(AstContext->getLangOpts()); 69 PrintingPolicyWithSupressedTag.SuppressTagKeyword = true; 70 PrintingPolicyWithSupressedTag.SuppressUnwrittenScope = true; 71 std::string BaseTypeName = 72 BaseType.getAsString(PrintingPolicyWithSupressedTag); 73 74 SourceLocation MemberExprStartLoc = MemberExpression->getBeginLoc(); 75 auto Diag = 76 diag(MemberExprStartLoc, "static member accessed through instance"); 77 78 if (BaseExpr->HasSideEffects(*AstContext) || 79 getNameSpecifierNestingLevel(BaseType) > NameSpecifierNestingThreshold) 80 return; 81 82 Diag << FixItHint::CreateReplacement( 83 CharSourceRange::getCharRange(MemberExprStartLoc, 84 MemberExpression->getMemberLoc()), 85 BaseTypeName + "::"); 86 } 87 88 } // namespace readability 89 } // namespace tidy 90 } // namespace clang 91