diff options
Diffstat (limited to 'clang/lib/Sema/SemaCodeComplete.cpp')
-rw-r--r-- | clang/lib/Sema/SemaCodeComplete.cpp | 202 |
1 files changed, 120 insertions, 82 deletions
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index f08159b79f3..5bc428a04ae 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -1291,10 +1291,13 @@ namespace { class CodeCompletionDeclConsumer : public VisibleDeclConsumer { ResultBuilder &Results; DeclContext *CurContext; + std::vector<FixItHint> FixIts; public: - CodeCompletionDeclConsumer(ResultBuilder &Results, DeclContext *CurContext) - : Results(Results), CurContext(CurContext) { } + CodeCompletionDeclConsumer( + ResultBuilder &Results, DeclContext *CurContext, + std::vector<FixItHint> FixIts = std::vector<FixItHint>()) + : Results(Results), CurContext(CurContext), FixIts(std::move(FixIts)) {} void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, bool InBaseClass) override { @@ -1303,7 +1306,7 @@ namespace { Accessible = Results.getSema().IsSimplyAccessible(ND, Ctx); ResultBuilder::Result Result(ND, Results.getBasePriority(ND), nullptr, - false, Accessible); + false, Accessible, FixIts); Results.AddResult(Result, CurContext, Hiding, InBaseClass); } @@ -3979,14 +3982,18 @@ static void AddObjCProperties( static void AddRecordMembersCompletionResults(Sema &SemaRef, ResultBuilder &Results, Scope *S, QualType BaseType, - RecordDecl *RD) { + RecordDecl *RD, + Optional<FixItHint> AccessOpFixIt) { // Indicate that we are performing a member access, and the cv-qualifiers // for the base object type. Results.setObjectTypeQualifiers(BaseType.getQualifiers()); // Access to a C/C++ class, struct, or union. Results.allowNestedNameSpecifiers(); - CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext); + std::vector<FixItHint> FixIts; + if (AccessOpFixIt) + FixIts.emplace_back(AccessOpFixIt.getValue()); + CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext, std::move(FixIts)); SemaRef.LookupVisibleDecls(RD, Sema::LookupMemberName, Consumer, SemaRef.CodeCompleter->includeGlobals(), /*IncludeDependentBases=*/true, @@ -4013,107 +4020,138 @@ static void AddRecordMembersCompletionResults(Sema &SemaRef, } void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, + Expr *OtherOpBase, SourceLocation OpLoc, bool IsArrow, bool IsBaseExprStatement) { if (!Base || !CodeCompleter) return; - + ExprResult ConvertedBase = PerformMemberExprBaseConversion(Base, IsArrow); if (ConvertedBase.isInvalid()) return; - Base = ConvertedBase.get(); - - QualType BaseType = Base->getType(); + QualType ConvertedBaseType = ConvertedBase.get()->getType(); + + enum CodeCompletionContext::Kind contextKind; if (IsArrow) { - if (const PointerType *Ptr = BaseType->getAs<PointerType>()) - BaseType = Ptr->getPointeeType(); - else if (BaseType->isObjCObjectPointerType()) - /*Do nothing*/ ; - else - return; + if (const PointerType *Ptr = ConvertedBaseType->getAs<PointerType>()) + ConvertedBaseType = Ptr->getPointeeType(); } - - enum CodeCompletionContext::Kind contextKind; - + if (IsArrow) { contextKind = CodeCompletionContext::CCC_ArrowMemberAccess; - } - else { - if (BaseType->isObjCObjectPointerType() || - BaseType->isObjCObjectOrInterfaceType()) { + } else { + if (ConvertedBaseType->isObjCObjectPointerType() || + ConvertedBaseType->isObjCObjectOrInterfaceType()) { contextKind = CodeCompletionContext::CCC_ObjCPropertyAccess; - } - else { + } else { contextKind = CodeCompletionContext::CCC_DotMemberAccess; } } - CodeCompletionContext CCContext(contextKind, BaseType); + CodeCompletionContext CCContext(contextKind, ConvertedBaseType); ResultBuilder Results(*this, CodeCompleter->getAllocator(), - CodeCompleter->getCodeCompletionTUInfo(), - CCContext, + CodeCompleter->getCodeCompletionTUInfo(), CCContext, &ResultBuilder::IsMember); - Results.EnterNewScope(); - if (const RecordType *Record = BaseType->getAs<RecordType>()) { - AddRecordMembersCompletionResults(*this, Results, S, BaseType, - Record->getDecl()); - } else if (const auto *TST = BaseType->getAs<TemplateSpecializationType>()) { - TemplateName TN = TST->getTemplateName(); - if (const auto *TD = - dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl())) { - CXXRecordDecl *RD = TD->getTemplatedDecl(); - AddRecordMembersCompletionResults(*this, Results, S, BaseType, RD); - } - } else if (const auto *ICNT = BaseType->getAs<InjectedClassNameType>()) { - if (auto *RD = ICNT->getDecl()) - AddRecordMembersCompletionResults(*this, Results, S, BaseType, RD); - } else if (!IsArrow && BaseType->isObjCObjectPointerType()) { - // Objective-C property reference. - AddedPropertiesSet AddedProperties; - - if (const ObjCObjectPointerType *ObjCPtr = - BaseType->getAsObjCInterfacePointerType()) { - // Add property results based on our interface. - assert(ObjCPtr && "Non-NULL pointer guaranteed above!"); - AddObjCProperties(CCContext, ObjCPtr->getInterfaceDecl(), true, - /*AllowNullaryMethods=*/true, CurContext, - AddedProperties, Results, IsBaseExprStatement); - } - - // Add properties from the protocols in a qualified interface. - for (auto *I : BaseType->getAs<ObjCObjectPointerType>()->quals()) - AddObjCProperties(CCContext, I, true, /*AllowNullaryMethods=*/true, - CurContext, AddedProperties, Results, - IsBaseExprStatement); - } else if ((IsArrow && BaseType->isObjCObjectPointerType()) || - (!IsArrow && BaseType->isObjCObjectType())) { - // Objective-C instance variable access. - ObjCInterfaceDecl *Class = nullptr; - if (const ObjCObjectPointerType *ObjCPtr - = BaseType->getAs<ObjCObjectPointerType>()) - Class = ObjCPtr->getInterfaceDecl(); - else - Class = BaseType->getAs<ObjCObjectType>()->getInterface(); - - // Add all ivars from this class and its superclasses. - if (Class) { - CodeCompletionDeclConsumer Consumer(Results, CurContext); - Results.setFilter(&ResultBuilder::IsObjCIvar); - LookupVisibleDecls( - Class, LookupMemberName, Consumer, CodeCompleter->includeGlobals(), - /*IncludeDependentBases=*/false, CodeCompleter->loadExternal()); + + auto DoCompletion = [&](Expr *Base, bool IsArrow, Optional<FixItHint> AccessOpFixIt) -> bool { + if (!Base) + return false; + + ExprResult ConvertedBase = PerformMemberExprBaseConversion(Base, IsArrow); + if (ConvertedBase.isInvalid()) + return false; + Base = ConvertedBase.get(); + + QualType BaseType = Base->getType(); + + if (IsArrow) { + if (const PointerType *Ptr = BaseType->getAs<PointerType>()) + BaseType = Ptr->getPointeeType(); + else if (BaseType->isObjCObjectPointerType()) + /*Do nothing*/; + else + return false; + } + + if (const RecordType *Record = BaseType->getAs<RecordType>()) { + AddRecordMembersCompletionResults(*this, Results, S, BaseType, + Record->getDecl(), + std::move(AccessOpFixIt)); + } else if (const auto *TST = + BaseType->getAs<TemplateSpecializationType>()) { + TemplateName TN = TST->getTemplateName(); + if (const auto *TD = + dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl())) { + CXXRecordDecl *RD = TD->getTemplatedDecl(); + AddRecordMembersCompletionResults(*this, Results, S, BaseType, RD, + std::move(AccessOpFixIt)); + } + } else if (const auto *ICNT = BaseType->getAs<InjectedClassNameType>()) { + if (auto *RD = ICNT->getDecl()) + AddRecordMembersCompletionResults(*this, Results, S, BaseType, RD, + std::move(AccessOpFixIt)); + } else if (!IsArrow && BaseType->isObjCObjectPointerType()) { + // Objective-C property reference. + AddedPropertiesSet AddedProperties; + + if (const ObjCObjectPointerType *ObjCPtr = + BaseType->getAsObjCInterfacePointerType()) { + // Add property results based on our interface. + assert(ObjCPtr && "Non-NULL pointer guaranteed above!"); + AddObjCProperties(CCContext, ObjCPtr->getInterfaceDecl(), true, + /*AllowNullaryMethods=*/true, CurContext, + AddedProperties, Results, IsBaseExprStatement); + } + + // Add properties from the protocols in a qualified interface. + for (auto *I : BaseType->getAs<ObjCObjectPointerType>()->quals()) + AddObjCProperties(CCContext, I, true, /*AllowNullaryMethods=*/true, + CurContext, AddedProperties, Results, + IsBaseExprStatement); + } else if ((IsArrow && BaseType->isObjCObjectPointerType()) || + (!IsArrow && BaseType->isObjCObjectType())) { + // Objective-C instance variable access. + ObjCInterfaceDecl *Class = nullptr; + if (const ObjCObjectPointerType *ObjCPtr = + BaseType->getAs<ObjCObjectPointerType>()) + Class = ObjCPtr->getInterfaceDecl(); + else + Class = BaseType->getAs<ObjCObjectType>()->getInterface(); + + // Add all ivars from this class and its superclasses. + if (Class) { + CodeCompletionDeclConsumer Consumer(Results, CurContext); + Results.setFilter(&ResultBuilder::IsObjCIvar); + LookupVisibleDecls( + Class, LookupMemberName, Consumer, CodeCompleter->includeGlobals(), + /*IncludeDependentBases=*/false, CodeCompleter->loadExternal()); + } } + + // FIXME: How do we cope with isa? + return true; + }; + + Results.EnterNewScope(); + + bool CompletionSucceded = DoCompletion(Base, IsArrow, None); + if (CodeCompleter->includeFixIts()) { + const CharSourceRange OpRange = + CharSourceRange::getTokenRange(OpLoc, OpLoc); + CompletionSucceded |= DoCompletion( + OtherOpBase, !IsArrow, + FixItHint::CreateReplacement(OpRange, IsArrow ? "." : "->")); } - - // FIXME: How do we cope with isa? - + Results.ExitScope(); + if (!CompletionSucceded) + return; + // Hand off the results found for code completion. - HandleCodeCompleteResults(this, CodeCompleter, - Results.getCompletionContext(), - Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } void Sema::CodeCompleteObjCClassPropertyRefExpr(Scope *S, |