Index: clang-tools-extra/trunk/clang-tidy/readability/CMakeLists.txt =================================================================== --- clang-tools-extra/trunk/clang-tidy/readability/CMakeLists.txt +++ clang-tools-extra/trunk/clang-tidy/readability/CMakeLists.txt @@ -17,6 +17,7 @@ RedundantSmartptrGetCheck.cpp RedundantStringInitCheck.cpp SimplifyBooleanExprCheck.cpp + StaticDefinitionInAnonymousNamespaceCheck.cpp UniqueptrDeleteReleaseCheck.cpp LINK_LIBS Index: clang-tools-extra/trunk/clang-tidy/readability/ReadabilityTidyModule.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/readability/ReadabilityTidyModule.cpp +++ clang-tools-extra/trunk/clang-tidy/readability/ReadabilityTidyModule.cpp @@ -24,6 +24,7 @@ #include "RedundantStringCStrCheck.h" #include "RedundantStringInitCheck.h" #include "SimplifyBooleanExprCheck.h" +#include "StaticDefinitionInAnonymousNamespaceCheck.h" #include "UniqueptrDeleteReleaseCheck.h" namespace clang { @@ -49,6 +50,8 @@ "readability-implicit-bool-cast"); CheckFactories.registerCheck( "readability-inconsistent-declaration-parameter-name"); + CheckFactories.registerCheck( + "readability-static-definition-in-anonymous-namespace"); CheckFactories.registerCheck( "readability-named-parameter"); CheckFactories.registerCheck( Index: clang-tools-extra/trunk/clang-tidy/readability/StaticDefinitionInAnonymousNamespaceCheck.h =================================================================== --- clang-tools-extra/trunk/clang-tidy/readability/StaticDefinitionInAnonymousNamespaceCheck.h +++ clang-tools-extra/trunk/clang-tidy/readability/StaticDefinitionInAnonymousNamespaceCheck.h @@ -0,0 +1,35 @@ +//===--- StaticDefinitionInAnonymousNamespaceCheck.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_DEFINITION_IN_ANONYMOUS_NAMESPACE_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STATIC_DEFINITION_IN_ANONYMOUS_NAMESPACE_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace readability { + +/// Finds static function and variable definitions in anonymous namespace. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/readability-static-definition-in-anonymous-namespace.html +class StaticDefinitionInAnonymousNamespaceCheck : public ClangTidyCheck { +public: + StaticDefinitionInAnonymousNamespaceCheck(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_DEFINITION_IN_ANONYMOUS_NAMESPACE_H Index: clang-tools-extra/trunk/clang-tidy/readability/StaticDefinitionInAnonymousNamespaceCheck.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/readability/StaticDefinitionInAnonymousNamespaceCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/readability/StaticDefinitionInAnonymousNamespaceCheck.cpp @@ -0,0 +1,72 @@ +//===--- StaticDefinitionInAnonymousNamespaceCheck.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 "StaticDefinitionInAnonymousNamespaceCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace readability { + +namespace { +AST_POLYMORPHIC_MATCHER(isStatic, AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl, + VarDecl)) { + return Node.getStorageClass() == SC_Static; +} +} // namespace + +void StaticDefinitionInAnonymousNamespaceCheck::registerMatchers( + MatchFinder *Finder) { + Finder->addMatcher(namedDecl(anyOf(functionDecl(isDefinition(), isStatic()), + varDecl(isDefinition(), isStatic())), + hasParent(namespaceDecl(isAnonymous()))) + .bind("static-def"), + this); +} + +void StaticDefinitionInAnonymousNamespaceCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *Def = Result.Nodes.getNodeAs("static-def"); + // Skips all static definitions defined in Macro. + if (Def->getLocation().isMacroID()) + return; + + // Skips all static definitions in function scope. + const DeclContext *DC = Def->getDeclContext(); + if (DC->getDeclKind() != Decl::Namespace) + return; + + auto Diag = + diag(Def->getLocation(), "%0 is a static definition in " + "anonymous namespace; static is redundant here") + << Def; + Token Tok; + SourceLocation Loc = Def->getSourceRange().getBegin(); + while (Loc < Def->getSourceRange().getEnd() && + !Lexer::getRawToken(Loc, Tok, *Result.SourceManager, + Result.Context->getLangOpts(), true)) { + SourceRange TokenRange(Tok.getLocation(), Tok.getEndLoc()); + StringRef SourceText = Lexer::getSourceText( + CharSourceRange::getTokenRange(TokenRange), + *Result.SourceManager, Result.Context->getLangOpts()); + if (SourceText == "static") { + Diag << FixItHint::CreateRemoval(TokenRange); + break; + } + Loc = Tok.getEndLoc(); + } +} + +} // namespace readability +} // namespace tidy +} // namespace clang Index: clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst @@ -107,4 +107,5 @@ readability-redundant-string-cstr readability-redundant-string-init readability-simplify-boolean-expr + readability-static-definition-in-anonymous-namespace readability-uniqueptr-delete-release Index: clang-tools-extra/trunk/docs/clang-tidy/checks/readability-static-definition-in-anonymous-namespace.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/readability-static-definition-in-anonymous-namespace.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/readability-static-definition-in-anonymous-namespace.rst @@ -0,0 +1,17 @@ +.. title:: clang-tidy - readability-static-definition-in-anonymous-namespace + +readability-static-definition-in-anonymous-namespace +==================================================== + +Finds static function and variable definitions in anonymous namespace. + +In this case, ``static`` is redundant, because anonymous namespace limits the +visibility of definitions to a single translation unit. + +.. code:: c++ + namespace { + static int a = 1; // Warning. + static const b = 1; // Warning. + } + +The check will apply a fix by removing the redundant ``static`` qualifier. Index: clang-tools-extra/trunk/test/clang-tidy/readability-static-definition-in-anonymous-namespace.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/readability-static-definition-in-anonymous-namespace.cpp +++ clang-tools-extra/trunk/test/clang-tidy/readability-static-definition-in-anonymous-namespace.cpp @@ -0,0 +1,49 @@ +// RUN: %check_clang_tidy %s readability-static-definition-in-anonymous-namespace %t + +namespace { + +int a = 1; +const int b = 1; +static int c = 1; +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: 'c' is a static definition in anonymous namespace; static is redundant here [readability-static-definition-in-anonymous-namespace] +// CHECK-FIXES: {{^}}int c = 1; +static const int d = 1; +// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: 'd' is a static definition in anonymous namespace +// CHECK-FIXES: {{^}}const int d = 1; +const static int e = 1; +// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: 'e' is a static definition in anonymous namespace +// CHECK-FIXES: {{^}}const int e = 1; + +void f() { + int a = 1; + static int b = 1; +} + +static int g() { +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: 'g' is a static definition in anonymous namespace +// CHECK-FIXES: {{^}}int g() { + return 1; +} + +#define DEFINE_STATIC static +// CHECK-FIXES: {{^}}#define DEFINE_STATIC static +DEFINE_STATIC int h = 1; +// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: 'h' is a static definition in anonymous namespace +// CHECK-FIXES: {{^}}DEFINE_STATIC int h = 1; + +#define DEFINE_STATIC_VAR(x) static int x = 2 +// CHECK-FIXES: {{^}}#define DEFINE_STATIC_VAR(x) static int x = 2 +DEFINE_STATIC_VAR(i); +// CHECK-FIXES: {{^}}DEFINE_STATIC_VAR(i); + +} // namespace + +namespace N { + +int a = 1; +const int b = 1; +static int c = 1; +static const int d = 1; +const static int e = 1; + +} // namespace N