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