-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[clang][CodeComplete] Use HeuristicResolver to resolve DependentNameTypes #123818
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-clang Author: Nathan Ridge (HighCommander4) ChangesFixes clangd/clangd#1249 Full diff: https://github.com/llvm/llvm-project/pull/123818.diff 2 Files Affected:
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 69cda6e68bd36b..d349928e1a171b 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -5736,11 +5736,20 @@ class ConceptInfo {
// In particular, when E->getType() is DependentTy, try to guess a likely type.
// We accept some lossiness (like dropping parameters).
// We only try to handle common expressions on the LHS of MemberExpr.
-QualType getApproximateType(const Expr *E) {
+QualType getApproximateType(const Expr *E, HeuristicResolver &Resolver) {
if (E->getType().isNull())
return QualType();
E = E->IgnoreParenImpCasts();
QualType Unresolved = E->getType();
+ // Resolve DependentNameType
+ if (const auto *DNT = Unresolved->getAs<DependentNameType>()) {
+ auto Decls = Resolver.resolveDependentNameType(DNT);
+ if (Decls.size() == 1) {
+ if (const auto *TD = dyn_cast<TypeDecl>(Decls[0])) {
+ return QualType(TD->getTypeForDecl(), 0);
+ }
+ }
+ }
// We only resolve DependentTy, or undeduced autos (including auto* etc).
if (!Unresolved->isSpecificBuiltinType(BuiltinType::Dependent)) {
AutoType *Auto = Unresolved->getContainedAutoType();
@@ -5749,7 +5758,7 @@ QualType getApproximateType(const Expr *E) {
}
// A call: approximate-resolve callee to a function type, get its return type
if (const CallExpr *CE = llvm::dyn_cast<CallExpr>(E)) {
- QualType Callee = getApproximateType(CE->getCallee());
+ QualType Callee = getApproximateType(CE->getCallee(), Resolver);
if (Callee.isNull() ||
Callee->isSpecificPlaceholderType(BuiltinType::BoundMember))
Callee = Expr::findBoundMemberType(CE->getCallee());
@@ -5792,7 +5801,7 @@ QualType getApproximateType(const Expr *E) {
if (const auto *CDSME = llvm::dyn_cast<CXXDependentScopeMemberExpr>(E)) {
QualType Base = CDSME->isImplicitAccess()
? CDSME->getBaseType()
- : getApproximateType(CDSME->getBase());
+ : getApproximateType(CDSME->getBase(), Resolver);
if (CDSME->isArrow() && !Base.isNull())
Base = Base->getPointeeType(); // could handle unique_ptr etc here?
auto *RD =
@@ -5813,14 +5822,15 @@ QualType getApproximateType(const Expr *E) {
if (const auto *DRE = llvm::dyn_cast<DeclRefExpr>(E)) {
if (const auto *VD = llvm::dyn_cast<VarDecl>(DRE->getDecl())) {
if (VD->hasInit())
- return getApproximateType(VD->getInit());
+ return getApproximateType(VD->getInit(), Resolver);
}
}
if (const auto *UO = llvm::dyn_cast<UnaryOperator>(E)) {
if (UO->getOpcode() == UnaryOperatorKind::UO_Deref) {
// We recurse into the subexpression because it could be of dependent
// type.
- if (auto Pointee = getApproximateType(UO->getSubExpr())->getPointeeType();
+ if (auto Pointee =
+ getApproximateType(UO->getSubExpr(), Resolver)->getPointeeType();
!Pointee.isNull())
return Pointee;
// Our caller expects a non-null result, even though the SubType is
@@ -5857,7 +5867,8 @@ void SemaCodeCompletion::CodeCompleteMemberReferenceExpr(
SemaRef.PerformMemberExprBaseConversion(Base, IsArrow);
if (ConvertedBase.isInvalid())
return;
- QualType ConvertedBaseType = getApproximateType(ConvertedBase.get());
+ QualType ConvertedBaseType =
+ getApproximateType(ConvertedBase.get(), Resolver);
enum CodeCompletionContext::Kind contextKind;
@@ -5896,7 +5907,7 @@ void SemaCodeCompletion::CodeCompleteMemberReferenceExpr(
return false;
Base = ConvertedBase.get();
- QualType BaseType = getApproximateType(Base);
+ QualType BaseType = getApproximateType(Base, Resolver);
if (BaseType.isNull())
return false;
ExprValueKind BaseKind = Base->getValueKind();
diff --git a/clang/test/CodeCompletion/member-access.cpp b/clang/test/CodeCompletion/member-access.cpp
index ab6dc69bf2923d..bf35f7ad021f71 100644
--- a/clang/test/CodeCompletion/member-access.cpp
+++ b/clang/test/CodeCompletion/member-access.cpp
@@ -401,3 +401,19 @@ struct node {
}
};
}
+
+namespace dependent_nested_class {
+template <typename T>
+struct Foo {
+ struct Bar {
+ int field;
+ };
+};
+template <typename T>
+void f() {
+ typename Foo<T>::Bar bar;
+ bar.field;
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:415:7 %s -o - | FileCheck -check-prefix=CHECK-DEPENDENT-NESTEDCLASS %s
+ // CHECK-DEPENDENT-NESTEDCLASS: [#int#]field
+}
+}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One nit, otherwise LGTM. thanks
Do we need a release note in llvm-project/clang/docs/ReleaseNotes.rst? This is an improvement on clang's code completion infra, but maybe it is not noticeable to compiler users. |
46a7cba
to
1b909be
Compare
Thanks for the reviews!
I added a generic note about using I think adding a separate note for individual changes to use |
Fixes clangd/clangd#1249