111 lines · cpp
1//===----------------------------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "PreferStaticOverAnonymousNamespaceCheck.h"10#include "clang/ASTMatchers/ASTMatchFinder.h"11 12using namespace clang::ast_matchers;13 14namespace clang::tidy::llvm_check {15 16namespace {17 18AST_MATCHER(NamedDecl, isInMacro) {19 return Node.getBeginLoc().isMacroID() || Node.getEndLoc().isMacroID();20}21 22AST_MATCHER(VarDecl, isLocalVariable) { return Node.isLocalVarDecl(); }23 24AST_MATCHER(Decl, isLexicallyInAnonymousNamespace) {25 for (const DeclContext *DC = Node.getLexicalDeclContext(); DC != nullptr;26 DC = DC->getLexicalParent()) {27 if (const auto *ND = dyn_cast<NamespaceDecl>(DC))28 if (ND->isAnonymousNamespace())29 return true;30 }31 32 return false;33}34 35} // namespace36 37PreferStaticOverAnonymousNamespaceCheck::38 PreferStaticOverAnonymousNamespaceCheck(StringRef Name,39 ClangTidyContext *Context)40 : ClangTidyCheck(Name, Context),41 AllowVariableDeclarations(Options.get("AllowVariableDeclarations", true)),42 AllowMemberFunctionsInClass(43 Options.get("AllowMemberFunctionsInClass", true)) {}44 45void PreferStaticOverAnonymousNamespaceCheck::storeOptions(46 ClangTidyOptions::OptionMap &Opts) {47 Options.store(Opts, "AllowVariableDeclarations", AllowVariableDeclarations);48 Options.store(Opts, "AllowMemberFunctionsInClass",49 AllowMemberFunctionsInClass);50}51 52void PreferStaticOverAnonymousNamespaceCheck::registerMatchers(53 MatchFinder *Finder) {54 const auto IsDefinitionInAnonymousNamespace = allOf(55 unless(isExpansionInSystemHeader()), isLexicallyInAnonymousNamespace(),56 unless(isInMacro()), isDefinition());57 58 if (AllowMemberFunctionsInClass) {59 Finder->addMatcher(60 functionDecl(IsDefinitionInAnonymousNamespace,61 unless(anyOf(hasParent(cxxRecordDecl()),62 hasParent(functionTemplateDecl(63 hasParent(cxxRecordDecl()))))))64 .bind("function"),65 this);66 } else {67 Finder->addMatcher(68 functionDecl(IsDefinitionInAnonymousNamespace).bind("function"), this);69 }70 71 if (!AllowVariableDeclarations)72 Finder->addMatcher(varDecl(IsDefinitionInAnonymousNamespace,73 unless(isLocalVariable()), unless(parmVarDecl()))74 .bind("var"),75 this);76}77 78void PreferStaticOverAnonymousNamespaceCheck::check(79 const MatchFinder::MatchResult &Result) {80 if (const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("function")) {81 if (Func->isCXXClassMember())82 diag(Func->getLocation(),83 "place definition of method %0 outside of an anonymous namespace")84 << Func;85 else if (Func->isStatic())86 diag(Func->getLocation(),87 "place static function %0 outside of an anonymous namespace")88 << Func;89 else90 diag(Func->getLocation(),91 "function %0 is declared in an anonymous namespace; "92 "prefer using 'static' for restricting visibility")93 << Func;94 return;95 }96 97 if (const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var")) {98 if (Var->getStorageClass() == SC_Static)99 diag(Var->getLocation(),100 "place static variable %0 outside of an anonymous namespace")101 << Var;102 else103 diag(Var->getLocation(),104 "variable %0 is declared in an anonymous namespace; "105 "prefer using 'static' for restricting visibility")106 << Var;107 }108}109 110} // namespace clang::tidy::llvm_check111