Index: lib/Sema/SemaCodeComplete.cpp =================================================================== --- lib/Sema/SemaCodeComplete.cpp +++ lib/Sema/SemaCodeComplete.cpp @@ -4037,39 +4037,33 @@ QualType ConvertedBaseType = ConvertedBase.get()->getType(); enum CodeCompletionContext::Kind contextKind; + QualType TypeWithoutPointer = ConvertedBaseType; if (IsArrow) { - if (const PointerType *Ptr = ConvertedBaseType->getAs()) - ConvertedBaseType = Ptr->getPointeeType(); + if (const PointerType *Ptr = TypeWithoutPointer->getAs()) + TypeWithoutPointer = Ptr->getPointeeType(); } if (IsArrow) { contextKind = CodeCompletionContext::CCC_ArrowMemberAccess; } else { - if (ConvertedBaseType->isObjCObjectPointerType() || - ConvertedBaseType->isObjCObjectOrInterfaceType()) { + if (TypeWithoutPointer->isObjCObjectPointerType() || + TypeWithoutPointer->isObjCObjectOrInterfaceType()) { contextKind = CodeCompletionContext::CCC_ObjCPropertyAccess; } else { contextKind = CodeCompletionContext::CCC_DotMemberAccess; } } - CodeCompletionContext CCContext(contextKind, ConvertedBaseType); + CodeCompletionContext CCContext(contextKind, TypeWithoutPointer); ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CCContext, &ResultBuilder::IsMember); - auto DoCompletion = [&](Expr *Base, bool IsArrow, Optional AccessOpFixIt) -> bool { - if (!Base) + auto DoCompletion = [&](QualType BaseType, bool IsArrow, + Optional AccessOpFixIt) -> bool { + if (BaseType.isNull()) 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()) BaseType = Ptr->getPointeeType(); @@ -4140,13 +4134,28 @@ Results.EnterNewScope(); - bool CompletionSucceded = DoCompletion(Base, IsArrow, None); + bool CompletionSucceded = DoCompletion(ConvertedBaseType, IsArrow, None); if (CodeCompleter->includeFixIts()) { - const CharSourceRange OpRange = - CharSourceRange::getTokenRange(OpLoc, OpLoc); - CompletionSucceded |= DoCompletion( - OtherOpBase, !IsArrow, - FixItHint::CreateReplacement(OpRange, IsArrow ? "." : "->")); + QualType ConvertedOtherBaseType; + if (!OtherOpBase) { + const Type *BaseTypePtr = ConvertedBaseType.getTypePtrOrNull(); + // Proceed if the initial type is pointer but IsArrow is false or the + // other way around. + if (BaseTypePtr && IsArrow != BaseTypePtr->isPointerType()) + ConvertedOtherBaseType = ConvertedBaseType; + } else { + ExprResult ConvertedOtherBase = + PerformMemberExprBaseConversion(OtherOpBase, !IsArrow); + if (!ConvertedOtherBase.isInvalid()) + ConvertedOtherBaseType = ConvertedOtherBase.get()->getType(); + } + if (!ConvertedOtherBaseType.isNull()) { + const CharSourceRange OpRange = + CharSourceRange::getTokenRange(OpLoc, OpLoc); + CompletionSucceded |= DoCompletion( + ConvertedOtherBaseType, !IsArrow, + FixItHint::CreateReplacement(OpRange, IsArrow ? "." : "->")); + } } Results.ExitScope();