diff --git a/clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.cpp b/clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.cpp index fa643a138792a..f901cd115a8ff 100644 --- a/clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.cpp +++ b/clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.cpp @@ -8,6 +8,7 @@ #include "InlineFunctionDeclCheck.h" #include "../utils/FileExtensionsUtils.h" +#include "../utils/LexerUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" @@ -17,6 +18,27 @@ using namespace clang::ast_matchers; namespace clang::tidy::llvm_libc { +namespace { + +const TemplateParameterList * +getLastTemplateParameterList(const FunctionDecl *FuncDecl) { + const TemplateParameterList *ReturnList = + FuncDecl->getDescribedTemplateParams(); + + if (!ReturnList) { + const unsigned NumberOfTemplateParameterLists = + FuncDecl->getNumTemplateParameterLists(); + + if (NumberOfTemplateParameterLists > 0) + ReturnList = FuncDecl->getTemplateParameterList( + NumberOfTemplateParameterLists - 1); + } + + return ReturnList; +} + +} // namespace + InlineFunctionDeclCheck::InlineFunctionDeclCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), @@ -34,16 +56,28 @@ void InlineFunctionDeclCheck::check(const MatchFinder::MatchResult &Result) { return; SourceLocation SrcBegin = FuncDecl->getBeginLoc(); + + // If we have a template parameter list, we need to skip that because the + // LIBC_INLINE macro must be placed after that. + if (const TemplateParameterList *TemplateParams = + getLastTemplateParameterList(FuncDecl)) { + SrcBegin = TemplateParams->getRAngleLoc(); + std::optional NextToken = + utils::lexer::findNextTokenSkippingComments( + SrcBegin, *Result.SourceManager, Result.Context->getLangOpts()); + if (NextToken) + SrcBegin = NextToken->getLocation(); + } + // Consider functions only in header files. if (!utils::isSpellingLocInHeaderFile(SrcBegin, *Result.SourceManager, HeaderFileExtensions)) return; // Ignore lambda functions as they are internal and implicit. - if (const auto *MethodDecl = dyn_cast(FuncDecl)) { + if (const auto *MethodDecl = dyn_cast(FuncDecl)) if (MethodDecl->getParent()->isLambda()) return; - } // Check if decl starts with LIBC_INLINE auto Loc = FullSourceLoc(Result.SourceManager->getFileLoc(SrcBegin), diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 32864fc13d834..7fa744d173649 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -325,6 +325,10 @@ Changes in existing checks ` check. Global options of the same name should be used instead. +- Fix false positive in :doc:`llvmlibc-inline-function-decl + ` when using templated + function with separate declarations and definitions. + - Improved the performance of the :doc:`misc-confusable-identifiers ` check through optimizations. diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvmlibc/inline-function-decl.hpp b/clang-tools-extra/test/clang-tidy/checkers/llvmlibc/inline-function-decl.hpp index 24d0441742a7f..ab4410ad4fb47 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/llvmlibc/inline-function-decl.hpp +++ b/clang-tools-extra/test/clang-tidy/checkers/llvmlibc/inline-function-decl.hpp @@ -68,6 +68,197 @@ LIBC_INLINE void lambda() { [](){}; } +namespace issue_62746 { + +void goodSimpleFunction(); +void badSimpleFunction(); +void badSimpleFunctionWrongLocation(); + +LIBC_INLINE void goodSimpleFunction() {} + +inline void badSimpleFunction() {} +// 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] + +void LIBC_INLINE badSimpleFunctionWrongLocation() {} +// 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] + +template +void goodTemplateFunction(); +template +void badTemplateFunction(); +template +void badTemplateFunctionWrongLocation(); + +template LIBC_INLINE void goodTemplateFunction() {} + +template inline void badTemplateFunction() {} +// 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] + +template void LIBC_INLINE badTemplateFunctionWrongLocation() {} +// 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] + +template +void goodVariadicFunction(); +template +void badVariadicFunction(); +template +void badVariadicFunctionWrongLocation(); + +template LIBC_INLINE void goodVariadicFunction() {} + +template inline void badVariadicFunction() {} +// 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] + +template void LIBC_INLINE badVariadicFunctionWrongLocation() {} +// 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] + +struct NoTemplate { + void goodNoTemplate(); + void badNoTemplate(); + void badNoTemplateWrongLocation(); + + template + void goodNestedTemplate(); + template + void badNestedTemplate(); + template + void badNestedTemplateWrongLocation(); + + template + void goodVariadicTemplate(); + template + void badVariadicTemplate(); + template + void badVariadicTemplateWrongLocation(); + +}; + +LIBC_INLINE void NoTemplate::goodNoTemplate() {} + +inline void NoTemplate::badNoTemplate() {} +// 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] + +void LIBC_INLINE NoTemplate::badNoTemplateWrongLocation() {} +// 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] + +template LIBC_INLINE void NoTemplate::goodNestedTemplate() {} + +template inline void NoTemplate::badNestedTemplate() {} +// 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] + +template void LIBC_INLINE NoTemplate::badNestedTemplateWrongLocation() {} +// 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] + +template LIBC_INLINE void NoTemplate::goodVariadicTemplate() {} + +template void inline NoTemplate::badVariadicTemplate() {} +// 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] + +template void LIBC_INLINE NoTemplate::badVariadicTemplateWrongLocation() {} +// 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] + +template +struct SimpleTemplate { + void goodSimpleTemplate(); + void badSimpleTemplate(); + void badSimpleTemplateWrongLocation(); + + template + void goodNestedTemplate(); + template + void badNestedTemplate(); + template + void badNestedTemplateWrongLocation(); + + template + void goodNestedVariadicTemplate(); + template + void badNestedVariadicTemplate(); + template + void badNestedVariadicTemplateWrongLocation(); +}; + +template LIBC_INLINE void SimpleTemplate::goodSimpleTemplate() {} + +template inline void SimpleTemplate::badSimpleTemplate() {} +// 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] + +template void LIBC_INLINE SimpleTemplate::badSimpleTemplateWrongLocation() {} +// 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] + +template template LIBC_INLINE void SimpleTemplate::goodNestedTemplate() {} + +template template inline void SimpleTemplate::badNestedTemplate() {} +// 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] + +template template void LIBC_INLINE SimpleTemplate::badNestedTemplateWrongLocation() {} +// 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] + +template template LIBC_INLINE void SimpleTemplate::goodNestedVariadicTemplate() {} + +template template inline void SimpleTemplate::badNestedVariadicTemplate() {} +// 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] + +template template void LIBC_INLINE SimpleTemplate::badNestedVariadicTemplateWrongLocation() {} +// 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] + +template +struct VariadicTemplate { + void goodVariadicTemplate(); + void badVariadicTemplate(); + void badVariadicTemplateWrongLocation(); + + template + void goodNestedTemplate(); + template + void badNestedTemplate(); + template + void badNestedTemplateWrongLocation(); + + template + void goodNestedVariadicTemplate(); + template + void badNestedVariadicTemplate(); + template + void badNestedVariadicTemplateWrongLocation(); +}; + +template LIBC_INLINE void VariadicTemplate::goodVariadicTemplate() {} + +template inline void VariadicTemplate::badVariadicTemplate() {} +// 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] + +template void LIBC_INLINE VariadicTemplate::badVariadicTemplateWrongLocation() {} +// 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] + +template template LIBC_INLINE void VariadicTemplate::goodNestedTemplate() {} + +template template inline void VariadicTemplate::badNestedTemplate() {} +// 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] + +template template void LIBC_INLINE VariadicTemplate::badNestedTemplateWrongLocation() {} +// 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] + +template template LIBC_INLINE void VariadicTemplate::goodNestedVariadicTemplate() {} + +template template inline void VariadicTemplate::badNestedVariadicTemplate() {} +// 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] + +template template void LIBC_INLINE VariadicTemplate::badNestedVariadicTemplateWrongLocation() {} +// 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] + +template +void goodWeirdFormatting(); +template +void badWeirdFormatting(); + +template LIBC_INLINE void goodWeirdFormatting() {} + +template void LIBC_INLINE badWeirdFormatting() {} +// 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] + +} // namespace issue_62746 + } // namespace __llvm_libc #endif // LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_LLVMLIBC_INLINEFUNCTIONDECL_H