Index: clang-tidy/readability/CMakeLists.txt =================================================================== --- clang-tidy/readability/CMakeLists.txt +++ clang-tidy/readability/CMakeLists.txt @@ -16,6 +16,7 @@ RedundantSmartptrGetCheck.cpp RedundantStringInitCheck.cpp SimplifyBooleanExprCheck.cpp + StaticDefinitionInAnonymousNamespaceCheck.cpp UniqueptrDeleteReleaseCheck.cpp LINK_LIBS Index: clang-tidy/readability/ReadabilityTidyModule.cpp =================================================================== --- clang-tidy/readability/ReadabilityTidyModule.cpp +++ clang-tidy/readability/ReadabilityTidyModule.cpp @@ -23,6 +23,7 @@ #include "RedundantStringCStrCheck.h" #include "RedundantStringInitCheck.h" #include "SimplifyBooleanExprCheck.h" +#include "StaticDefinitionInAnonymousNamespaceCheck.h" #include "UniqueptrDeleteReleaseCheck.h" namespace clang { @@ -46,6 +47,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-tidy/readability/StaticDefinitionInAnonymousNamespaceCheck.h =================================================================== --- /dev/null +++ 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-tidy/readability/StaticDefinitionInAnonymousNamespaceCheck.cpp =================================================================== --- /dev/null +++ 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->getName(); + 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: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -101,4 +101,5 @@ readability-redundant-string-cstr readability-redundant-string-init readability-simplify-boolean-expr + readability-static-definition-in-anonymous-namespace readability-uniqueptr-delete-release Index: docs/clang-tidy/checks/readability-static-definition-in-anonymous-namespace.rst =================================================================== --- /dev/null +++ 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. + +Static is redundant in the current translation unit because anonymous namespace +is only visible in current transform 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: test/clang-tidy/readability-static-definition-in-anonymous-namespace.cpp =================================================================== --- /dev/null +++ test/clang-tidy/readability-static-definition-in-anonymous-namespace.cpp @@ -0,0 +1,46 @@ +// RUN: %check_clang_tidy %s readability-static-definition-in-anonymous-namespace %t + +#define STATIC static +#define DEFINE_STATIC_VAR(x) static int x = 2 + +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; +} + +STATIC int h = 1; +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: 'h' is a static definition in anonymous namespace + +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