Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[clang-tidy] Add new readability non-idiomatic static access check
Patch by: Lilla Barancsuk Differential Revision: https://reviews.llvm.org/D35937 llvm-svn: 310371
- Loading branch information
Showing
9 changed files
with
429 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
90 changes: 90 additions & 0 deletions
90
clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
//===--- 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->getLocStart().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->getLocStart(); | ||
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 |
43 changes: 43 additions & 0 deletions
43
clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
//===--- StaticAccessedThroughInstanceCheck.h - clang-tidy-------*- C++ -*-===// | ||
// | ||
// The LLVM Compiler Infrastructure | ||
// | ||
// This file is distributed under the University of Illinois Open Source | ||
// License. See LICENSE.TXT for details. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STATIC_ACCESSED_THROUGH_INSTANCE_H | ||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STATIC_ACCESSED_THROUGH_INSTANCE_H | ||
|
||
#include "../ClangTidy.h" | ||
|
||
namespace clang { | ||
namespace tidy { | ||
namespace readability { | ||
|
||
/// \@brief Checks for member expressions that access static members through | ||
/// instances and replaces them with uses of the appropriate qualified-id. | ||
/// | ||
/// For the user-facing documentation see: | ||
/// http://clang.llvm.org/extra/clang-tidy/checks/readability-static-accessed-through-instance.html | ||
class StaticAccessedThroughInstanceCheck : public ClangTidyCheck { | ||
public: | ||
StaticAccessedThroughInstanceCheck(StringRef Name, ClangTidyContext *Context) | ||
: ClangTidyCheck(Name, Context), | ||
NameSpecifierNestingThreshold( | ||
Options.get("NameSpecifierNestingThreshold", 3)) {} | ||
|
||
void storeOptions(ClangTidyOptions::OptionMap &Opts) override; | ||
void registerMatchers(ast_matchers::MatchFinder *Finder) override; | ||
void check(const ast_matchers::MatchFinder::MatchResult &Result) override; | ||
|
||
private: | ||
const unsigned NameSpecifierNestingThreshold; | ||
}; | ||
|
||
} // namespace readability | ||
} // namespace tidy | ||
} // namespace clang | ||
|
||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STATIC_ACCESSED_THROUGH_INSTANCE_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
...s-extra/docs/clang-tidy/checks/readability-static-accessed-through-instance.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
.. title:: clang-tidy - readability-static-accessed-through-instance | ||
|
||
readability-static-accessed-through-instance | ||
============================================ | ||
|
||
Checks for member expressions that access static members through instances, and | ||
replaces them with uses of the appropriate qualified-id. | ||
|
||
Example: | ||
|
||
The following code: | ||
|
||
.. code-block:: c++ | ||
|
||
struct C { | ||
static void foo(); | ||
static int x; | ||
}; | ||
|
||
C *c1 = new C(); | ||
c1->foo(); | ||
c1->x; | ||
is changed to: | ||
|
||
.. code-block:: c++ | ||
|
||
C::foo(); | ||
C::x; | ||
|
33 changes: 33 additions & 0 deletions
33
...-extra/test/clang-tidy/readability-static-accessed-through-instance-nesting-threshold.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// RUN: %check_clang_tidy %s readability-static-accessed-through-instance %t -- -config="{CheckOptions: [{key: readability-static-accessed-through-instance.NameSpecifierNestingThreshold, value: 4}]}" -- | ||
|
||
// Nested specifiers | ||
namespace M { | ||
namespace N { | ||
struct V { | ||
static int v; | ||
struct T { | ||
static int t; | ||
struct U { | ||
static int u; | ||
}; | ||
}; | ||
}; | ||
} | ||
} | ||
|
||
void f(M::N::V::T::U u) { | ||
M::N::V v; | ||
v.v = 12; | ||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member | ||
// CHECK-FIXES: {{^}} M::N::V::v = 12;{{$}} | ||
|
||
M::N::V::T w; | ||
w.t = 12; | ||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member | ||
// CHECK-FIXES: {{^}} M::N::V::T::t = 12;{{$}} | ||
|
||
// u.u is not changed, because the nesting level is over 4 | ||
u.u = 12; | ||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member | ||
// CHECK-FIXES: {{^}} u.u = 12;{{$}} | ||
} |
Oops, something went wrong.