Skip to content

Commit c96306d

Browse files
AMS21PiotrZSL
authored andcommitted
[clang-tidy] Fix llvmlibc-inline-function-decl false positives for templated function definitions
For a declaration the `FunctionDecl` begin location does not include the template parameter lists, but for some reason if you have a separate definitions to the declaration the begin location does include them. With this patch we now correctly handle that case. This fixes llvm#62746 Reviewed By: PiotrZSL Differential Revision: https://reviews.llvm.org/D153218
1 parent ed0620f commit c96306d

File tree

3 files changed

+231
-2
lines changed

3 files changed

+231
-2
lines changed

clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.cpp

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "InlineFunctionDeclCheck.h"
1010
#include "../utils/FileExtensionsUtils.h"
11+
#include "../utils/LexerUtils.h"
1112
#include "clang/AST/ASTContext.h"
1213
#include "clang/ASTMatchers/ASTMatchFinder.h"
1314

@@ -17,6 +18,27 @@ using namespace clang::ast_matchers;
1718

1819
namespace clang::tidy::llvm_libc {
1920

21+
namespace {
22+
23+
const TemplateParameterList *
24+
getLastTemplateParameterList(const FunctionDecl *FuncDecl) {
25+
const TemplateParameterList *ReturnList =
26+
FuncDecl->getDescribedTemplateParams();
27+
28+
if (!ReturnList) {
29+
const unsigned NumberOfTemplateParameterLists =
30+
FuncDecl->getNumTemplateParameterLists();
31+
32+
if (NumberOfTemplateParameterLists > 0)
33+
ReturnList = FuncDecl->getTemplateParameterList(
34+
NumberOfTemplateParameterLists - 1);
35+
}
36+
37+
return ReturnList;
38+
}
39+
40+
} // namespace
41+
2042
InlineFunctionDeclCheck::InlineFunctionDeclCheck(StringRef Name,
2143
ClangTidyContext *Context)
2244
: ClangTidyCheck(Name, Context),
@@ -34,16 +56,28 @@ void InlineFunctionDeclCheck::check(const MatchFinder::MatchResult &Result) {
3456
return;
3557

3658
SourceLocation SrcBegin = FuncDecl->getBeginLoc();
59+
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());
68+
if (NextToken)
69+
SrcBegin = NextToken->getLocation();
70+
}
71+
3772
// Consider functions only in header files.
3873
if (!utils::isSpellingLocInHeaderFile(SrcBegin, *Result.SourceManager,
3974
HeaderFileExtensions))
4075
return;
4176

4277
// Ignore lambda functions as they are internal and implicit.
43-
if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FuncDecl)) {
78+
if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FuncDecl))
4479
if (MethodDecl->getParent()->isLambda())
4580
return;
46-
}
4781

4882
// Check if decl starts with LIBC_INLINE
4983
auto Loc = FullSourceLoc(Result.SourceManager->getFileLoc(SrcBegin),

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,10 @@ Changes in existing checks
325325
<clang-tidy/checks/llvm/header-guard>` check.
326326
Global options of the same name should be used instead.
327327

328+
- Fix false positive in :doc:`llvmlibc-inline-function-decl
329+
<clang-tidy/checks/llvmlibc/inline-function-decl>` when using templated
330+
function with separate declarations and definitions.
331+
328332
- Improved the performance of the :doc:`misc-confusable-identifiers
329333
<clang-tidy/checks/misc/confusable-identifiers>` check through optimizations.
330334

clang-tools-extra/test/clang-tidy/checkers/llvmlibc/inline-function-decl.hpp

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,197 @@ LIBC_INLINE void lambda() {
6868
[](){};
6969
}
7070

71+
namespace issue_62746 {
72+
73+
void goodSimpleFunction();
74+
void badSimpleFunction();
75+
void badSimpleFunctionWrongLocation();
76+
77+
LIBC_INLINE void goodSimpleFunction() {}
78+
79+
inline void badSimpleFunction() {}
80+
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: 'badSimpleFunction' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
81+
82+
void LIBC_INLINE badSimpleFunctionWrongLocation() {}
83+
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: 'badSimpleFunctionWrongLocation' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
84+
85+
template <typename T>
86+
void goodTemplateFunction();
87+
template <typename T>
88+
void badTemplateFunction();
89+
template <typename T>
90+
void badTemplateFunctionWrongLocation();
91+
92+
template <typename T> LIBC_INLINE void goodTemplateFunction() {}
93+
94+
template <typename T> inline void badTemplateFunction() {}
95+
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: 'badTemplateFunction' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
96+
97+
template <typename T> void LIBC_INLINE badTemplateFunctionWrongLocation() {}
98+
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: 'badTemplateFunctionWrongLocation' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
99+
100+
template <typename... Ts>
101+
void goodVariadicFunction();
102+
template <typename... Ts>
103+
void badVariadicFunction();
104+
template <typename... Ts>
105+
void badVariadicFunctionWrongLocation();
106+
107+
template <typename... Ts> LIBC_INLINE void goodVariadicFunction() {}
108+
109+
template <typename... Ts> inline void badVariadicFunction() {}
110+
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: 'badVariadicFunction' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
111+
112+
template <typename... Ts> void LIBC_INLINE badVariadicFunctionWrongLocation() {}
113+
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: 'badVariadicFunctionWrongLocation' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
114+
115+
struct NoTemplate {
116+
void goodNoTemplate();
117+
void badNoTemplate();
118+
void badNoTemplateWrongLocation();
119+
120+
template <typename T>
121+
void goodNestedTemplate();
122+
template <typename T>
123+
void badNestedTemplate();
124+
template <typename T>
125+
void badNestedTemplateWrongLocation();
126+
127+
template <typename... Ts>
128+
void goodVariadicTemplate();
129+
template <typename... Ts>
130+
void badVariadicTemplate();
131+
template <typename... Ts>
132+
void badVariadicTemplateWrongLocation();
133+
134+
};
135+
136+
LIBC_INLINE void NoTemplate::goodNoTemplate() {}
137+
138+
inline void NoTemplate::badNoTemplate() {}
139+
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: 'badNoTemplate' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
140+
141+
void LIBC_INLINE NoTemplate::badNoTemplateWrongLocation() {}
142+
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: 'badNoTemplateWrongLocation' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
143+
144+
template <typename T> LIBC_INLINE void NoTemplate::goodNestedTemplate() {}
145+
146+
template <typename T> inline void NoTemplate::badNestedTemplate() {}
147+
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: 'badNestedTemplate' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
148+
149+
template <typename T> void LIBC_INLINE NoTemplate::badNestedTemplateWrongLocation() {}
150+
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: 'badNestedTemplateWrongLocation' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
151+
152+
template <typename... Ts> LIBC_INLINE void NoTemplate::goodVariadicTemplate() {}
153+
154+
template <typename... Ts> void inline NoTemplate::badVariadicTemplate() {}
155+
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: 'badVariadicTemplate' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
156+
157+
template <typename... Ts> void LIBC_INLINE NoTemplate::badVariadicTemplateWrongLocation() {}
158+
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: 'badVariadicTemplateWrongLocation' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
159+
160+
template <typename T>
161+
struct SimpleTemplate {
162+
void goodSimpleTemplate();
163+
void badSimpleTemplate();
164+
void badSimpleTemplateWrongLocation();
165+
166+
template <typename U>
167+
void goodNestedTemplate();
168+
template <typename U>
169+
void badNestedTemplate();
170+
template <typename U>
171+
void badNestedTemplateWrongLocation();
172+
173+
template <typename... Ts>
174+
void goodNestedVariadicTemplate();
175+
template <typename... Ts>
176+
void badNestedVariadicTemplate();
177+
template <typename... Ts>
178+
void badNestedVariadicTemplateWrongLocation();
179+
};
180+
181+
template <typename T> LIBC_INLINE void SimpleTemplate<T>::goodSimpleTemplate() {}
182+
183+
template <typename T> inline void SimpleTemplate<T>::badSimpleTemplate() {}
184+
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: 'badSimpleTemplate' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
185+
186+
template <typename T> void LIBC_INLINE SimpleTemplate<T>::badSimpleTemplateWrongLocation() {}
187+
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: 'badSimpleTemplateWrongLocation' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
188+
189+
template <typename T> template <typename U> LIBC_INLINE void SimpleTemplate<T>::goodNestedTemplate() {}
190+
191+
template <typename T> template <typename U> inline void SimpleTemplate<T>::badNestedTemplate() {}
192+
// CHECK-MESSAGES: :[[@LINE-1]]:45: warning: 'badNestedTemplate' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
193+
194+
template <typename T> template <typename U> void LIBC_INLINE SimpleTemplate<T>::badNestedTemplateWrongLocation() {}
195+
// CHECK-MESSAGES: :[[@LINE-1]]:45: warning: 'badNestedTemplateWrongLocation' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
196+
197+
template <typename T> template <typename... Ts> LIBC_INLINE void SimpleTemplate<T>::goodNestedVariadicTemplate() {}
198+
199+
template <typename T> template <typename... Ts> inline void SimpleTemplate<T>::badNestedVariadicTemplate() {}
200+
// CHECK-MESSAGES: :[[@LINE-1]]:49: warning: 'badNestedVariadicTemplate' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
201+
202+
template <typename T> template <typename... Ts> void LIBC_INLINE SimpleTemplate<T>::badNestedVariadicTemplateWrongLocation() {}
203+
// CHECK-MESSAGES: :[[@LINE-1]]:49: warning: 'badNestedVariadicTemplateWrongLocation' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
204+
205+
template <typename... Ts>
206+
struct VariadicTemplate {
207+
void goodVariadicTemplate();
208+
void badVariadicTemplate();
209+
void badVariadicTemplateWrongLocation();
210+
211+
template <typename U>
212+
void goodNestedTemplate();
213+
template <typename U>
214+
void badNestedTemplate();
215+
template <typename U>
216+
void badNestedTemplateWrongLocation();
217+
218+
template <typename... Us>
219+
void goodNestedVariadicTemplate();
220+
template <typename... Us>
221+
void badNestedVariadicTemplate();
222+
template <typename... Us>
223+
void badNestedVariadicTemplateWrongLocation();
224+
};
225+
226+
template <typename... Ts> LIBC_INLINE void VariadicTemplate<Ts...>::goodVariadicTemplate() {}
227+
228+
template <typename... Ts> inline void VariadicTemplate<Ts...>::badVariadicTemplate() {}
229+
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: 'badVariadicTemplate' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
230+
231+
template <typename... Ts> void LIBC_INLINE VariadicTemplate<Ts...>::badVariadicTemplateWrongLocation() {}
232+
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: 'badVariadicTemplateWrongLocation' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
233+
234+
template <typename... Ts> template <typename U> LIBC_INLINE void VariadicTemplate<Ts...>::goodNestedTemplate() {}
235+
236+
template <typename... Ts> template <typename U> inline void VariadicTemplate<Ts...>::badNestedTemplate() {}
237+
// CHECK-MESSAGES: :[[@LINE-1]]:49: warning: 'badNestedTemplate' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
238+
239+
template <typename... Ts> template <typename U> void LIBC_INLINE VariadicTemplate<Ts...>::badNestedTemplateWrongLocation() {}
240+
// CHECK-MESSAGES: :[[@LINE-1]]:49: warning: 'badNestedTemplateWrongLocation' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
241+
242+
template <typename... Ts> template <typename... Us> LIBC_INLINE void VariadicTemplate<Ts...>::goodNestedVariadicTemplate() {}
243+
244+
template <typename... Ts> template <typename... Us> inline void VariadicTemplate<Ts...>::badNestedVariadicTemplate() {}
245+
// CHECK-MESSAGES: :[[@LINE-1]]:53: warning: 'badNestedVariadicTemplate' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
246+
247+
template <typename... Ts> template <typename... Us> void LIBC_INLINE VariadicTemplate<Ts...>::badNestedVariadicTemplateWrongLocation() {}
248+
// CHECK-MESSAGES: :[[@LINE-1]]:53: warning: 'badNestedVariadicTemplateWrongLocation' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
249+
250+
template <typename T>
251+
void goodWeirdFormatting();
252+
template <typename T>
253+
void badWeirdFormatting();
254+
255+
template <typename T>LIBC_INLINE void goodWeirdFormatting() {}
256+
257+
template <typename T>void LIBC_INLINE badWeirdFormatting() {}
258+
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: 'badWeirdFormatting' must be tagged with the LIBC_INLINE macro; the macro should be placed at the beginning of the declaration [llvmlibc-inline-function-decl]
259+
260+
} // namespace issue_62746
261+
71262
} // namespace __llvm_libc
72263

73264
#endif // LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_LLVMLIBC_INLINEFUNCTIONDECL_H

0 commit comments

Comments
 (0)