forked from OSchip/llvm-project
91 lines
3.0 KiB
C++
91 lines
3.0 KiB
C++
//===--- StaticAccessedThroughInstanceCheck.cpp - clang-tidy---------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "StaticAccessedThroughInstanceCheck.h"
|
|
#include "clang/AST/ASTContext.h"
|
|
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
|
|
|
using namespace clang::ast_matchers;
|
|
|
|
namespace clang {
|
|
namespace tidy {
|
|
namespace readability {
|
|
|
|
static unsigned getNameSpecifierNestingLevel(const QualType &QType) {
|
|
if (const ElaboratedType *ElType = QType->getAs<ElaboratedType>()) {
|
|
const NestedNameSpecifier *NestedSpecifiers = ElType->getQualifier();
|
|
unsigned NameSpecifierNestingLevel = 1;
|
|
do {
|
|
NameSpecifierNestingLevel++;
|
|
NestedSpecifiers = NestedSpecifiers->getPrefix();
|
|
} while (NestedSpecifiers);
|
|
|
|
return NameSpecifierNestingLevel;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void StaticAccessedThroughInstanceCheck::storeOptions(
|
|
ClangTidyOptions::OptionMap &Opts) {
|
|
Options.store(Opts, "NameSpecifierNestingThreshold",
|
|
NameSpecifierNestingThreshold);
|
|
}
|
|
|
|
void StaticAccessedThroughInstanceCheck::registerMatchers(MatchFinder *Finder) {
|
|
Finder->addMatcher(
|
|
memberExpr(hasDeclaration(anyOf(cxxMethodDecl(isStaticStorageClass()),
|
|
varDecl(hasStaticStorageDuration()))),
|
|
unless(isInTemplateInstantiation()))
|
|
.bind("memberExpression"),
|
|
this);
|
|
}
|
|
|
|
void StaticAccessedThroughInstanceCheck::check(
|
|
const MatchFinder::MatchResult &Result) {
|
|
const auto *MemberExpression =
|
|
Result.Nodes.getNodeAs<MemberExpr>("memberExpression");
|
|
|
|
if (MemberExpression->getBeginLoc().isMacroID())
|
|
return;
|
|
|
|
const Expr *BaseExpr = MemberExpression->getBase();
|
|
|
|
// Do not warn for overlaoded -> operators.
|
|
if (isa<CXXOperatorCallExpr>(BaseExpr))
|
|
return;
|
|
|
|
QualType BaseType =
|
|
BaseExpr->getType()->isPointerType()
|
|
? BaseExpr->getType()->getPointeeType().getUnqualifiedType()
|
|
: BaseExpr->getType().getUnqualifiedType();
|
|
|
|
const ASTContext *AstContext = Result.Context;
|
|
PrintingPolicy PrintingPolicyWithSupressedTag(AstContext->getLangOpts());
|
|
PrintingPolicyWithSupressedTag.SuppressTagKeyword = true;
|
|
std::string BaseTypeName =
|
|
BaseType.getAsString(PrintingPolicyWithSupressedTag);
|
|
|
|
SourceLocation MemberExprStartLoc = MemberExpression->getBeginLoc();
|
|
auto Diag =
|
|
diag(MemberExprStartLoc, "static member accessed through instance");
|
|
|
|
if (BaseExpr->HasSideEffects(*AstContext) ||
|
|
getNameSpecifierNestingLevel(BaseType) > NameSpecifierNestingThreshold)
|
|
return;
|
|
|
|
Diag << FixItHint::CreateReplacement(
|
|
CharSourceRange::getCharRange(MemberExprStartLoc,
|
|
MemberExpression->getMemberLoc()),
|
|
BaseTypeName + "::");
|
|
}
|
|
|
|
} // namespace readability
|
|
} // namespace tidy
|
|
} // namespace clang
|