mirror of
https://github.com/intel/llvm.git
synced 2026-01-20 01:58:44 +08:00
[clang][CodeComplete] Use HeuristicResolver to resolve DependentNameTypes (#123818)
Fixes https://github.com/clangd/clangd/issues/1249
This commit is contained in:
@@ -1272,6 +1272,13 @@ libclang
|
||||
- Added ``clang_getOffsetOfBase``, which allows computing the offset of a base
|
||||
class in a class's layout.
|
||||
|
||||
|
||||
Code Completion
|
||||
---------------
|
||||
|
||||
- Use ``HeuristicResolver`` (upstreamed from clangd) to improve code completion results
|
||||
in dependent code
|
||||
|
||||
Static Analyzer
|
||||
---------------
|
||||
|
||||
|
||||
@@ -5736,11 +5736,19 @@ private:
|
||||
// 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>()) {
|
||||
if (auto Decls = Resolver.resolveDependentNameType(DNT);
|
||||
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 +5757,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 +5800,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 +5821,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 +5866,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 +5906,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();
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user