[clang-tools-extra] 1f8963c - [clangd] Parameter hints for dependent calls

Nathan Ridge via cfe-commits cfe-commits at lists.llvm.org
Sun May 2 23:03:27 PDT 2021


Author: Nathan Ridge
Date: 2021-05-03T02:03:16-04:00
New Revision: 1f8963c80195aa86d02e81acedcf1ff3da127842

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

LOG: [clangd] Parameter hints for dependent calls

Differential Revision: https://reviews.llvm.org/D100742

Added: 
    

Modified: 
    clang-tools-extra/clangd/HeuristicResolver.cpp
    clang-tools-extra/clangd/HeuristicResolver.h
    clang-tools-extra/clangd/InlayHints.cpp
    clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/HeuristicResolver.cpp b/clang-tools-extra/clangd/HeuristicResolver.cpp
index aacc90369fec5..316b7d11224b0 100644
--- a/clang-tools-extra/clangd/HeuristicResolver.cpp
+++ b/clang-tools-extra/clangd/HeuristicResolver.cpp
@@ -130,6 +130,15 @@ HeuristicResolver::resolveTypeOfCallExpr(const CallExpr *CE) const {
   return {};
 }
 
+std::vector<const NamedDecl *>
+HeuristicResolver::resolveCalleeOfCallExpr(const CallExpr *CE) const {
+  if (const auto *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {
+    return {ND};
+  }
+
+  return resolveExprToDecls(CE->getCallee());
+}
+
 std::vector<const NamedDecl *> HeuristicResolver::resolveUsingValueDecl(
     const UnresolvedUsingValueDecl *UUVD) const {
   return resolveDependentMember(UUVD->getQualifier()->getAsType(),
@@ -163,18 +172,30 @@ const Type *resolveDeclsToType(const std::vector<const NamedDecl *> &Decls) {
   return nullptr;
 }
 
-const Type *HeuristicResolver::resolveExprToType(const Expr *E) const {
+std::vector<const NamedDecl *>
+HeuristicResolver::resolveExprToDecls(const Expr *E) const {
   if (const auto *ME = dyn_cast<CXXDependentScopeMemberExpr>(E)) {
-    return resolveDeclsToType(resolveMemberExpr(ME));
+    return resolveMemberExpr(ME);
   }
   if (const auto *RE = dyn_cast<DependentScopeDeclRefExpr>(E)) {
-    return resolveDeclsToType(resolveDeclRefExpr(RE));
+    return resolveDeclRefExpr(RE);
+  }
+  if (const auto *OE = dyn_cast<OverloadExpr>(E)) {
+    return {OE->decls_begin(), OE->decls_end()};
   }
   if (const auto *CE = dyn_cast<CallExpr>(E)) {
-    return resolveDeclsToType(resolveTypeOfCallExpr(CE));
+    return resolveTypeOfCallExpr(CE);
   }
   if (const auto *ME = dyn_cast<MemberExpr>(E))
-    return resolveDeclsToType({ME->getMemberDecl()});
+    return {ME->getMemberDecl()};
+
+  return {};
+}
+
+const Type *HeuristicResolver::resolveExprToType(const Expr *E) const {
+  std::vector<const NamedDecl *> Decls = resolveExprToDecls(E);
+  if (!Decls.empty())
+    return resolveDeclsToType(Decls);
 
   return E->getType().getTypePtr();
 }

diff  --git a/clang-tools-extra/clangd/HeuristicResolver.h b/clang-tools-extra/clangd/HeuristicResolver.h
index dd906245da524..c66e1d1895699 100644
--- a/clang-tools-extra/clangd/HeuristicResolver.h
+++ b/clang-tools-extra/clangd/HeuristicResolver.h
@@ -56,6 +56,8 @@ class HeuristicResolver {
   std::vector<const NamedDecl *>
   resolveTypeOfCallExpr(const CallExpr *CE) const;
   std::vector<const NamedDecl *>
+  resolveCalleeOfCallExpr(const CallExpr *CE) const;
+  std::vector<const NamedDecl *>
   resolveUsingValueDecl(const UnresolvedUsingValueDecl *UUVD) const;
   std::vector<const NamedDecl *>
   resolveDependentNameType(const DependentNameType *DNT) const;
@@ -87,6 +89,7 @@ class HeuristicResolver {
   // Try to heuristically resolve the type of a possibly-dependent expression
   // `E`.
   const Type *resolveExprToType(const Expr *E) const;
+  std::vector<const NamedDecl *> resolveExprToDecls(const Expr *E) const;
 
   // Given the type T of a dependent expression that appears of the LHS of a
   // "->", heuristically find a corresponding pointee type in whose scope we

diff  --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp
index a9f3100a187e1..3880273f85908 100644
--- a/clang-tools-extra/clangd/InlayHints.cpp
+++ b/clang-tools-extra/clangd/InlayHints.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 #include "InlayHints.h"
+#include "HeuristicResolver.h"
 #include "ParsedAST.h"
 #include "support/Logger.h"
 #include "clang/AST/DeclarationName.h"
@@ -20,7 +21,8 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
 public:
   InlayHintVisitor(std::vector<InlayHint> &Results, ParsedAST &AST)
       : Results(Results), AST(AST.getASTContext()),
-        MainFileID(AST.getSourceManager().getMainFileID()) {
+        MainFileID(AST.getSourceManager().getMainFileID()),
+        Resolver(AST.getHeuristicResolver()) {
     bool Invalid = false;
     llvm::StringRef Buf =
         AST.getSourceManager().getBufferData(MainFileID, &Invalid);
@@ -50,9 +52,18 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
     if (isa<CXXOperatorCallExpr>(E) || isa<UserDefinedLiteral>(E))
       return true;
 
-    processCall(E->getRParenLoc(),
-                dyn_cast_or_null<FunctionDecl>(E->getCalleeDecl()),
-                {E->getArgs(), E->getNumArgs()});
+    auto CalleeDecls = Resolver->resolveCalleeOfCallExpr(E);
+    if (CalleeDecls.size() != 1)
+      return true;
+    const FunctionDecl *Callee = nullptr;
+    if (const auto *FD = dyn_cast<FunctionDecl>(CalleeDecls[0]))
+      Callee = FD;
+    else if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(CalleeDecls[0]))
+      Callee = FTD->getTemplatedDecl();
+    if (!Callee)
+      return true;
+
+    processCall(E->getRParenLoc(), Callee, {E->getArgs(), E->getNumArgs()});
     return true;
   }
 
@@ -266,6 +277,7 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
   ASTContext &AST;
   FileID MainFileID;
   StringRef MainFileBuf;
+  const HeuristicResolver *Resolver;
 };
 
 std::vector<InlayHint> inlayHints(ParsedAST &AST) {

diff  --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
index 23f0e9ef11d3e..3cf1c6d70c0d3 100644
--- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -244,19 +244,35 @@ TEST(ParameterHints, LeadingUnderscore) {
                        ExpectedHint{"p3: ", "p3"});
 }
 
-TEST(ParameterHints, DependentCall) {
-  // FIXME: This doesn't currently produce a hint but should.
+TEST(ParameterHints, DependentCalls) {
   assertParameterHints(R"cpp(
     template <typename T>
-    void foo(T param);
+    void nonmember(T par1);
+
+    template <typename T>
+    struct A {
+      void member(T par2);
+      static void static_member(T par3);
+    };
+
+    void overload(int anInt);
+    void overload(double aDouble);
 
     template <typename T>
     struct S {
-      void bar(T par) {
-        foo($param[[par]]);
+      void bar(A<T> a, T t) {
+        nonmember($par1[[t]]);
+        a.member($par2[[t]]);
+        // FIXME: This one does not work yet.
+        A<T>::static_member($par3[[t]]);
+        // We don't want to arbitrarily pick between
+        // "anInt" or "aDouble", so just show no hint.
+        overload(T{});
       }
     };
-  )cpp");
+  )cpp",
+                       ExpectedHint{"par1: ", "par1"},
+                       ExpectedHint{"par2: ", "par2"});
 }
 
 TEST(ParameterHints, VariadicFunction) {
@@ -362,4 +378,4 @@ TEST(ParameterHints, SetterFunctions) {
 
 } // namespace
 } // namespace clangd
-} // namespace clang
+} // namespace clang
\ No newline at end of file


        


More information about the cfe-commits mailing list