Skip to content

Commit

Permalink
[clangd] Parameter hints for dependent calls
Browse files Browse the repository at this point in the history
Differential Revision: https://reviews.llvm.org/D100742
  • Loading branch information
HighCommander4 committed May 3, 2021
1 parent ae845d6 commit 1f8963c
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 16 deletions.
31 changes: 26 additions & 5 deletions clang-tools-extra/clangd/HeuristicResolver.cpp
Expand Up @@ -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(),
Expand Down Expand Up @@ -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();
}
Expand Down
3 changes: 3 additions & 0 deletions clang-tools-extra/clangd/HeuristicResolver.h
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
20 changes: 16 additions & 4 deletions clang-tools-extra/clangd/InlayHints.cpp
Expand Up @@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
#include "InlayHints.h"
#include "HeuristicResolver.h"
#include "ParsedAST.h"
#include "support/Logger.h"
#include "clang/AST/DeclarationName.h"
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -266,6 +277,7 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
ASTContext &AST;
FileID MainFileID;
StringRef MainFileBuf;
const HeuristicResolver *Resolver;
};

std::vector<InlayHint> inlayHints(ParsedAST &AST) {
Expand Down
30 changes: 23 additions & 7 deletions clang-tools-extra/clangd/unittests/InlayHintTests.cpp
Expand Up @@ -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) {
Expand Down Expand Up @@ -362,4 +378,4 @@ TEST(ParameterHints, SetterFunctions) {

} // namespace
} // namespace clangd
} // namespace clang
} // namespace clang

0 comments on commit 1f8963c

Please sign in to comment.