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