Skip to content

Commit

Permalink
[clang-tidy] Add new readability non-idiomatic static access check
Browse files Browse the repository at this point in the history
Patch by: Lilla Barancsuk

Differential Revision: https://reviews.llvm.org/D35937

llvm-svn: 310371
  • Loading branch information
Xazax-hun committed Aug 8, 2017
1 parent 741d21f commit 40b6512
Show file tree
Hide file tree
Showing 9 changed files with 429 additions and 0 deletions.
1 change: 1 addition & 0 deletions clang-tools-extra/clang-tidy/readability/CMakeLists.txt
Expand Up @@ -25,6 +25,7 @@ add_clang_library(clangTidyReadabilityModule
RedundantSmartptrGetCheck.cpp
RedundantStringInitCheck.cpp
SimplifyBooleanExprCheck.cpp
StaticAccessedThroughInstanceCheck.cpp
StaticDefinitionInAnonymousNamespaceCheck.cpp
UniqueptrDeleteReleaseCheck.cpp

Expand Down
Expand Up @@ -32,6 +32,7 @@
#include "RedundantStringCStrCheck.h"
#include "RedundantStringInitCheck.h"
#include "SimplifyBooleanExprCheck.h"
#include "StaticAccessedThroughInstanceCheck.h"
#include "StaticDefinitionInAnonymousNamespaceCheck.h"
#include "UniqueptrDeleteReleaseCheck.h"

Expand Down Expand Up @@ -70,6 +71,8 @@ class ReadabilityModule : public ClangTidyModule {
"readability-redundant-function-ptr-dereference");
CheckFactories.registerCheck<RedundantMemberInitCheck>(
"readability-redundant-member-init");
CheckFactories.registerCheck<StaticAccessedThroughInstanceCheck>(
"readability-static-accessed-through-instance");
CheckFactories.registerCheck<StaticDefinitionInAnonymousNamespaceCheck>(
"readability-static-definition-in-anonymous-namespace");
CheckFactories.registerCheck<readability::NamedParameterCheck>(
Expand Down
@@ -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
@@ -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
6 changes: 6 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Expand Up @@ -71,6 +71,12 @@ Improvements to clang-tidy
``AllowConditionalPointerCasts`` -> ``AllowPointerConditions``.


- New `readability-static-accessed-through-instance
<http://clang.llvm.org/extra/clang-tidy/checks/readability-static-accessed-through-instance.html>`_ check

Finds member expressions that access static members through instances and
replaces them with uses of the appropriate qualified-id.

Improvements to include-fixer
-----------------------------

Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/docs/clang-tidy/checks/list.rst
Expand Up @@ -178,5 +178,6 @@ Clang-Tidy Checks
readability-redundant-string-cstr
readability-redundant-string-init
readability-simplify-boolean-expr
readability-static-accessed-through-instance
readability-static-definition-in-anonymous-namespace
readability-uniqueptr-delete-release
@@ -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;

@@ -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;{{$}}
}

0 comments on commit 40b6512

Please sign in to comment.