Index: clang-tidy/readability/CMakeLists.txt =================================================================== --- clang-tidy/readability/CMakeLists.txt +++ clang-tidy/readability/CMakeLists.txt @@ -25,6 +25,7 @@ RedundantSmartptrGetCheck.cpp RedundantStringInitCheck.cpp SimplifyBooleanExprCheck.cpp + StaticAccessedThroughInstanceCheck.cpp StaticDefinitionInAnonymousNamespaceCheck.cpp UniqueptrDeleteReleaseCheck.cpp Index: clang-tidy/readability/ReadabilityTidyModule.cpp =================================================================== --- clang-tidy/readability/ReadabilityTidyModule.cpp +++ clang-tidy/readability/ReadabilityTidyModule.cpp @@ -32,6 +32,7 @@ #include "RedundantStringCStrCheck.h" #include "RedundantStringInitCheck.h" #include "SimplifyBooleanExprCheck.h" +#include "StaticAccessedThroughInstanceCheck.h" #include "StaticDefinitionInAnonymousNamespaceCheck.h" #include "UniqueptrDeleteReleaseCheck.h" @@ -70,6 +71,8 @@ "readability-redundant-function-ptr-dereference"); CheckFactories.registerCheck( "readability-redundant-member-init"); + CheckFactories.registerCheck( + "readability-static-accessed-through-instance"); CheckFactories.registerCheck( "readability-static-definition-in-anonymous-namespace"); CheckFactories.registerCheck( Index: clang-tidy/readability/StaticAccessedThroughInstanceCheck.h =================================================================== --- /dev/null +++ clang-tidy/readability/StaticAccessedThroughInstanceCheck.h @@ -0,0 +1,36 @@ +//===--- 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 calls to the preferred, more readable `::` operator. +/// +/// 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) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace readability +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STATIC_ACCESSED_THROUGH_INSTANCE_H Index: clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp @@ -0,0 +1,59 @@ +//===--- 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 { + +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("memberExpression"); + + if (MemberExpression->getLocStart().isMacroID()) + return; + + const Expr *BaseExpr = MemberExpression->getBase(); + + QualType BaseType = + BaseExpr->getType()->isPointerType() + ? BaseExpr->getType().getUnqualifiedType()->getPointeeType() + : BaseExpr->getType().getUnqualifiedType(); + + PrintingPolicy PrintingPolicyWithSupressedTag(Result.Context->getLangOpts()); + PrintingPolicyWithSupressedTag.SuppressTagKeyword = true; + std::string BaseTypeName = + BaseType.getAsString(PrintingPolicyWithSupressedTag); + + diag(MemberExpression->getLocStart(), + "static member accessed through instance") + << FixItHint::CreateReplacement( + CharSourceRange::getCharRange(MemberExpression->getLocStart(), + MemberExpression->getMemberLoc()), + BaseTypeName + "::"); +} + +} // namespace readability +} // namespace tidy +} // namespace clang Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -142,6 +142,12 @@ Finds misleading indentation where braces should be introduced or the code should be reformatted. +- New `readability-static-accessed-through-instance + `_ check + + Finds member expressions that access static members through instances and + replaces them with the corresponding expressions that use a more readable scope operator. + - Support clang-formatting of the code around applied fixes (``-format-style`` command-line option). Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -175,5 +175,6 @@ 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 Index: docs/clang-tidy/checks/readability-static-accessed-through-instance.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/readability-static-accessed-through-instance.rst @@ -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 the corresponding expressions that use a more readable `::` operator. + +Example: + +Thefollowing 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; + Index: test/clang-tidy/readability-static-accessed-through-instance.cpp =================================================================== --- /dev/null +++ test/clang-tidy/readability-static-accessed-through-instance.cpp @@ -0,0 +1,137 @@ +// RUN: %check_clang_tidy %s readability-static-accessed-through-instance %t + +struct C { + static void foo(); + static int x; + int nsx; + void mf() { + (void)&x; // OK, x is accessed inside the struct. + (void)&C::x; // OK, x is accessed using the scope operator. + foo(); // OK, foo() is accessed inside the struct. + } +}; + +struct CC { + void foo(); + int x; +}; + +template struct CT { + static T foo(); + static T x; + int nsx; + void mf() { + (void)&x; // OK, x is accessed inside the struct. + (void)&C::x; // OK, x is accessed using the scope operator. + foo(); // OK, foo() is accessed inside the struct. + } +}; + +C &f(int, int, int, int); +void g() { + f(1, 2, 3, 4).x; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through instance [readability-static-accessed-through-instance] + // CHECK-FIXES: {{^}} C::x;{{$}} +} + +template T CT::x; + +template struct CCT { + T foo(); + T x; +}; + +typedef C D; + +using E = D; + +#define FOO(c) c.foo() +#define X(c) c.x + +template void f(T t, C c) { + t.x; // OK, t is a template parameter. + c.x; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through + // instance [readability-static-accessed-through-instance] + // CHECK-FIXES: {{^}} C::x;{{$}} +} + +template struct S { static int x; }; + +template <> struct S<0> { int x; }; + +template void h() { + S sN; + sN.x; // OK, value of N affects whether x is static or not. + + S<2> s2; + s2.x; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through + // instance [readability-static-accessed-through-instance] + // CHECK-FIXES: {{^}} S<2>::x;{{$}} +} + +void static_through_instance() { + C *c1 = new C(); + c1->foo(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through + // instance [readability-static-accessed-through-instance] + // CHECK-FIXES: {{^}} C::foo();{{$}} + c1->x; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through + // instance [readability-static-accessed-through-instance] + // CHECK-FIXES: {{^}} C::x;{{$}} + c1->nsx; // OK, nsx is a non-static member. + + C::foo(); // OK, foo() is accessed using the scope operator. + C::x; // OK, x is accessed using the scope operator. + + D d; + d.foo(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through + // instance [readability-static-accessed-through-instance] + // CHECK-FIXES: {{^}} D::foo();{{$}} + d.x; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through + // instance [readability-static-accessed-through-instance] + // CHECK-FIXES: {{^}} D::x;{{$}} + + E e; + e.foo(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through + // instance [readability-static-accessed-through-instance] + // CHECK-FIXES: {{^}} E::foo();{{$}} + e.x; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through + // instance [readability-static-accessed-through-instance] + // CHECK-FIXES: {{^}} E::x;{{$}} + + CC *cc = new CC; + + f(*c1, *c1); + f(*cc, *c1); + + // Macros: OK, macros are not checked. + FOO((*c1)); + X((*c1)); + FOO((*cc)); + X((*cc)); + + // Templates + CT ct; + ct.foo(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through + // instance [readability-static-accessed-through-instance] + // CHECK-FIXES: {{^}} CT::foo();{{$}} + ct.x; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through + // instance [readability-static-accessed-through-instance] + // CHECK-FIXES: {{^}} CT::x;{{$}} + ct.nsx; // OK, nsx is a non-static member + + CCT cct; + cct.foo(); // OK, CCT has no static members. + cct.x; // OK, CCT has no static members. + + h<4>(); +}