[clang-tools-extra] c96306d - [clang-tidy] Fix `llvmlibc-inline-function-decl` false positives for templated function definitions

Piotr Zegar via cfe-commits cfe-commits at lists.llvm.org
Sun Jun 18 04:41:54 PDT 2023


Author: AMS21
Date: 2023-06-18T11:40:33Z
New Revision: c96306db2cad4cf687cb044c8a0635f982a4db98

URL: https://github.com/llvm/llvm-project/commit/c96306db2cad4cf687cb044c8a0635f982a4db98
DIFF: https://github.com/llvm/llvm-project/commit/c96306db2cad4cf687cb044c8a0635f982a4db98.diff

LOG: [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

Added: 
    

Modified: 
    clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.cpp
    clang-tools-extra/docs/ReleaseNotes.rst
    clang-tools-extra/test/clang-tidy/checkers/llvmlibc/inline-function-decl.hpp

Removed: 
    


################################################################################
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<Token> 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<CXXMethodDecl>(FuncDecl)) {
+  if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(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
   <clang-tidy/checks/llvm/header-guard>` check.
   Global options of the same name should be used instead.
 
+- Fix false positive in :doc:`llvmlibc-inline-function-decl
+  <clang-tidy/checks/llvmlibc/inline-function-decl>` when using templated
+  function with separate declarations and definitions.
+
 - Improved the performance of the :doc:`misc-confusable-identifiers
   <clang-tidy/checks/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 <typename T>
+void goodTemplateFunction();
+template <typename T>
+void badTemplateFunction();
+template <typename T>
+void badTemplateFunctionWrongLocation();
+
+template <typename T> LIBC_INLINE void goodTemplateFunction() {}
+
+template <typename T> 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 <typename T> 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 <typename... Ts>
+void goodVariadicFunction();
+template <typename... Ts>
+void badVariadicFunction();
+template <typename... Ts>
+void badVariadicFunctionWrongLocation();
+
+template <typename... Ts> LIBC_INLINE void goodVariadicFunction() {}
+
+template <typename... Ts> 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 <typename... Ts> 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 <typename T>
+  void goodNestedTemplate();
+  template <typename T>
+  void badNestedTemplate();
+  template <typename T>
+  void badNestedTemplateWrongLocation();
+
+  template <typename... Ts>
+  void goodVariadicTemplate();
+  template <typename... Ts>
+  void badVariadicTemplate();
+  template <typename... Ts>
+  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 <typename T> LIBC_INLINE void NoTemplate::goodNestedTemplate() {}
+
+template <typename T> 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 <typename T> 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 <typename... Ts> LIBC_INLINE void NoTemplate::goodVariadicTemplate() {}
+
+template <typename... Ts> 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 <typename... Ts> 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 <typename T>
+struct SimpleTemplate {
+  void goodSimpleTemplate();
+  void badSimpleTemplate();
+  void badSimpleTemplateWrongLocation();
+
+  template <typename U>
+  void goodNestedTemplate();
+  template <typename U>
+  void badNestedTemplate();
+  template <typename U>
+  void badNestedTemplateWrongLocation();
+
+  template <typename... Ts>
+  void goodNestedVariadicTemplate();
+  template <typename... Ts>
+  void badNestedVariadicTemplate();
+  template <typename... Ts>
+  void badNestedVariadicTemplateWrongLocation();
+};
+
+template <typename T> LIBC_INLINE void SimpleTemplate<T>::goodSimpleTemplate() {}
+
+template <typename T> inline void SimpleTemplate<T>::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 <typename T> void LIBC_INLINE SimpleTemplate<T>::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 <typename T> template <typename U> LIBC_INLINE void SimpleTemplate<T>::goodNestedTemplate() {}
+
+template <typename T> template <typename U> inline void SimpleTemplate<T>::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 <typename T> template <typename U> void LIBC_INLINE SimpleTemplate<T>::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 <typename T> template <typename... Ts> LIBC_INLINE void SimpleTemplate<T>::goodNestedVariadicTemplate() {}
+
+template <typename T> template <typename... Ts> inline void SimpleTemplate<T>::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 <typename T> template <typename... Ts> void LIBC_INLINE SimpleTemplate<T>::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 <typename... Ts>
+struct VariadicTemplate {
+  void goodVariadicTemplate();
+  void badVariadicTemplate();
+  void badVariadicTemplateWrongLocation();
+
+  template <typename U>
+  void goodNestedTemplate();
+  template <typename U>
+  void badNestedTemplate();
+  template <typename U>
+  void badNestedTemplateWrongLocation();
+
+  template <typename... Us>
+  void goodNestedVariadicTemplate();
+  template <typename... Us>
+  void badNestedVariadicTemplate();
+  template <typename... Us>
+  void badNestedVariadicTemplateWrongLocation();
+};
+
+template <typename... Ts> LIBC_INLINE void VariadicTemplate<Ts...>::goodVariadicTemplate() {}
+
+template <typename... Ts> inline void VariadicTemplate<Ts...>::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 <typename... Ts> void LIBC_INLINE VariadicTemplate<Ts...>::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 <typename... Ts> template <typename U> LIBC_INLINE void VariadicTemplate<Ts...>::goodNestedTemplate() {}
+
+template <typename... Ts> template <typename U> inline void VariadicTemplate<Ts...>::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 <typename... Ts> template <typename U> void LIBC_INLINE VariadicTemplate<Ts...>::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 <typename... Ts> template <typename... Us> LIBC_INLINE void VariadicTemplate<Ts...>::goodNestedVariadicTemplate() {}
+
+template <typename... Ts> template <typename... Us> inline void VariadicTemplate<Ts...>::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 <typename... Ts> template <typename... Us> void LIBC_INLINE VariadicTemplate<Ts...>::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 <typename T>
+void goodWeirdFormatting();
+template <typename T>
+void badWeirdFormatting();
+
+template <typename T>LIBC_INLINE void goodWeirdFormatting() {}
+
+template <typename T>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


        


More information about the cfe-commits mailing list