11#include "clang/AST/Decl.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13#include "clang/ASTMatchers/ASTMatchers.h"
14#include "clang/ASTMatchers/ASTMatchersMacros.h"
15#include "clang/Basic/Module.h"
16#include "clang/Basic/SourceLocation.h"
17#include "clang/Basic/Specifiers.h"
18#include "clang/Lex/Token.h"
19#include "llvm/ADT/DenseSet.h"
20#include "llvm/ADT/STLExtras.h"
21#include "llvm/ADT/SmallVector.h"
29 static llvm::ArrayRef<
30 std::pair<misc::UseInternalLinkageCheck::FixModeKind, StringRef>>
52 if (SM.isInMainFile(L))
55 L = SM.getIncludeLoc(SM.getFileID(L));
65AST_MATCHER(Decl, isFirstDecl) {
return Node.isFirstDecl(); }
67AST_MATCHER(FunctionDecl, hasBody) {
return Node.hasBody(); }
69AST_MATCHER(Decl, isInImportableModuleUnit) {
70 const Module *OwningModule = Node.getOwningModule();
71 return OwningModule &&
72 (OwningModule->Kind == Module::ModuleInterfaceUnit ||
73 OwningModule->Kind == Module::ModulePartitionInterface ||
74 OwningModule->Kind == Module::ModulePartitionImplementation);
78 HeaderFileExtensions) {
79 return llvm::all_of(Node.redecls(), [&](
const Decl *D) {
80 return isInMainFile(D->getLocation(),
81 Finder->getASTContext().getSourceManager(),
82 *HeaderFileExtensions);
87 AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl,
89 return Node.getStorageClass() == SC_Extern;
92AST_MATCHER(FunctionDecl, isAllocationOrDeallocationOverloadedFunction) {
99 static const llvm::DenseSet<OverloadedOperatorKind> OverloadedOperators{
100 OverloadedOperatorKind::OO_New,
101 OverloadedOperatorKind::OO_Array_New,
102 OverloadedOperatorKind::OO_Delete,
103 OverloadedOperatorKind::OO_Array_Delete,
105 return OverloadedOperators.contains(Node.getOverloadedOperator());
109 AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl,
111 return Finder->getASTContext().getLangOpts().CPlusPlus && Node.isExternC();
114AST_MATCHER(TagDecl, hasNameForLinkage) {
return Node.hasNameForLinkage(); }
116AST_MATCHER(CXXRecordDecl, isExplicitTemplateInstantiation) {
117 return Node.getTemplateSpecializationKind() ==
118 TSK_ExplicitInstantiationDefinition;
127 AnalyzeFunctions(Options.get(
"AnalyzeFunctions", true)),
128 AnalyzeVariables(Options.get(
"AnalyzeVariables", true)),
129 AnalyzeTypes(Options.get(
"AnalyzeTypes", true)) {
130 if (!AnalyzeFunctions && !AnalyzeVariables && !AnalyzeTypes)
132 "the 'misc-use-internal-linkage' check will not perform any "
133 "analysis because its 'AnalyzeFunctions', 'AnalyzeVariables', "
134 "and 'AnalyzeTypes' options have all been set to false");
138 Options.store(Opts,
"FixMode", FixMode);
139 Options.store(Opts,
"AnalyzeFunctions", AnalyzeFunctions);
140 Options.store(Opts,
"AnalyzeVariables", AnalyzeVariables);
141 Options.store(Opts,
"AnalyzeTypes", AnalyzeTypes);
146 allOf(isFirstDecl(), isAllRedeclsInMainFile(&getHeaderFileExtensions()),
147 unless(anyOf(isInAnonymousNamespace(), isInImportableModuleUnit(),
148 hasAncestor(decl(friendDecl())))));
150 if (AnalyzeFunctions)
155 isExplicitlyExternC(), isStaticStorageClass(),
156 isExternStorageClass(), isExplicitTemplateSpecialization(),
157 cxxMethodDecl(), isConsteval(),
158 isAllocationOrDeallocationOverloadedFunction(), isMain())))
162 if (AnalyzeVariables)
164 varDecl(Common, hasGlobalStorage(),
165 unless(anyOf(isExplicitlyExternC(), isStaticStorageClass(),
166 isExternStorageClass(),
167 isExplicitTemplateSpecialization(),
168 hasThreadStorageDuration())))
172 if (getLangOpts().CPlusPlus && AnalyzeTypes)
174 tagDecl(Common, isDefinition(), hasNameForLinkage(),
175 hasDeclContext(anyOf(translationUnitDecl(), namespaceDecl())),
177 classTemplatePartialSpecializationDecl(),
178 cxxRecordDecl(anyOf(isExplicitTemplateSpecialization(),
179 isExplicitTemplateInstantiation())))))
185 "%0 %1 can be made static %select{|or moved into an anonymous namespace }2"
186 "to enforce internal linkage";
189 if (
const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>(
"fn")) {
190 const DiagnosticBuilder DB = diag(FD->getLocation(),
Message)
191 <<
"function" << FD << getLangOpts().CPlusPlus;
192 const SourceLocation FixLoc = FD->getInnerLocStart();
193 if (FixLoc.isInvalid() || FixLoc.isMacroID())
196 DB << FixItHint::CreateInsertion(FixLoc,
"static ");
199 if (
const auto *VD = Result.Nodes.getNodeAs<VarDecl>(
"var")) {
203 if (getLangOpts().CPlusPlus && VD->getType().isConstQualified())
206 const DiagnosticBuilder DB = diag(VD->getLocation(),
Message)
207 <<
"variable" << VD << getLangOpts().CPlusPlus;
208 const SourceLocation FixLoc = VD->getInnerLocStart();
209 if (FixLoc.isInvalid() || FixLoc.isMacroID())
212 DB << FixItHint::CreateInsertion(FixLoc,
"static ");
215 if (
const auto *TD = Result.Nodes.getNodeAs<TagDecl>(
"tag")) {
216 diag(TD->getLocation(),
"%0 %1 can be moved into an anonymous namespace "
217 "to enforce internal linkage")
218 << TD->getKindName() << TD;
221 llvm_unreachable(
"");
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
UseInternalLinkageCheck(StringRef Name, ClangTidyContext *Context)
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override
AST_POLYMORPHIC_MATCHER(isInAbseilFile, AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc, NestedNameSpecifierLoc))
Matches AST nodes that were found within Abseil files.
AST_MATCHER_P(Stmt, isStatementIdenticalToBoundNode, std::string, ID)
AST_MATCHER(BinaryOperator, isRelationalOperator)
static bool isInMainFile(SourceLocation L, const SourceManager &SM, const FileExtensionsSet &HeaderFileExtensions)
static constexpr StringRef Message
bool isExpansionLocInHeaderFile(SourceLocation Loc, const SourceManager &SM, const FileExtensionsSet &HeaderFileExtensions)
Checks whether expansion location of Loc is in header file.
llvm::SmallSet< llvm::StringRef, 5 > FileExtensionsSet
llvm::StringMap< ClangTidyValue > OptionMap
static llvm::ArrayRef< std::pair< misc::UseInternalLinkageCheck::FixModeKind, StringRef > > getEnumMapping()
This class should be specialized by any enum type that needs to be converted to and from an llvm::Str...