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