diff --git a/clang-tools-extra/clangd/HeuristicResolver.h b/clang-tools-extra/clangd/HeuristicResolver.h --- a/clang-tools-extra/clangd/HeuristicResolver.h +++ b/clang-tools-extra/clangd/HeuristicResolver.h @@ -56,6 +56,8 @@ std::vector resolveTypeOfCallExpr(const CallExpr *CE) const; std::vector + resolveCalleeOfCallExpr(const CallExpr *CE) const; + std::vector resolveUsingValueDecl(const UnresolvedUsingValueDecl *UUVD) const; std::vector resolveDependentNameType(const DependentNameType *DNT) const; @@ -87,6 +89,7 @@ // Try to heuristically resolve the type of a possibly-dependent expression // `E`. const Type *resolveExprToType(const Expr *E) const; + std::vector 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/HeuristicResolver.cpp b/clang-tools-extra/clangd/HeuristicResolver.cpp --- a/clang-tools-extra/clangd/HeuristicResolver.cpp +++ b/clang-tools-extra/clangd/HeuristicResolver.cpp @@ -130,6 +130,15 @@ return {}; } +std::vector +HeuristicResolver::resolveCalleeOfCallExpr(const CallExpr *CE) const { + if (const auto *ND = dyn_cast_or_null(CE->getCalleeDecl())) { + return {ND}; + } + + return resolveExprToDecls(CE->getCallee()); +} + std::vector HeuristicResolver::resolveUsingValueDecl( const UnresolvedUsingValueDecl *UUVD) const { return resolveDependentMember(UUVD->getQualifier()->getAsType(), @@ -163,18 +172,30 @@ return nullptr; } -const Type *HeuristicResolver::resolveExprToType(const Expr *E) const { +std::vector +HeuristicResolver::resolveExprToDecls(const Expr *E) const { if (const auto *ME = dyn_cast(E)) { - return resolveDeclsToType(resolveMemberExpr(ME)); + return resolveMemberExpr(ME); } if (const auto *RE = dyn_cast(E)) { - return resolveDeclsToType(resolveDeclRefExpr(RE)); + return resolveDeclRefExpr(RE); + } + if (const auto *OE = dyn_cast(E)) { + return {OE->decls_begin(), OE->decls_end()}; } if (const auto *CE = dyn_cast(E)) { - return resolveDeclsToType(resolveTypeOfCallExpr(CE)); + return resolveTypeOfCallExpr(CE); } if (const auto *ME = dyn_cast(E)) - return resolveDeclsToType({ME->getMemberDecl()}); + return {ME->getMemberDecl()}; + + return {}; +} + +const Type *HeuristicResolver::resolveExprToType(const Expr *E) const { + std::vector Decls = resolveExprToDecls(E); + if (!Decls.empty()) + return resolveDeclsToType(Decls); return E->getType().getTypePtr(); } diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp --- 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 @@ public: InlayHintVisitor(std::vector &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 @@ if (isa(E) || isa(E)) return true; - processCall(E->getRParenLoc(), - dyn_cast_or_null(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(CalleeDecls[0])) + Callee = FD; + else if (const auto *FTD = dyn_cast(CalleeDecls[0])) + Callee = FTD->getTemplatedDecl(); + if (!Callee) + return true; + + processCall(E->getRParenLoc(), Callee, {E->getArgs(), E->getNumArgs()}); return true; } @@ -266,6 +277,7 @@ ASTContext * FileID MainFileID; StringRef MainFileBuf; + const HeuristicResolver *Resolver; }; std::vector inlayHints(ParsedAST &AST) { diff --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp --- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp +++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp @@ -244,19 +244,35 @@ ExpectedHint{"p3: ", "p3"}); } -TEST(ParameterHints, DependentCall) { - // FIXME: This doesn't currently produce a hint but should. +TEST(ParameterHints, DependentCalls) { assertParameterHints(R"cpp( template - void foo(T param); + void nonmember(T par1); + + template + struct A { + void member(T par2); + static void static_member(T par3); + }; + + void overload(int anInt); + void overload(double aDouble); template struct S { - void bar(T par) { - foo($param[[par]]); + void bar(A a, T t) { + nonmember($par1[[t]]); + a.member($par2[[t]]); + // FIXME: This one does not work yet. + A::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 @@ } // namespace } // namespace clangd -} // namespace clang +} // namespace clang \ No newline at end of file