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(),
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();
}
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;
// 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
//
//===----------------------------------------------------------------------===//
#include "InlayHints.h"
+#include "HeuristicResolver.h"
#include "ParsedAST.h"
#include "support/Logger.h"
#include "clang/AST/DeclarationName.h"
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);
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;
}
ASTContext &AST;
FileID MainFileID;
StringRef MainFileBuf;
+ const HeuristicResolver *Resolver;
};
std::vector<InlayHint> inlayHints(ParsedAST &AST) {
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) {
} // namespace
} // namespace clangd
-} // namespace clang
+} // namespace clang
\ No newline at end of file