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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits