summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaCodeComplete.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaCodeComplete.cpp')
-rw-r--r--clang/lib/Sema/SemaCodeComplete.cpp202
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,
OpenPOWER on IntegriCloud