diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-11-18 01:29:26 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-11-18 01:29:26 +0000 |
commit | 95ac6556a5dfc504491103c37f9aa05b303d2729 (patch) | |
tree | 08e817bd4c6cdb7a5d97db9037929918df5308f8 /lib/Sema/SemaCodeComplete.cpp | |
parent | a14cd1111f5daf6891be4f3c9e534a75b5ce6294 (diff) |
Code completion for member accesses that involve Objective-C properties and instance variables
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89182 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaCodeComplete.cpp')
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 134 |
1 files changed, 107 insertions, 27 deletions
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index e9b00e0361..ebd860b692 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -1128,6 +1128,49 @@ void Sema::CodeCompleteOrdinaryName(Scope *S) { HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } +static void AddObjCProperties(ObjCContainerDecl *Container, + DeclContext *CurContext, + ResultBuilder &Results) { + typedef CodeCompleteConsumer::Result Result; + + // Add properties in this container. + for (ObjCContainerDecl::prop_iterator P = Container->prop_begin(), + PEnd = Container->prop_end(); + P != PEnd; + ++P) + Results.MaybeAddResult(Result(*P, 0), CurContext); + + // Add properties in referenced protocols. + if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) { + for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(), + PEnd = Protocol->protocol_end(); + P != PEnd; ++P) + AddObjCProperties(*P, CurContext, Results); + } else if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)){ + // Look through categories. + for (ObjCCategoryDecl *Category = IFace->getCategoryList(); + Category; Category = Category->getNextClassCategory()) + AddObjCProperties(Category, CurContext, Results); + + // Look through protocols. + for (ObjCInterfaceDecl::protocol_iterator I = IFace->protocol_begin(), + E = IFace->protocol_end(); + I != E; ++I) + AddObjCProperties(*I, CurContext, Results); + + // Look in the superclass. + if (IFace->getSuperClass()) + AddObjCProperties(IFace->getSuperClass(), CurContext, Results); + } else if (const ObjCCategoryDecl *Category + = dyn_cast<ObjCCategoryDecl>(Container)) { + // Look through protocols. + for (ObjCInterfaceDecl::protocol_iterator P = Category->protocol_begin(), + PEnd = Category->protocol_end(); + P != PEnd; ++P) + AddObjCProperties(*P, CurContext, Results); + } +} + void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, SourceLocation OpLoc, bool IsArrow) { @@ -1151,38 +1194,75 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, ResultBuilder Results(*this, &ResultBuilder::IsMember); unsigned NextRank = 0; - // If this isn't a record type, we are done. - const RecordType *Record = BaseType->getAs<RecordType>(); - if (!Record) - return; - - NextRank = CollectMemberLookupResults(Record->getDecl(), NextRank, - Record->getDecl(), Results); + Results.EnterNewScope(); + if (const RecordType *Record = BaseType->getAs<RecordType>()) { + // Access to a C/C++ class, struct, or union. + NextRank = CollectMemberLookupResults(Record->getDecl(), NextRank, + Record->getDecl(), Results); + + if (getLangOptions().CPlusPlus) { + if (!Results.empty()) { + // The "template" keyword can follow "->" or "." in the grammar. + // However, we only want to suggest the template keyword if something + // is dependent. + bool IsDependent = BaseType->isDependentType(); + if (!IsDependent) { + for (Scope *DepScope = S; DepScope; DepScope = DepScope->getParent()) + if (DeclContext *Ctx = (DeclContext *)DepScope->getEntity()) { + IsDependent = Ctx->isDependentContext(); + break; + } + } - if (getLangOptions().CPlusPlus) { - if (!Results.empty()) { - // The "template" keyword can follow "->" or "." in the grammar. - // However, we only want to suggest the template keyword if something - // is dependent. - bool IsDependent = BaseType->isDependentType(); - if (!IsDependent) { - for (Scope *DepScope = S; DepScope; DepScope = DepScope->getParent()) - if (DeclContext *Ctx = (DeclContext *)DepScope->getEntity()) { - IsDependent = Ctx->isDependentContext(); - break; - } + if (IsDependent) + Results.MaybeAddResult(Result("template", NextRank++)); } - if (IsDependent) - Results.MaybeAddResult(Result("template", NextRank++)); + // We could have the start of a nested-name-specifier. Add those + // results as well. + Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); + CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank, + CurContext, Results); + } + } else if (!IsArrow && BaseType->getAsObjCInterfacePointerType()) { + // Objective-C property reference. + + // Add property results based on our interface. + const ObjCObjectPointerType *ObjCPtr + = BaseType->getAsObjCInterfacePointerType(); + assert(ObjCPtr && "Non-NULL pointer guaranteed above!"); + AddObjCProperties(ObjCPtr->getInterfaceDecl(), CurContext, Results); + + // Add properties from the protocols in a qualified interface. + for (ObjCObjectPointerType::qual_iterator I = ObjCPtr->qual_begin(), + E = ObjCPtr->qual_end(); + I != E; ++I) + AddObjCProperties(*I, CurContext, Results); + + // FIXME: We could (should?) also look for "implicit" properties, identified + // only by the presence of nullary and unary selectors. + } else if ((IsArrow && BaseType->isObjCObjectPointerType()) || + (!IsArrow && BaseType->isObjCInterfaceType())) { + // Objective-C instance variable access. + ObjCInterfaceDecl *Class = 0; + if (const ObjCObjectPointerType *ObjCPtr + = BaseType->getAs<ObjCObjectPointerType>()) + Class = ObjCPtr->getInterfaceDecl(); + else + Class = BaseType->getAs<ObjCInterfaceType>()->getDecl(); + + // Add all ivars from this class and its superclasses. + for (; Class; Class = Class->getSuperClass()) { + for (ObjCInterfaceDecl::ivar_iterator IVar = Class->ivar_begin(), + IVarEnd = Class->ivar_end(); + IVar != IVarEnd; ++IVar) + Results.MaybeAddResult(Result(*IVar, 0), CurContext); } - - // We could have the start of a nested-name-specifier. Add those - // results as well. - Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); - CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank, - CurContext, Results); } + + // FIXME: How do we cope with isa? + + Results.ExitScope(); // Add macros if (CodeCompleter->includeMacros()) |