sammccall created this revision.
Herald added subscribers: usaxena95, kadircet, arphaman.
sammccall requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added projects: clang, clang-tools-extra.

This prototype is crude and breaks things (e.g. including rename).
It has this behavior for all selections and nothing else.
A real version would use it for *some* selections (not rename!) and some other
traversals too (syntax highlighting).

It does allow hover/go-to-definition to work in cases like:

  void callMeWithFoos(std::function<void(Foo)>);
  ...
  callMeWithFoos([](auto &&x) {
    x.^bar(); // will jump to Foo::bar
  });

as well as other cases handled in D119537 <https://reviews.llvm.org/D119537>


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D120131

Files:
  clang-tools-extra/clangd/FindTarget.cpp
  clang-tools-extra/clangd/Selection.cpp
  clang/include/clang/AST/RecursiveASTVisitor.h

Index: clang/include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- clang/include/clang/AST/RecursiveASTVisitor.h
+++ clang/include/clang/AST/RecursiveASTVisitor.h
@@ -94,6 +94,28 @@
       SecondMethodPtrTy>::value>::isSameMethod(FirstMethodPtr, SecondMethodPtr);
 }
 
+// Paper over API difference between Function templates and others.
+template <typename TemplatedDeclTy>
+TemplateSpecializationKind getTemplateSpecializationKind(TemplatedDeclTy *TD) {
+  return TD->getSpecializationKind();
+}
+
+inline TemplateSpecializationKind
+getTemplateSpecializationKind(FunctionDecl *FD) {
+  return FD->getTemplateSpecializationKind();
+}
+
+template <typename TemplateTy>
+auto getTemplatedDecl(TemplateTy *D, bool SingleInstantiationInstead)
+    -> decltype(D->getTemplatedDecl()) {
+  if (SingleInstantiationInstead && llvm::size(D->specializations()) == 1) {
+    auto *Candidate = *D->spec_begin();
+    if (getTemplateSpecializationKind(Candidate) != TSK_ExplicitSpecialization)
+      return Candidate;
+  }
+  return D->getTemplatedDecl();
+}
+
 } // end namespace detail
 
 /// A class that does preorder or postorder
@@ -178,6 +200,11 @@
   /// template instantiations.
   bool shouldVisitTemplateInstantiations() const { return false; }
 
+  /// When encountering a singly-instantiated template definition,
+  /// should we walk the instantiated body instead of the template body?
+  /// Ignored if shouldVisitTemplateInstantiations() is true.
+  bool shouldVisitSingleTemplateInstantiationInstead() const { return false; }
+
   /// Return whether this visitor should recurse into the types of
   /// TypeLocs.
   bool shouldWalkTypesOfTypeLocs() const { return true; }
@@ -1761,24 +1788,27 @@
 
 // This macro unifies the traversal of class, variable and function
 // template declarations.
-#define DEF_TRAVERSE_TMPL_DECL(TMPLDECLKIND)                                   \
-  DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateDecl, {                              \
-    TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));   \
-    TRY_TO(TraverseDecl(D->getTemplatedDecl()));                               \
-                                                                               \
-    /* By default, we do not traverse the instantiations of                    \
-       class templates since they do not appear in the user code. The          \
-       following code optionally traverses them.                               \
-                                                                               \
-       We only traverse the class instantiations when we see the canonical     \
-       declaration of the template, to ensure we only visit them once. */      \
-    if (getDerived().shouldVisitTemplateInstantiations() &&                    \
-        D == D->getCanonicalDecl())                                            \
-      TRY_TO(TraverseTemplateInstantiations(D));                               \
-                                                                               \
-    /* Note that getInstantiatedFromMemberTemplate() is just a link            \
-       from a template instantiation back to the template from which           \
-       it was instantiated, and thus should not be traversed. */               \
+#define DEF_TRAVERSE_TMPL_DECL(TMPLDECLKIND)                                     \
+  DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateDecl, {                                \
+    TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));     \
+    TRY_TO(TraverseDecl(detail::getTemplatedDecl(                                \
+        D,                                                                       \
+        !getDerived().shouldVisitTemplateInstantiations() &&                     \
+            getDerived().shouldVisitSingleTemplateInstantiationInstead())));     \
+                                                                                 \
+    /* By default, we do not traverse the instantiations of                      \
+       class templates since they do not appear in the user code. The            \
+       following code optionally traverses them.                                 \
+                                                                               \ \
+       We only traverse the class instantiations when we see the canonical       \
+       declaration of the template, to ensure we only visit them once. */        \
+    if (getDerived().shouldVisitTemplateInstantiations() &&                      \
+        D == D->getCanonicalDecl())                                              \
+      TRY_TO(TraverseTemplateInstantiations(D));                                 \
+                                                                                 \
+    /* Note that getInstantiatedFromMemberTemplate() is just a link              \
+       from a template instantiation back to the template from which             \
+       it was instantiated, and thus should not be traversed. */                 \
   })
 
 DEF_TRAVERSE_TMPL_DECL(Class)
@@ -2547,7 +2577,14 @@
     TRY_TO(TraverseDecl(S->getLambdaClass()));
   } else {
     // We need to poke around to find the bits that might be explicitly written.
-    TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
+    FunctionDecl *CallOperator = S->getCallOperator();
+    if (FunctionTemplateDecl *CallTemplate = S->getDependentCallOperator()) {
+      CallOperator = detail::getTemplatedDecl(
+          CallTemplate,
+          !getDerived().shouldVisitTemplateInstantiations() &&
+              getDerived().shouldVisitSingleTemplateInstantiationInstead());
+    }
+    TypeLoc TL = CallOperator->getTypeSourceInfo()->getTypeLoc();
     FunctionProtoTypeLoc Proto = TL.getAsAdjusted<FunctionProtoTypeLoc>();
 
     TRY_TO(TraverseTemplateParameterListHelper(S->getTemplateParameterList()));
@@ -2568,7 +2605,7 @@
       TRY_TO(TraverseTypeLoc(Proto.getReturnLoc()));
     TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getTrailingRequiresClause());
 
-    TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getBody());
+    TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(CallOperator->getBody());
   }
   ShouldVisitChildren = false;
 })
Index: clang-tools-extra/clangd/Selection.cpp
===================================================================
--- clang-tools-extra/clangd/Selection.cpp
+++ clang-tools-extra/clangd/Selection.cpp
@@ -605,6 +605,8 @@
 // For simple cases (not inside macros) we prune subtrees that don't intersect.
 class SelectionVisitor : public RecursiveASTVisitor<SelectionVisitor> {
 public:
+  bool shouldVisitSingleTemplateInstantiationInstead() const { return true; }
+
   // Runs the visitor to gather selected nodes and their ancestors.
   // If there is any selection, the root (TUDecl) is the first node.
   static std::deque<Node> collect(ASTContext &AST,
Index: clang-tools-extra/clangd/FindTarget.cpp
===================================================================
--- clang-tools-extra/clangd/FindTarget.cpp
+++ clang-tools-extra/clangd/FindTarget.cpp
@@ -450,6 +450,11 @@
       void VisitTemplateTypeParmType(const TemplateTypeParmType *TTPT) {
         Outer.add(TTPT->getDecl(), Flags);
       }
+      void
+      VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *STTPT) {
+        Outer.add(STTPT->getReplacedParameter()->getDecl(), Flags | Rel::Alias);
+        Outer.add(STTPT->getReplacementType(), Flags | Rel::Underlying);
+      }
       void VisitObjCInterfaceType(const ObjCInterfaceType *OIT) {
         Outer.add(OIT->getDecl(), Flags);
       }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to