upsj created this revision.
upsj added a reviewer: nridge.
Herald added subscribers: usaxena95, kadircet, arphaman.
Herald added a project: All.
upsj requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.

I am working on support for forwarding parameter names in make_unique-like 
functions, first for inlay hints, later maybe for signature help.
For that to work generically, I'd like to parse all of these functions in the 
preamble. Not sure how this impacts performance on large codebases though.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D124688

Files:
  clang-tools-extra/clangd/Preamble.cpp


Index: clang-tools-extra/clangd/Preamble.cpp
===================================================================
--- clang-tools-extra/clangd/Preamble.cpp
+++ clang-tools-extra/clangd/Preamble.cpp
@@ -137,14 +137,42 @@
   }
 
   bool shouldSkipFunctionBody(Decl *D) override {
-    // Generally we skip function bodies in preambles for speed.
-    // We can make exceptions for functions that are cheap to parse and
-    // instantiate, widely used, and valuable (e.g. commonly produce errors).
-    if (const auto *FT = llvm::dyn_cast<clang::FunctionTemplateDecl>(D)) {
-      if (const auto *II = FT->getDeclName().getAsIdentifierInfo())
-        // std::make_unique is trivial, and we diagnose bad constructor calls.
-        if (II->isStr("make_unique") && FT->isInStdNamespace())
-          return false;
+    // Find functions with variadic template arguments:
+    // Any templated function...
+    if (auto *FT = llvm::dyn_cast<clang::FunctionTemplateDecl>(D)) {
+      // ... with a template parameter pack...
+      if (FT->getTemplateParameters()->hasParameterPack()) {
+        auto PackIt = std::find_if(
+            FT->getInjectedTemplateArgs().begin(),
+            FT->getInjectedTemplateArgs().end(), [](const auto &Arg) {
+              return Arg.getKind() == TemplateArgument::Pack;
+            });
+        assert(PackIt != FT->getInjectedTemplateArgs().end() &&
+               "Can't find parameter pack in argument list!");
+        const auto &Pack = PackIt->getPackAsArray();
+
+        // ... that is a type parameter pack...
+        if (Pack.size() == 1 && Pack[0].getKind() == TemplateArgument::Type) {
+          const auto *PackType =
+              Pack[0].getAsType().getNonPackExpansionType().getTypePtr();
+          const auto *FD = FT->getAsFunction();
+          const auto NumParams = FD->getNumParams();
+          if (NumParams > 0) {
+            const auto *LastParam = FD->getParamDecl(NumParams - 1);
+            // ... with its type matching the last parameter (pack) of the
+            // function (minus references)...
+            if (LastParam->isParameterPack()) {
+              if (LastParam->getType()
+                      .getNonPackExpansionType()
+                      .getNonReferenceType()
+                      .getTypePtr() == PackType) {
+                // ... we need to parse the body
+                return false;
+              }
+            }
+          }
+        }
+      }
     }
     return true;
   }


Index: clang-tools-extra/clangd/Preamble.cpp
===================================================================
--- clang-tools-extra/clangd/Preamble.cpp
+++ clang-tools-extra/clangd/Preamble.cpp
@@ -137,14 +137,42 @@
   }
 
   bool shouldSkipFunctionBody(Decl *D) override {
-    // Generally we skip function bodies in preambles for speed.
-    // We can make exceptions for functions that are cheap to parse and
-    // instantiate, widely used, and valuable (e.g. commonly produce errors).
-    if (const auto *FT = llvm::dyn_cast<clang::FunctionTemplateDecl>(D)) {
-      if (const auto *II = FT->getDeclName().getAsIdentifierInfo())
-        // std::make_unique is trivial, and we diagnose bad constructor calls.
-        if (II->isStr("make_unique") && FT->isInStdNamespace())
-          return false;
+    // Find functions with variadic template arguments:
+    // Any templated function...
+    if (auto *FT = llvm::dyn_cast<clang::FunctionTemplateDecl>(D)) {
+      // ... with a template parameter pack...
+      if (FT->getTemplateParameters()->hasParameterPack()) {
+        auto PackIt = std::find_if(
+            FT->getInjectedTemplateArgs().begin(),
+            FT->getInjectedTemplateArgs().end(), [](const auto &Arg) {
+              return Arg.getKind() == TemplateArgument::Pack;
+            });
+        assert(PackIt != FT->getInjectedTemplateArgs().end() &&
+               "Can't find parameter pack in argument list!");
+        const auto &Pack = PackIt->getPackAsArray();
+
+        // ... that is a type parameter pack...
+        if (Pack.size() == 1 && Pack[0].getKind() == TemplateArgument::Type) {
+          const auto *PackType =
+              Pack[0].getAsType().getNonPackExpansionType().getTypePtr();
+          const auto *FD = FT->getAsFunction();
+          const auto NumParams = FD->getNumParams();
+          if (NumParams > 0) {
+            const auto *LastParam = FD->getParamDecl(NumParams - 1);
+            // ... with its type matching the last parameter (pack) of the
+            // function (minus references)...
+            if (LastParam->isParameterPack()) {
+              if (LastParam->getType()
+                      .getNonPackExpansionType()
+                      .getNonReferenceType()
+                      .getTypePtr() == PackType) {
+                // ... we need to parse the body
+                return false;
+              }
+            }
+          }
+        }
+      }
     }
     return true;
   }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to