1 //===--- StaticAccessedThroughInstanceCheck.cpp - clang-tidy---------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "StaticAccessedThroughInstanceCheck.h" 11 #include "clang/AST/ASTContext.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 13 14 using namespace clang::ast_matchers; 15 16 namespace clang { 17 namespace tidy { 18 namespace readability { 19 20 static unsigned getNameSpecifierNestingLevel(const QualType &QType) { 21 if (const ElaboratedType *ElType = QType->getAs<ElaboratedType>()) { 22 const NestedNameSpecifier *NestedSpecifiers = ElType->getQualifier(); 23 unsigned NameSpecifierNestingLevel = 1; 24 do { 25 NameSpecifierNestingLevel++; 26 NestedSpecifiers = NestedSpecifiers->getPrefix(); 27 } while (NestedSpecifiers); 28 29 return NameSpecifierNestingLevel; 30 } 31 return 0; 32 } 33 34 void StaticAccessedThroughInstanceCheck::storeOptions( 35 ClangTidyOptions::OptionMap &Opts) { 36 Options.store(Opts, "NameSpecifierNestingThreshold", 37 NameSpecifierNestingThreshold); 38 } 39 40 void StaticAccessedThroughInstanceCheck::registerMatchers(MatchFinder *Finder) { 41 Finder->addMatcher( 42 memberExpr(hasDeclaration(anyOf(cxxMethodDecl(isStaticStorageClass()), 43 varDecl(hasStaticStorageDuration()))), 44 unless(isInTemplateInstantiation())) 45 .bind("memberExpression"), 46 this); 47 } 48 49 void StaticAccessedThroughInstanceCheck::check( 50 const MatchFinder::MatchResult &Result) { 51 const auto *MemberExpression = 52 Result.Nodes.getNodeAs<MemberExpr>("memberExpression"); 53 54 if (MemberExpression->getLocStart().isMacroID()) 55 return; 56 57 const Expr *BaseExpr = MemberExpression->getBase(); 58 59 // Do not warn for overlaoded -> operators. 60 if (isa<CXXOperatorCallExpr>(BaseExpr)) 61 return; 62 63 QualType BaseType = 64 BaseExpr->getType()->isPointerType() 65 ? BaseExpr->getType()->getPointeeType().getUnqualifiedType() 66 : BaseExpr->getType().getUnqualifiedType(); 67 68 const ASTContext *AstContext = Result.Context; 69 PrintingPolicy PrintingPolicyWithSupressedTag(AstContext->getLangOpts()); 70 PrintingPolicyWithSupressedTag.SuppressTagKeyword = true; 71 std::string BaseTypeName = 72 BaseType.getAsString(PrintingPolicyWithSupressedTag); 73 74 SourceLocation MemberExprStartLoc = MemberExpression->getLocStart(); 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