diff options
Diffstat (limited to 'clang/lib/Sema/SemaCodeComplete.cpp')
-rw-r--r-- | clang/lib/Sema/SemaCodeComplete.cpp | 73 |
1 files changed, 71 insertions, 2 deletions
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 2f5a28e..1e4d5dd 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -5176,6 +5176,75 @@ private: llvm::DenseMap<const IdentifierInfo *, Member> Results; }; + +// Returns a type for E that yields acceptable member completions. +// 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 Unresolved = E->getType(); + if (Unresolved.isNull() || + !Unresolved->isSpecificBuiltinType(BuiltinType::Dependent)) + return Unresolved; + E = E->IgnoreParens(); + // 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()); + if (Callee.isNull() || + Callee->isSpecificPlaceholderType(BuiltinType::BoundMember)) + Callee = Expr::findBoundMemberType(CE->getCallee()); + if (Callee.isNull()) + return Unresolved; + + if (const auto *FnTypePtr = Callee->getAs<PointerType>()) { + Callee = FnTypePtr->getPointeeType(); + } else if (const auto *BPT = Callee->getAs<BlockPointerType>()) { + Callee = BPT->getPointeeType(); + } + if (const FunctionType *FnType = Callee->getAs<FunctionType>()) + return FnType->getReturnType().getNonReferenceType(); + + // Unresolved call: try to guess the return type. + if (const auto *OE = llvm::dyn_cast<OverloadExpr>(CE->getCallee())) { + // If all candidates have the same approximate return type, use it. + // Discard references and const to allow more to be "the same". + // (In particular, if there's one candidate + ADL, resolve it). + const Type *Common = nullptr; + for (const auto *D : OE->decls()) { + QualType ReturnType; + if (const auto *FD = llvm::dyn_cast<FunctionDecl>(D)) + ReturnType = FD->getReturnType(); + else if (const auto *FTD = llvm::dyn_cast<FunctionTemplateDecl>(D)) + ReturnType = FTD->getTemplatedDecl()->getReturnType(); + if (ReturnType.isNull()) + continue; + const Type *Candidate = + ReturnType.getNonReferenceType().getCanonicalType().getTypePtr(); + if (Common && Common != Candidate) + return Unresolved; // Multiple candidates. + Common = Candidate; + } + if (Common != nullptr) + return QualType(Common, 0); + } + } + // A dependent member: approximate-resolve the base, then lookup. + if (const auto *CDSME = llvm::dyn_cast<CXXDependentScopeMemberExpr>(E)) { + QualType Base = CDSME->isImplicitAccess() + ? CDSME->getBaseType() + : getApproximateType(CDSME->getBase()); + if (CDSME->isArrow() && !Base.isNull()) + Base = Base->getPointeeType(); // could handle unique_ptr etc here? + RecordDecl *RD = Base.isNull() ? nullptr : getAsRecordDecl(Base); + if (RD && RD->isCompleteDefinition()) { + for (const auto &Member : RD->lookup(CDSME->getMember())) + if (const ValueDecl *VD = llvm::dyn_cast<ValueDecl>(Member)) + return VD->getType().getNonReferenceType(); + } + } + return Unresolved; +} + } // namespace void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, @@ -5198,7 +5267,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, ExprResult ConvertedBase = PerformMemberExprBaseConversion(Base, IsArrow); if (ConvertedBase.isInvalid()) return; - QualType ConvertedBaseType = ConvertedBase.get()->getType(); + QualType ConvertedBaseType = getApproximateType(ConvertedBase.get()); enum CodeCompletionContext::Kind contextKind; @@ -5234,7 +5303,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, return false; Base = ConvertedBase.get(); - QualType BaseType = Base->getType(); + QualType BaseType = getApproximateType(Base); if (BaseType.isNull()) return false; ExprValueKind BaseKind = Base->getValueKind(); |