1 //===--- StaticAccessedThroughInstanceCheck.cpp - clang-tidy---------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "StaticAccessedThroughInstanceCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "llvm/ADT/StringRef.h"
14 using namespace clang::ast_matchers
;
18 namespace readability
{
20 static unsigned getNameSpecifierNestingLevel(const QualType
&QType
) {
21 if (const ElaboratedType
*ElType
= QType
->getAs
<ElaboratedType
>()) {
22 if (const NestedNameSpecifier
*NestedSpecifiers
= ElType
->getQualifier()) {
23 unsigned NameSpecifierNestingLevel
= 1;
25 NameSpecifierNestingLevel
++;
26 NestedSpecifiers
= NestedSpecifiers
->getPrefix();
27 } while (NestedSpecifiers
);
29 return NameSpecifierNestingLevel
;
35 void StaticAccessedThroughInstanceCheck::storeOptions(
36 ClangTidyOptions::OptionMap
&Opts
) {
37 Options
.store(Opts
, "NameSpecifierNestingThreshold",
38 NameSpecifierNestingThreshold
);
41 void StaticAccessedThroughInstanceCheck::registerMatchers(MatchFinder
*Finder
) {
43 memberExpr(hasDeclaration(anyOf(cxxMethodDecl(isStaticStorageClass()),
44 varDecl(hasStaticStorageDuration()))))
45 .bind("memberExpression"),
49 void StaticAccessedThroughInstanceCheck::check(
50 const MatchFinder::MatchResult
&Result
) {
51 const auto *MemberExpression
=
52 Result
.Nodes
.getNodeAs
<MemberExpr
>("memberExpression");
54 if (MemberExpression
->getBeginLoc().isMacroID())
57 const Expr
*BaseExpr
= MemberExpression
->getBase();
59 // Do not warn for overloaded -> operators.
60 if (isa
<CXXOperatorCallExpr
>(BaseExpr
))
64 BaseExpr
->getType()->isPointerType()
65 ? BaseExpr
->getType()->getPointeeType().getUnqualifiedType()
66 : BaseExpr
->getType().getUnqualifiedType();
68 const ASTContext
*AstContext
= Result
.Context
;
69 PrintingPolicy
PrintingPolicyWithSupressedTag(AstContext
->getLangOpts());
70 PrintingPolicyWithSupressedTag
.SuppressTagKeyword
= true;
71 PrintingPolicyWithSupressedTag
.SuppressUnwrittenScope
= true;
73 PrintingPolicyWithSupressedTag
.PrintCanonicalTypes
=
74 !BaseExpr
->getType()->isTypedefNameType();
76 std::string BaseTypeName
=
77 BaseType
.getAsString(PrintingPolicyWithSupressedTag
);
79 // Do not warn for CUDA built-in variables.
80 if (StringRef(BaseTypeName
).startswith("__cuda_builtin_"))
83 SourceLocation MemberExprStartLoc
= MemberExpression
->getBeginLoc();
85 diag(MemberExprStartLoc
, "static member accessed through instance");
87 if (BaseExpr
->HasSideEffects(*AstContext
) ||
88 getNameSpecifierNestingLevel(BaseType
) > NameSpecifierNestingThreshold
)
91 Diag
<< FixItHint::CreateReplacement(
92 CharSourceRange::getCharRange(MemberExprStartLoc
,
93 MemberExpression
->getMemberLoc()),
97 } // namespace readability