xref: /llvm-project/clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.cpp (revision c92cf315c67edaffea1c4f3a914197dce2a194f3)
1b7b28c6cSSiva Chandra Reddy //===-- InlineFunctionDeclCheck.cpp ---------------------------------------===//
2b7b28c6cSSiva Chandra Reddy //
3b7b28c6cSSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b7b28c6cSSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information.
5b7b28c6cSSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b7b28c6cSSiva Chandra Reddy //
7b7b28c6cSSiva Chandra Reddy //===----------------------------------------------------------------------===//
8b7b28c6cSSiva Chandra Reddy 
9b7b28c6cSSiva Chandra Reddy #include "InlineFunctionDeclCheck.h"
105b37cddfSCarlos Galvez #include "../utils/FileExtensionsUtils.h"
11c96306dbSAMS21 #include "../utils/LexerUtils.h"
12b7b28c6cSSiva Chandra Reddy #include "clang/AST/ASTContext.h"
13b7b28c6cSSiva Chandra Reddy #include "clang/ASTMatchers/ASTMatchFinder.h"
14b7b28c6cSSiva Chandra Reddy 
15b7b28c6cSSiva Chandra Reddy #include "llvm/ADT/StringSet.h"
16b7b28c6cSSiva Chandra Reddy 
17b7b28c6cSSiva Chandra Reddy using namespace clang::ast_matchers;
18b7b28c6cSSiva Chandra Reddy 
19b7b28c6cSSiva Chandra Reddy namespace clang::tidy::llvm_libc {
20b7b28c6cSSiva Chandra Reddy 
21c96306dbSAMS21 namespace {
22c96306dbSAMS21 
23c96306dbSAMS21 const TemplateParameterList *
getLastTemplateParameterList(const FunctionDecl * FuncDecl)24c96306dbSAMS21 getLastTemplateParameterList(const FunctionDecl *FuncDecl) {
25c96306dbSAMS21   const TemplateParameterList *ReturnList =
26c96306dbSAMS21       FuncDecl->getDescribedTemplateParams();
27c96306dbSAMS21 
28c96306dbSAMS21   if (!ReturnList) {
29c96306dbSAMS21     const unsigned NumberOfTemplateParameterLists =
30c96306dbSAMS21         FuncDecl->getNumTemplateParameterLists();
31c96306dbSAMS21 
32c96306dbSAMS21     if (NumberOfTemplateParameterLists > 0)
33c96306dbSAMS21       ReturnList = FuncDecl->getTemplateParameterList(
34c96306dbSAMS21           NumberOfTemplateParameterLists - 1);
35c96306dbSAMS21   }
36c96306dbSAMS21 
37c96306dbSAMS21   return ReturnList;
38c96306dbSAMS21 }
39c96306dbSAMS21 
40c96306dbSAMS21 } // namespace
41c96306dbSAMS21 
InlineFunctionDeclCheck(StringRef Name,ClangTidyContext * Context)42b7b28c6cSSiva Chandra Reddy InlineFunctionDeclCheck::InlineFunctionDeclCheck(StringRef Name,
43b7b28c6cSSiva Chandra Reddy                                                  ClangTidyContext *Context)
44b7b28c6cSSiva Chandra Reddy     : ClangTidyCheck(Name, Context),
455b37cddfSCarlos Galvez       HeaderFileExtensions(Context->getHeaderFileExtensions()) {}
46b7b28c6cSSiva Chandra Reddy 
registerMatchers(MatchFinder * Finder)47b7b28c6cSSiva Chandra Reddy void InlineFunctionDeclCheck::registerMatchers(MatchFinder *Finder) {
48*c92cf315Smichaelrj-google   // Ignore functions that have been deleted.
49*c92cf315Smichaelrj-google   Finder->addMatcher(decl(functionDecl(unless(isDeleted()))).bind("func_decl"),
50*c92cf315Smichaelrj-google                      this);
51b7b28c6cSSiva Chandra Reddy }
52b7b28c6cSSiva Chandra Reddy 
check(const MatchFinder::MatchResult & Result)53b7b28c6cSSiva Chandra Reddy void InlineFunctionDeclCheck::check(const MatchFinder::MatchResult &Result) {
54b7b28c6cSSiva Chandra Reddy   const auto *FuncDecl = Result.Nodes.getNodeAs<FunctionDecl>("func_decl");
55b7b28c6cSSiva Chandra Reddy 
56b7b28c6cSSiva Chandra Reddy   // Consider only explicitly or implicitly inline functions.
57b7b28c6cSSiva Chandra Reddy   if (FuncDecl == nullptr || !FuncDecl->isInlined())
58b7b28c6cSSiva Chandra Reddy     return;
59b7b28c6cSSiva Chandra Reddy 
60b7b28c6cSSiva Chandra Reddy   SourceLocation SrcBegin = FuncDecl->getBeginLoc();
61c96306dbSAMS21 
62c96306dbSAMS21   // If we have a template parameter list, we need to skip that because the
63c96306dbSAMS21   // LIBC_INLINE macro must be placed after that.
64c96306dbSAMS21   if (const TemplateParameterList *TemplateParams =
65c96306dbSAMS21           getLastTemplateParameterList(FuncDecl)) {
66c96306dbSAMS21     SrcBegin = TemplateParams->getRAngleLoc();
67c96306dbSAMS21     std::optional<Token> NextToken =
68c96306dbSAMS21         utils::lexer::findNextTokenSkippingComments(
69c96306dbSAMS21             SrcBegin, *Result.SourceManager, Result.Context->getLangOpts());
70c96306dbSAMS21     if (NextToken)
71c96306dbSAMS21       SrcBegin = NextToken->getLocation();
72c96306dbSAMS21   }
73c96306dbSAMS21 
74b7b28c6cSSiva Chandra Reddy   // Consider functions only in header files.
75b7b28c6cSSiva Chandra Reddy   if (!utils::isSpellingLocInHeaderFile(SrcBegin, *Result.SourceManager,
76b7b28c6cSSiva Chandra Reddy                                         HeaderFileExtensions))
77b7b28c6cSSiva Chandra Reddy     return;
78b7b28c6cSSiva Chandra Reddy 
791663016bSJoseph Huber   // Ignore lambda functions as they are internal and implicit.
80c96306dbSAMS21   if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FuncDecl))
811663016bSJoseph Huber     if (MethodDecl->getParent()->isLambda())
821663016bSJoseph Huber       return;
831663016bSJoseph Huber 
84b7b28c6cSSiva Chandra Reddy   // Check if decl starts with LIBC_INLINE
85b7b28c6cSSiva Chandra Reddy   auto Loc = FullSourceLoc(Result.SourceManager->getFileLoc(SrcBegin),
86b7b28c6cSSiva Chandra Reddy                            *Result.SourceManager);
87b7b28c6cSSiva Chandra Reddy   llvm::StringRef SrcText = Loc.getBufferData().drop_front(Loc.getFileOffset());
88b7b28c6cSSiva Chandra Reddy   if (SrcText.starts_with("LIBC_INLINE"))
89b7b28c6cSSiva Chandra Reddy     return;
90b7b28c6cSSiva Chandra Reddy 
91b7b28c6cSSiva Chandra Reddy   diag(SrcBegin, "%0 must be tagged with the LIBC_INLINE macro; the macro "
92b7b28c6cSSiva Chandra Reddy                  "should be placed at the beginning of the declaration")
939d4162ffSRoland McGrath       << FuncDecl << FixItHint::CreateInsertion(Loc, "LIBC_INLINE ");
94b7b28c6cSSiva Chandra Reddy }
95b7b28c6cSSiva Chandra Reddy 
96b7b28c6cSSiva Chandra Reddy } // namespace clang::tidy::llvm_libc
97