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 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 .bind("memberExpression"), 45 this); 46 } 47 48 void 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 overloaded -> 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 // Do not warn for CUDA built-in variables. 75 if (StringRef(BaseTypeName).startswith("__cuda_builtin_")) 76 return; 77 78 SourceLocation MemberExprStartLoc = MemberExpression->getBeginLoc(); 79 auto Diag = 80 diag(MemberExprStartLoc, "static member accessed through instance"); 81 82 if (BaseExpr->HasSideEffects(*AstContext) || 83 getNameSpecifierNestingLevel(BaseType) > NameSpecifierNestingThreshold) 84 return; 85 86 Diag << FixItHint::CreateReplacement( 87 CharSourceRange::getCharRange(MemberExprStartLoc, 88 MemberExpression->getMemberLoc()), 89 BaseTypeName + "::"); 90 } 91 92 } // namespace readability 93 } // namespace tidy 94 } // namespace clang 95