//===--- PreferStaticOverAnonymousNamespaceCheck.cpp - clang-tidy ---------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "PreferStaticOverAnonymousNamespaceCheck.h" #include "clang/ASTMatchers/ASTMatchFinder.h" using namespace clang::ast_matchers; namespace clang::tidy::llvm_check { namespace { AST_MATCHER(NamedDecl, isInMacro) { return Node.getBeginLoc().isMacroID() || Node.getEndLoc().isMacroID(); } AST_MATCHER(VarDecl, isLocalVariable) { return Node.isLocalVarDecl(); } AST_MATCHER(Decl, isLexicallyInAnonymousNamespace) { for (const DeclContext *DC = Node.getLexicalDeclContext(); DC != nullptr; DC = DC->getLexicalParent()) { if (const auto *ND = dyn_cast(DC)) if (ND->isAnonymousNamespace()) return true; } return false; } } // namespace PreferStaticOverAnonymousNamespaceCheck:: PreferStaticOverAnonymousNamespaceCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), AllowVariableDeclarations(Options.get("AllowVariableDeclarations", true)), AllowMemberFunctionsInClass( Options.get("AllowMemberFunctionsInClass", true)) {} void PreferStaticOverAnonymousNamespaceCheck::storeOptions( ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "AllowVariableDeclarations", AllowVariableDeclarations); Options.store(Opts, "AllowMemberFunctionsInClass", AllowMemberFunctionsInClass); } void PreferStaticOverAnonymousNamespaceCheck::registerMatchers( MatchFinder *Finder) { const auto IsDefinitionInAnonymousNamespace = allOf( unless(isExpansionInSystemHeader()), isLexicallyInAnonymousNamespace(), unless(isInMacro()), isDefinition()); if (AllowMemberFunctionsInClass) { Finder->addMatcher( functionDecl(IsDefinitionInAnonymousNamespace, unless(anyOf(hasParent(cxxRecordDecl()), hasParent(functionTemplateDecl( hasParent(cxxRecordDecl())))))) .bind("function"), this); } else { Finder->addMatcher( functionDecl(IsDefinitionInAnonymousNamespace).bind("function"), this); } if (!AllowVariableDeclarations) Finder->addMatcher(varDecl(IsDefinitionInAnonymousNamespace, unless(isLocalVariable()), unless(parmVarDecl())) .bind("var"), this); } void PreferStaticOverAnonymousNamespaceCheck::check( const MatchFinder::MatchResult &Result) { if (const auto *Func = Result.Nodes.getNodeAs("function")) { if (Func->isCXXClassMember()) diag(Func->getLocation(), "place definition of method %0 outside of an anonymous namespace") << Func; else if (Func->isStatic()) diag(Func->getLocation(), "place static function %0 outside of an anonymous namespace") << Func; else diag(Func->getLocation(), "function %0 is declared in an anonymous namespace; " "prefer using 'static' for restricting visibility") << Func; return; } if (const auto *Var = Result.Nodes.getNodeAs("var")) { if (Var->getStorageClass() == SC_Static) diag(Var->getLocation(), "place static variable %0 outside of an anonymous namespace") << Var; else diag(Var->getLocation(), "variable %0 is declared in an anonymous namespace; " "prefer using 'static' for restricting visibility") << Var; } } } // namespace clang::tidy::llvm_check