clang-tools 23.0.0git
PreferStaticOverAnonymousNamespaceCheck.cpp
Go to the documentation of this file.
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-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 isLexicallyInAnonymousNamespace(), unless(isInMacro()), isDefinition());
56
57 if (AllowMemberFunctionsInClass) {
58 Finder->addMatcher(
59 functionDecl(IsDefinitionInAnonymousNamespace,
60 unless(anyOf(hasParent(cxxRecordDecl()),
61 hasParent(functionTemplateDecl(
62 hasParent(cxxRecordDecl()))))))
63 .bind("function"),
64 this);
65 } else {
66 Finder->addMatcher(
67 functionDecl(IsDefinitionInAnonymousNamespace).bind("function"), this);
68 }
69
70 if (!AllowVariableDeclarations)
71 Finder->addMatcher(varDecl(IsDefinitionInAnonymousNamespace,
72 unless(isLocalVariable()), unless(parmVarDecl()))
73 .bind("var"),
74 this);
75}
76
78 const MatchFinder::MatchResult &Result) {
79 if (const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("function")) {
80 if (Func->isCXXClassMember())
81 diag(Func->getLocation(),
82 "place definition of method %0 outside of an anonymous namespace")
83 << Func;
84 else if (Func->isStatic())
85 diag(Func->getLocation(),
86 "place static function %0 outside of an anonymous namespace")
87 << Func;
88 else
89 diag(Func->getLocation(),
90 "function %0 is declared in an anonymous namespace; "
91 "prefer using 'static' for restricting visibility")
92 << Func;
93 return;
94 }
95
96 if (const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var")) {
97 if (Var->getStorageClass() == SC_Static)
98 diag(Var->getLocation(),
99 "place static variable %0 outside of an anonymous namespace")
100 << Var;
101 else
102 diag(Var->getLocation(),
103 "variable %0 is declared in an anonymous namespace; "
104 "prefer using 'static' for restricting visibility")
105 << Var;
106 }
107}
108
109} // 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