1 //===-- InlineFunctionDeclCheck.cpp ---------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "InlineFunctionDeclCheck.h"
10 #include "../utils/FileExtensionsUtils.h"
11 #include "../utils/LexerUtils.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/ASTMatchers/ASTMatchFinder.h"
15 #include "llvm/ADT/StringSet.h"
17 using namespace clang::ast_matchers
;
19 namespace clang::tidy::llvm_libc
{
23 const TemplateParameterList
*
24 getLastTemplateParameterList(const FunctionDecl
*FuncDecl
) {
25 const TemplateParameterList
*ReturnList
=
26 FuncDecl
->getDescribedTemplateParams();
29 const unsigned NumberOfTemplateParameterLists
=
30 FuncDecl
->getNumTemplateParameterLists();
32 if (NumberOfTemplateParameterLists
> 0)
33 ReturnList
= FuncDecl
->getTemplateParameterList(
34 NumberOfTemplateParameterLists
- 1);
42 InlineFunctionDeclCheck::InlineFunctionDeclCheck(StringRef Name
,
43 ClangTidyContext
*Context
)
44 : ClangTidyCheck(Name
, Context
),
45 HeaderFileExtensions(Context
->getHeaderFileExtensions()) {}
47 void InlineFunctionDeclCheck::registerMatchers(MatchFinder
*Finder
) {
48 Finder
->addMatcher(decl(functionDecl()).bind("func_decl"), this);
51 void InlineFunctionDeclCheck::check(const MatchFinder::MatchResult
&Result
) {
52 const auto *FuncDecl
= Result
.Nodes
.getNodeAs
<FunctionDecl
>("func_decl");
54 // Consider only explicitly or implicitly inline functions.
55 if (FuncDecl
== nullptr || !FuncDecl
->isInlined())
58 SourceLocation SrcBegin
= FuncDecl
->getBeginLoc();
60 // If we have a template parameter list, we need to skip that because the
61 // LIBC_INLINE macro must be placed after that.
62 if (const TemplateParameterList
*TemplateParams
=
63 getLastTemplateParameterList(FuncDecl
)) {
64 SrcBegin
= TemplateParams
->getRAngleLoc();
65 std::optional
<Token
> NextToken
=
66 utils::lexer::findNextTokenSkippingComments(
67 SrcBegin
, *Result
.SourceManager
, Result
.Context
->getLangOpts());
69 SrcBegin
= NextToken
->getLocation();
72 // Consider functions only in header files.
73 if (!utils::isSpellingLocInHeaderFile(SrcBegin
, *Result
.SourceManager
,
74 HeaderFileExtensions
))
77 // Ignore lambda functions as they are internal and implicit.
78 if (const auto *MethodDecl
= dyn_cast
<CXXMethodDecl
>(FuncDecl
))
79 if (MethodDecl
->getParent()->isLambda())
82 // Check if decl starts with LIBC_INLINE
83 auto Loc
= FullSourceLoc(Result
.SourceManager
->getFileLoc(SrcBegin
),
84 *Result
.SourceManager
);
85 llvm::StringRef SrcText
= Loc
.getBufferData().drop_front(Loc
.getFileOffset());
86 if (SrcText
.starts_with("LIBC_INLINE"))
89 diag(SrcBegin
, "%0 must be tagged with the LIBC_INLINE macro; the macro "
90 "should be placed at the beginning of the declaration")
91 << FuncDecl
<< FixItHint::CreateInsertion(Loc
, "LIBC_INLINE ");
94 } // namespace clang::tidy::llvm_libc