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 #include "llvm/ADT/StringRef.h" 13 14 using namespace clang::ast_matchers; 15 16 namespace clang { 17 namespace tidy { 18 namespace readability { 19 getNameSpecifierNestingLevel(const QualType & QType)20static unsigned getNameSpecifierNestingLevel(const QualType &QType) { 21 if (const ElaboratedType *ElType = QType->getAs<ElaboratedType>()) { 22 if (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 } 32 return 0; 33 } 34 storeOptions(ClangTidyOptions::OptionMap & Opts)35void StaticAccessedThroughInstanceCheck::storeOptions( 36 ClangTidyOptions::OptionMap &Opts) { 37 Options.store(Opts, "NameSpecifierNestingThreshold", 38 NameSpecifierNestingThreshold); 39 } 40 registerMatchers(MatchFinder * Finder)41void StaticAccessedThroughInstanceCheck::registerMatchers(MatchFinder *Finder) { 42 Finder->addMatcher( 43 memberExpr(hasDeclaration(anyOf(cxxMethodDecl(isStaticStorageClass()), 44 varDecl(hasStaticStorageDuration())))) 45 .bind("memberExpression"), 46 this); 47 } 48 check(const MatchFinder::MatchResult & Result)49void StaticAccessedThroughInstanceCheck::check( 50 const MatchFinder::MatchResult &Result) { 51 const auto *MemberExpression = 52 Result.Nodes.getNodeAs<MemberExpr>("memberExpression"); 53 54 if (MemberExpression->getBeginLoc().isMacroID()) 55 return; 56 57 const Expr *BaseExpr = MemberExpression->getBase(); 58 59 // Do not warn for overloaded -> 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 PrintingPolicyWithSupressedTag.SuppressUnwrittenScope = true; 72 73 PrintingPolicyWithSupressedTag.PrintCanonicalTypes = 74 !BaseExpr->getType()->isTypedefNameType(); 75 76 std::string BaseTypeName = 77 BaseType.getAsString(PrintingPolicyWithSupressedTag); 78 79 // Do not warn for CUDA built-in variables. 80 if (StringRef(BaseTypeName).startswith("__cuda_builtin_")) 81 return; 82 83 SourceLocation MemberExprStartLoc = MemberExpression->getBeginLoc(); 84 auto Diag = 85 diag(MemberExprStartLoc, "static member accessed through instance"); 86 87 if (BaseExpr->HasSideEffects(*AstContext) || 88 getNameSpecifierNestingLevel(BaseType) > NameSpecifierNestingThreshold) 89 return; 90 91 Diag << FixItHint::CreateReplacement( 92 CharSourceRange::getCharRange(MemberExprStartLoc, 93 MemberExpression->getMemberLoc()), 94 BaseTypeName + "::"); 95 } 96 97 } // namespace readability 98 } // namespace tidy 99 } // namespace clang 100