xref: /llvm-project/clang-tools-extra/clang-tidy/llvmlibc/CalleeNamespaceCheck.cpp (revision a074f8869563cb5b296732e0e8af46dcdc286ae5)
18683f5deSPaula Toth //===-- CalleeNamespaceCheck.cpp ------------------------------------------===//
28683f5deSPaula Toth //
38683f5deSPaula Toth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
48683f5deSPaula Toth // See https://llvm.org/LICENSE.txt for license information.
58683f5deSPaula Toth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68683f5deSPaula Toth //
78683f5deSPaula Toth //===----------------------------------------------------------------------===//
88683f5deSPaula Toth 
98683f5deSPaula Toth #include "CalleeNamespaceCheck.h"
10daca9721Smichaelrj-google #include "NamespaceConstants.h"
118683f5deSPaula Toth #include "clang/AST/ASTContext.h"
128683f5deSPaula Toth #include "clang/ASTMatchers/ASTMatchFinder.h"
138683f5deSPaula Toth 
14daca9721Smichaelrj-google #include "clang/ASTMatchers/ASTMatchers.h"
15155f5a6dSMichael Jones #include "llvm/ADT/StringSet.h"
16155f5a6dSMichael Jones 
178683f5deSPaula Toth using namespace clang::ast_matchers;
188683f5deSPaula Toth 
197d2ea6c4SCarlos Galvez namespace clang::tidy::llvm_libc {
208683f5deSPaula Toth 
218683f5deSPaula Toth // Gets the outermost namespace of a DeclContext, right under the Translation
228683f5deSPaula Toth // Unit.
238683f5deSPaula Toth const DeclContext *getOutermostNamespace(const DeclContext *Decl) {
248683f5deSPaula Toth   const DeclContext *Parent = Decl->getParent();
25003e0382SSimon Pilgrim   if (Parent->isTranslationUnit())
268683f5deSPaula Toth     return Decl;
278683f5deSPaula Toth   return getOutermostNamespace(Parent);
288683f5deSPaula Toth }
298683f5deSPaula Toth 
308683f5deSPaula Toth void CalleeNamespaceCheck::registerMatchers(MatchFinder *Finder) {
318683f5deSPaula Toth   Finder->addMatcher(
328683f5deSPaula Toth       declRefExpr(to(functionDecl().bind("func"))).bind("use-site"), this);
338683f5deSPaula Toth }
348683f5deSPaula Toth 
35155f5a6dSMichael Jones // A list of functions that are exempted from this check. The __errno_location
36155f5a6dSMichael Jones // function is for setting errno, which is allowed in libc, and the other
37155f5a6dSMichael Jones // functions are specifically allowed to be external so that they can be
38155f5a6dSMichael Jones // intercepted.
39155f5a6dSMichael Jones static const llvm::StringSet<> IgnoredFunctions = {
40155f5a6dSMichael Jones     "__errno_location", "malloc", "calloc", "realloc", "free", "aligned_alloc"};
41155f5a6dSMichael Jones 
428683f5deSPaula Toth void CalleeNamespaceCheck::check(const MatchFinder::MatchResult &Result) {
438683f5deSPaula Toth   const auto *UsageSiteExpr = Result.Nodes.getNodeAs<DeclRefExpr>("use-site");
448683f5deSPaula Toth   const auto *FuncDecl = Result.Nodes.getNodeAs<FunctionDecl>("func");
458683f5deSPaula Toth 
468683f5deSPaula Toth   // Ignore compiler builtin functions.
478683f5deSPaula Toth   if (FuncDecl->getBuiltinID() != 0)
488683f5deSPaula Toth     return;
498683f5deSPaula Toth 
50daca9721Smichaelrj-google   // If the outermost namespace of the function is a macro that starts with
51daca9721Smichaelrj-google   // __llvm_libc, we're good.
528683f5deSPaula Toth   const auto *NS = dyn_cast<NamespaceDecl>(getOutermostNamespace(FuncDecl));
53daca9721Smichaelrj-google   if (NS && Result.SourceManager->isMacroBodyExpansion(NS->getLocation()) &&
54*a074f886SPaul Kirth       NS->getName().starts_with(RequiredNamespaceRefStart))
558683f5deSPaula Toth     return;
568683f5deSPaula Toth 
57f4834815SWhisperity   const DeclarationName &Name = FuncDecl->getDeclName();
58f4834815SWhisperity   if (Name.isIdentifier() &&
59f4834815SWhisperity       IgnoredFunctions.contains(Name.getAsIdentifierInfo()->getName()))
60155f5a6dSMichael Jones     return;
61155f5a6dSMichael Jones 
62daca9721Smichaelrj-google   diag(UsageSiteExpr->getBeginLoc(),
63daca9721Smichaelrj-google        "%0 must resolve to a function declared "
64daca9721Smichaelrj-google        "within the namespace defined by the '%1' macro")
65*a074f886SPaul Kirth       << FuncDecl << RequiredNamespaceRefMacroName;
668683f5deSPaula Toth 
678683f5deSPaula Toth   diag(FuncDecl->getLocation(), "resolves to this declaration",
688683f5deSPaula Toth        clang::DiagnosticIDs::Note);
698683f5deSPaula Toth }
708683f5deSPaula Toth 
717d2ea6c4SCarlos Galvez } // namespace clang::tidy::llvm_libc
72