Skip to content

Commit ba17485

Browse files
[clang][CodeComplete] Use HeuristicResolver to resolve DependentNameTypes (#123818)
Fixes clangd/clangd#1249
1 parent c3dfd34 commit ba17485

File tree

3 files changed

+40
-7
lines changed

3 files changed

+40
-7
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,6 +1272,13 @@ libclang
12721272
- Added ``clang_getOffsetOfBase``, which allows computing the offset of a base
12731273
class in a class's layout.
12741274

1275+
1276+
Code Completion
1277+
---------------
1278+
1279+
- Use ``HeuristicResolver`` (upstreamed from clangd) to improve code completion results
1280+
in dependent code
1281+
12751282
Static Analyzer
12761283
---------------
12771284

clang/lib/Sema/SemaCodeComplete.cpp

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5736,11 +5736,19 @@ class ConceptInfo {
57365736
// In particular, when E->getType() is DependentTy, try to guess a likely type.
57375737
// We accept some lossiness (like dropping parameters).
57385738
// We only try to handle common expressions on the LHS of MemberExpr.
5739-
QualType getApproximateType(const Expr *E) {
5739+
QualType getApproximateType(const Expr *E, HeuristicResolver &Resolver) {
57405740
if (E->getType().isNull())
57415741
return QualType();
57425742
E = E->IgnoreParenImpCasts();
57435743
QualType Unresolved = E->getType();
5744+
// Resolve DependentNameType
5745+
if (const auto *DNT = Unresolved->getAs<DependentNameType>()) {
5746+
if (auto Decls = Resolver.resolveDependentNameType(DNT);
5747+
Decls.size() == 1) {
5748+
if (const auto *TD = dyn_cast<TypeDecl>(Decls[0]))
5749+
return QualType(TD->getTypeForDecl(), 0);
5750+
}
5751+
}
57445752
// We only resolve DependentTy, or undeduced autos (including auto* etc).
57455753
if (!Unresolved->isSpecificBuiltinType(BuiltinType::Dependent)) {
57465754
AutoType *Auto = Unresolved->getContainedAutoType();
@@ -5749,7 +5757,7 @@ QualType getApproximateType(const Expr *E) {
57495757
}
57505758
// A call: approximate-resolve callee to a function type, get its return type
57515759
if (const CallExpr *CE = llvm::dyn_cast<CallExpr>(E)) {
5752-
QualType Callee = getApproximateType(CE->getCallee());
5760+
QualType Callee = getApproximateType(CE->getCallee(), Resolver);
57535761
if (Callee.isNull() ||
57545762
Callee->isSpecificPlaceholderType(BuiltinType::BoundMember))
57555763
Callee = Expr::findBoundMemberType(CE->getCallee());
@@ -5792,7 +5800,7 @@ QualType getApproximateType(const Expr *E) {
57925800
if (const auto *CDSME = llvm::dyn_cast<CXXDependentScopeMemberExpr>(E)) {
57935801
QualType Base = CDSME->isImplicitAccess()
57945802
? CDSME->getBaseType()
5795-
: getApproximateType(CDSME->getBase());
5803+
: getApproximateType(CDSME->getBase(), Resolver);
57965804
if (CDSME->isArrow() && !Base.isNull())
57975805
Base = Base->getPointeeType(); // could handle unique_ptr etc here?
57985806
auto *RD =
@@ -5813,14 +5821,15 @@ QualType getApproximateType(const Expr *E) {
58135821
if (const auto *DRE = llvm::dyn_cast<DeclRefExpr>(E)) {
58145822
if (const auto *VD = llvm::dyn_cast<VarDecl>(DRE->getDecl())) {
58155823
if (VD->hasInit())
5816-
return getApproximateType(VD->getInit());
5824+
return getApproximateType(VD->getInit(), Resolver);
58175825
}
58185826
}
58195827
if (const auto *UO = llvm::dyn_cast<UnaryOperator>(E)) {
58205828
if (UO->getOpcode() == UnaryOperatorKind::UO_Deref) {
58215829
// We recurse into the subexpression because it could be of dependent
58225830
// type.
5823-
if (auto Pointee = getApproximateType(UO->getSubExpr())->getPointeeType();
5831+
if (auto Pointee =
5832+
getApproximateType(UO->getSubExpr(), Resolver)->getPointeeType();
58245833
!Pointee.isNull())
58255834
return Pointee;
58265835
// Our caller expects a non-null result, even though the SubType is
@@ -5857,7 +5866,8 @@ void SemaCodeCompletion::CodeCompleteMemberReferenceExpr(
58575866
SemaRef.PerformMemberExprBaseConversion(Base, IsArrow);
58585867
if (ConvertedBase.isInvalid())
58595868
return;
5860-
QualType ConvertedBaseType = getApproximateType(ConvertedBase.get());
5869+
QualType ConvertedBaseType =
5870+
getApproximateType(ConvertedBase.get(), Resolver);
58615871

58625872
enum CodeCompletionContext::Kind contextKind;
58635873

@@ -5896,7 +5906,7 @@ void SemaCodeCompletion::CodeCompleteMemberReferenceExpr(
58965906
return false;
58975907
Base = ConvertedBase.get();
58985908

5899-
QualType BaseType = getApproximateType(Base);
5909+
QualType BaseType = getApproximateType(Base, Resolver);
59005910
if (BaseType.isNull())
59015911
return false;
59025912
ExprValueKind BaseKind = Base->getValueKind();

clang/test/CodeCompletion/member-access.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,3 +401,19 @@ struct node {
401401
}
402402
};
403403
}
404+
405+
namespace dependent_nested_class {
406+
template <typename T>
407+
struct Foo {
408+
struct Bar {
409+
int field;
410+
};
411+
};
412+
template <typename T>
413+
void f() {
414+
typename Foo<T>::Bar bar;
415+
bar.field;
416+
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:415:7 %s -o - | FileCheck -check-prefix=CHECK-DEPENDENT-NESTEDCLASS %s
417+
// CHECK-DEPENDENT-NESTEDCLASS: [#int#]field
418+
}
419+
}

0 commit comments

Comments
 (0)