clang-tools 22.0.0git
PreferStaticOverAnonymousNamespaceCheck.cpp
Go to the documentation of this file.
1//===--- PreferStaticOverAnonymousNamespaceCheck.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
10#include "clang/ASTMatchers/ASTMatchFinder.h"
11
12using namespace clang::ast_matchers;
13
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} // namespace
36
39 ClangTidyContext *Context)
40 : ClangTidyCheck(Name, Context),
41 AllowVariableDeclarations(Options.get("AllowVariableDeclarations", true)),
42 AllowMemberFunctionsInClass(
43 Options.get("AllowMemberFunctionsInClass", true)) {}
44
47 Options.store(Opts, "AllowVariableDeclarations", AllowVariableDeclarations);
48 Options.store(Opts, "AllowMemberFunctionsInClass",
49 AllowMemberFunctionsInClass);
50}
51
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
79 const MatchFinder::MatchResult &Result) {
80
81 if (const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("function")) {
82 if (Func->isCXXClassMember())
83 diag(Func->getLocation(),
84 "place definition of method %0 outside of an anonymous namespace")
85 << Func;
86 else if (Func->isStatic())
87 diag(Func->getLocation(),
88 "place static function %0 outside of an anonymous namespace")
89 << Func;
90 else
91 diag(Func->getLocation(),
92 "function %0 is declared in an anonymous namespace; "
93 "prefer using 'static' for restricting visibility")
94 << Func;
95 return;
96 }
97
98 if (const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var")) {
99 if (Var->getStorageClass() == SC_Static)
100 diag(Var->getLocation(),
101 "place static variable %0 outside of an anonymous namespace")
102 << Var;
103 else
104 diag(Var->getLocation(),
105 "variable %0 is declared in an anonymous namespace; "
106 "prefer using 'static' for restricting visibility")
107 << Var;
108 }
109}
110
111} // namespace clang::tidy::llvm_check
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
AST_MATCHER(BinaryOperator, isRelationalOperator)
llvm::StringMap< ClangTidyValue > OptionMap