1 //===--- StaticDefinitionInAnonymousNamespaceCheck.cpp - clang-tidy--------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "StaticDefinitionInAnonymousNamespaceCheck.h" 11 #include "clang/AST/ASTContext.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 13 #include "clang/Lex/Lexer.h" 14 15 using namespace clang::ast_matchers; 16 17 namespace clang { 18 namespace tidy { 19 namespace readability { 20 21 namespace { 22 AST_POLYMORPHIC_MATCHER(isStatic, AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl, 23 VarDecl)) { 24 return Node.getStorageClass() == SC_Static; 25 } 26 } // namespace 27 28 void StaticDefinitionInAnonymousNamespaceCheck::registerMatchers( 29 MatchFinder *Finder) { 30 Finder->addMatcher(namedDecl(anyOf(functionDecl(isDefinition(), isStatic()), 31 varDecl(isDefinition(), isStatic())), 32 hasParent(namespaceDecl(isAnonymous()))) 33 .bind("static-def"), 34 this); 35 } 36 37 void StaticDefinitionInAnonymousNamespaceCheck::check( 38 const MatchFinder::MatchResult &Result) { 39 const auto *Def = Result.Nodes.getNodeAs<NamedDecl>("static-def"); 40 // Skips all static definitions defined in Macro. 41 if (Def->getLocation().isMacroID()) 42 return; 43 44 // Skips all static definitions in function scope. 45 const DeclContext *DC = Def->getDeclContext(); 46 if (DC->getDeclKind() != Decl::Namespace) 47 return; 48 49 auto Diag = 50 diag(Def->getLocation(), "%0 is a static definition in " 51 "anonymous namespace; static is redundant here") 52 << Def; 53 Token Tok; 54 SourceLocation Loc = Def->getSourceRange().getBegin(); 55 while (Loc < Def->getSourceRange().getEnd() && 56 !Lexer::getRawToken(Loc, Tok, *Result.SourceManager, 57 Result.Context->getLangOpts(), true)) { 58 SourceRange TokenRange(Tok.getLocation(), Tok.getEndLoc()); 59 StringRef SourceText = Lexer::getSourceText( 60 CharSourceRange::getTokenRange(TokenRange), 61 *Result.SourceManager, Result.Context->getLangOpts()); 62 if (SourceText == "static") { 63 Diag << FixItHint::CreateRemoval(TokenRange); 64 break; 65 } 66 Loc = Tok.getEndLoc(); 67 } 68 } 69 70 } // namespace readability 71 } // namespace tidy 72 } // namespace clang 73