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 void StaticDefinitionInAnonymousNamespaceCheck::registerMatchers( 21 MatchFinder *Finder) { 22 Finder->addMatcher( 23 namedDecl(anyOf(functionDecl(isDefinition(), isStaticStorageClass()), 24 varDecl(isDefinition(), isStaticStorageClass())), 25 hasParent(namespaceDecl(isAnonymous()))) 26 .bind("static-def"), 27 this); 28 } 29 30 void StaticDefinitionInAnonymousNamespaceCheck::check( 31 const MatchFinder::MatchResult &Result) { 32 const auto *Def = Result.Nodes.getNodeAs<NamedDecl>("static-def"); 33 // Skips all static definitions defined in Macro. 34 if (Def->getLocation().isMacroID()) 35 return; 36 37 // Skips all static definitions in function scope. 38 const DeclContext *DC = Def->getDeclContext(); 39 if (DC->getDeclKind() != Decl::Namespace) 40 return; 41 42 auto Diag = 43 diag(Def->getLocation(), "%0 is a static definition in " 44 "anonymous namespace; static is redundant here") 45 << Def; 46 Token Tok; 47 SourceLocation Loc = Def->getSourceRange().getBegin(); 48 while (Loc < Def->getSourceRange().getEnd() && 49 !Lexer::getRawToken(Loc, Tok, *Result.SourceManager, getLangOpts(), 50 true)) { 51 SourceRange TokenRange(Tok.getLocation(), Tok.getEndLoc()); 52 StringRef SourceText = 53 Lexer::getSourceText(CharSourceRange::getTokenRange(TokenRange), 54 *Result.SourceManager, getLangOpts()); 55 if (SourceText == "static") { 56 Diag << FixItHint::CreateRemoval(TokenRange); 57 break; 58 } 59 Loc = Tok.getEndLoc(); 60 } 61 } 62 63 } // namespace readability 64 } // namespace tidy 65 } // namespace clang 66