[clangd] Avoid calling resolveTypeOfCallExpr() twice in HeuristicResolver::resolveExprToType() (#164353)

Fixes the performance regression reported at
https://github.com/llvm/llvm-project/pull/156282#issuecomment-3421570600
This commit is contained in:
Nathan Ridge 2025-10-22 00:34:21 -04:00 committed by GitHub
parent 829804724b
commit 093af77ece
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 27 additions and 0 deletions

View File

@ -450,7 +450,12 @@ QualType HeuristicResolverImpl::resolveExprToType(const Expr *E) {
if (const auto *CE = dyn_cast<CallExpr>(E)) {
if (QualType Resolved = resolveTypeOfCallExpr(CE); !Resolved.isNull())
return Resolved;
// Don't proceed to try resolveExprToDecls(), it would just call
// resolveTypeOfCallExpr() again.
return E->getType();
}
// Similarly, unwrapping a unary dereference operation does not work via
// resolveExprToDecls.
if (const auto *UO = dyn_cast<UnaryOperator>(E->IgnoreParenCasts())) {

View File

@ -524,6 +524,28 @@ TEST(HeuristicResolver, MemberExpr_HangIssue126536) {
cxxDependentScopeMemberExpr(hasMemberName("foo")).bind("input"));
}
TEST(HeuristicResolver, MemberExpr_HangOnLongCallChain) {
const size_t CallChainLength = 50;
std::string Code = R"cpp(
template <typename T>
void foo(T t) {
t
)cpp";
for (size_t I = 0; I < CallChainLength; ++I)
Code.append(".method()\n");
Code.append(R"cpp(
.lastMethod();
}
)cpp");
// Test that resolution of a name whose base is a long call chain
// does not hang. Note that the hang for which this is a regression
// test is finite (exponential runtime in the length of the chain),
// so a "failure" here manifests as abnormally long runtime.
expectResolution(
Code, &HeuristicResolver::resolveMemberExpr,
cxxDependentScopeMemberExpr(hasMemberName("lastMethod")).bind("input"));
}
TEST(HeuristicResolver, MemberExpr_DefaultTemplateArgument) {
std::string Code = R"cpp(
struct Default {