mirror of
https://github.com/intel/llvm.git
synced 2026-02-03 10:39:35 +08:00
Refactor code-completion support for message sends, collecting the
code to find and add Objective-C methods (starting at an ObjCContainerDecl) into a single, static function. Also, make sure that we search into the implementations of classes and categories to find even more methods. llvm-svn: 89163
This commit is contained in:
@@ -1047,7 +1047,9 @@ namespace {
|
||||
typedef CodeCompleteConsumer::Result Result;
|
||||
|
||||
bool isEarlierDeclarationName(DeclarationName X, DeclarationName Y) const {
|
||||
if (X.getNameKind() != Y.getNameKind())
|
||||
if (!X.getObjCSelector().isNull() && !Y.getObjCSelector().isNull()) {
|
||||
// Consider all selector kinds to be equivalent.
|
||||
} else if (X.getNameKind() != Y.getNameKind())
|
||||
return X.getNameKind() < Y.getNameKind();
|
||||
|
||||
return llvm::LowercaseString(X.getAsString())
|
||||
@@ -1554,6 +1556,74 @@ void Sema::CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS) {
|
||||
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
|
||||
}
|
||||
|
||||
/// \brief Add all of the Objective-C methods in the given Objective-C
|
||||
/// container to the set of results.
|
||||
///
|
||||
/// The container will be a class, protocol, category, or implementation of
|
||||
/// any of the above. This mether will recurse to include methods from
|
||||
/// the superclasses of classes along with their categories, protocols, and
|
||||
/// implementations.
|
||||
///
|
||||
/// \param Container the container in which we'll look to find methods.
|
||||
///
|
||||
/// \param WantInstance whether to add instance methods (only); if false, this
|
||||
/// routine will add factory methods (only).
|
||||
///
|
||||
/// \param CurContext the context in which we're performing the lookup that
|
||||
/// finds methods.
|
||||
///
|
||||
/// \param Results the structure into which we'll add results.
|
||||
static void AddObjCMethods(ObjCContainerDecl *Container,
|
||||
bool WantInstanceMethods,
|
||||
DeclContext *CurContext,
|
||||
ResultBuilder &Results) {
|
||||
typedef CodeCompleteConsumer::Result Result;
|
||||
for (ObjCContainerDecl::method_iterator M = Container->meth_begin(),
|
||||
MEnd = Container->meth_end();
|
||||
M != MEnd; ++M) {
|
||||
if ((*M)->isInstanceMethod() == WantInstanceMethods)
|
||||
Results.MaybeAddResult(Result(*M, 0), CurContext);
|
||||
}
|
||||
|
||||
ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container);
|
||||
if (!IFace)
|
||||
return;
|
||||
|
||||
// Add methods in protocols.
|
||||
const ObjCList<ObjCProtocolDecl> &Protocols= IFace->getReferencedProtocols();
|
||||
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
|
||||
E = Protocols.end();
|
||||
I != E; ++I)
|
||||
AddObjCMethods(*I, WantInstanceMethods, CurContext, Results);
|
||||
|
||||
// Add methods in categories.
|
||||
for (ObjCCategoryDecl *CatDecl = IFace->getCategoryList(); CatDecl;
|
||||
CatDecl = CatDecl->getNextClassCategory()) {
|
||||
AddObjCMethods(CatDecl, WantInstanceMethods, CurContext, Results);
|
||||
|
||||
// Add a categories protocol methods.
|
||||
const ObjCList<ObjCProtocolDecl> &Protocols
|
||||
= CatDecl->getReferencedProtocols();
|
||||
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
|
||||
E = Protocols.end();
|
||||
I != E; ++I)
|
||||
AddObjCMethods(*I, WantInstanceMethods, CurContext, Results);
|
||||
|
||||
// Add methods in category implementations.
|
||||
if (ObjCCategoryImplDecl *Impl = CatDecl->getImplementation())
|
||||
AddObjCMethods(Impl, WantInstanceMethods, CurContext, Results);
|
||||
}
|
||||
|
||||
// Add methods in superclass.
|
||||
if (IFace->getSuperClass())
|
||||
AddObjCMethods(IFace->getSuperClass(), WantInstanceMethods, CurContext,
|
||||
Results);
|
||||
|
||||
// Add methods in our implementation, if any.
|
||||
if (ObjCImplementationDecl *Impl = IFace->getImplementation())
|
||||
AddObjCMethods(Impl, WantInstanceMethods, CurContext, Results);
|
||||
}
|
||||
|
||||
void Sema::CodeCompleteObjCFactoryMethod(Scope *S, IdentifierInfo *FName) {
|
||||
typedef CodeCompleteConsumer::Result Result;
|
||||
ObjCInterfaceDecl *CDecl = 0;
|
||||
@@ -1608,109 +1678,52 @@ void Sema::CodeCompleteObjCFactoryMethod(Scope *S, IdentifierInfo *FName) {
|
||||
return CodeCompleteObjCInstanceMethod(S, (Expr *)Super.get());
|
||||
}
|
||||
|
||||
// Add all of the factory methods in this Objective-C class, its protocols,
|
||||
// superclasses, categories, implementation, etc.
|
||||
ResultBuilder Results(*this);
|
||||
Results.EnterNewScope();
|
||||
|
||||
while (CDecl != NULL) {
|
||||
for (ObjCInterfaceDecl::classmeth_iterator I = CDecl->classmeth_begin(),
|
||||
E = CDecl->classmeth_end();
|
||||
I != E; ++I) {
|
||||
Results.MaybeAddResult(Result(*I, 0), CurContext);
|
||||
}
|
||||
// Add class methods in protocols.
|
||||
const ObjCList<ObjCProtocolDecl> &Protocols=CDecl->getReferencedProtocols();
|
||||
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
|
||||
E = Protocols.end(); I != E; ++I) {
|
||||
for (ObjCProtocolDecl::classmeth_iterator I2 = (*I)->classmeth_begin(),
|
||||
E2 = (*I)->classmeth_end();
|
||||
I2 != E2; ++I2) {
|
||||
Results.MaybeAddResult(Result(*I2, 0), CurContext);
|
||||
}
|
||||
}
|
||||
// Add class methods in categories.
|
||||
ObjCCategoryDecl *CatDecl = CDecl->getCategoryList();
|
||||
while (CatDecl) {
|
||||
for (ObjCCategoryDecl::classmeth_iterator I = CatDecl->classmeth_begin(),
|
||||
E = CatDecl->classmeth_end();
|
||||
I != E; ++I) {
|
||||
Results.MaybeAddResult(Result(*I, 0), CurContext);
|
||||
}
|
||||
// Add a categories protocol methods.
|
||||
const ObjCList<ObjCProtocolDecl> &Protocols =
|
||||
CatDecl->getReferencedProtocols();
|
||||
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
|
||||
E = Protocols.end(); I != E; ++I) {
|
||||
for (ObjCProtocolDecl::classmeth_iterator I2 = (*I)->classmeth_begin(),
|
||||
E2 = (*I)->classmeth_end();
|
||||
I2 != E2; ++I2) {
|
||||
Results.MaybeAddResult(Result(*I2, 0), CurContext);
|
||||
}
|
||||
}
|
||||
CatDecl = CatDecl->getNextClassCategory();
|
||||
}
|
||||
CDecl = CDecl->getSuperClass();
|
||||
}
|
||||
AddObjCMethods(CDecl, false, CurContext, Results);
|
||||
Results.ExitScope();
|
||||
|
||||
// This also suppresses remaining diagnostics.
|
||||
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
|
||||
}
|
||||
|
||||
void Sema::CodeCompleteObjCInstanceMethod(Scope *S, ExprTy *Receiver) {
|
||||
typedef CodeCompleteConsumer::Result Result;
|
||||
ResultBuilder Results(*this);
|
||||
Results.EnterNewScope();
|
||||
|
||||
Expr *RecExpr = static_cast<Expr *>(Receiver);
|
||||
QualType RecType = RecExpr->getType();
|
||||
|
||||
const ObjCObjectPointerType* OCOPT = RecType->getAs<ObjCObjectPointerType>();
|
||||
// If necessary, apply function/array conversion to the receiver.
|
||||
// C99 6.7.5.3p[7,8].
|
||||
DefaultFunctionArrayConversion(RecExpr);
|
||||
QualType ReceiverType = RecExpr->getType();
|
||||
|
||||
if (ReceiverType->isObjCIdType() || ReceiverType->isBlockPointerType()) {
|
||||
// FIXME: We're messaging 'id'. Do we actually want to look up every method
|
||||
// in the universe?
|
||||
return;
|
||||
}
|
||||
|
||||
const ObjCObjectPointerType* OCOPT
|
||||
= ReceiverType->getAs<ObjCObjectPointerType>();
|
||||
if (!OCOPT)
|
||||
return;
|
||||
|
||||
// FIXME: handle 'id', 'Class', and qualified types.
|
||||
ObjCInterfaceDecl *CDecl = OCOPT->getInterfaceDecl();
|
||||
|
||||
// Build the set of methods we can see.
|
||||
ResultBuilder Results(*this);
|
||||
Results.EnterNewScope();
|
||||
|
||||
while (CDecl != NULL) {
|
||||
for (ObjCInterfaceDecl::instmeth_iterator I = CDecl->instmeth_begin(),
|
||||
E = CDecl->instmeth_end();
|
||||
I != E; ++I) {
|
||||
Results.MaybeAddResult(Result(*I, 0), CurContext);
|
||||
}
|
||||
// Add class methods in protocols.
|
||||
const ObjCList<ObjCProtocolDecl> &Protocols=CDecl->getReferencedProtocols();
|
||||
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
|
||||
E = Protocols.end(); I != E; ++I) {
|
||||
for (ObjCProtocolDecl::instmeth_iterator I2 = (*I)->instmeth_begin(),
|
||||
E2 = (*I)->instmeth_end();
|
||||
I2 != E2; ++I2) {
|
||||
Results.MaybeAddResult(Result(*I2, 0), CurContext);
|
||||
}
|
||||
}
|
||||
// Add class methods in categories.
|
||||
ObjCCategoryDecl *CatDecl = CDecl->getCategoryList();
|
||||
while (CatDecl) {
|
||||
for (ObjCCategoryDecl::instmeth_iterator I = CatDecl->instmeth_begin(),
|
||||
E = CatDecl->instmeth_end();
|
||||
I != E; ++I) {
|
||||
Results.MaybeAddResult(Result(*I, 0), CurContext);
|
||||
}
|
||||
// Add a categories protocol methods.
|
||||
const ObjCList<ObjCProtocolDecl> &Protocols =
|
||||
CatDecl->getReferencedProtocols();
|
||||
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
|
||||
E = Protocols.end(); I != E; ++I) {
|
||||
for (ObjCProtocolDecl::instmeth_iterator I2 = (*I)->instmeth_begin(),
|
||||
E2 = (*I)->instmeth_end();
|
||||
I2 != E2; ++I2) {
|
||||
Results.MaybeAddResult(Result(*I2, 0), CurContext);
|
||||
}
|
||||
}
|
||||
CatDecl = CatDecl->getNextClassCategory();
|
||||
}
|
||||
CDecl = CDecl->getSuperClass();
|
||||
}
|
||||
ObjCInterfaceDecl *CDecl = OCOPT->getInterfaceDecl();
|
||||
if (!CDecl)
|
||||
return;
|
||||
|
||||
AddObjCMethods(CDecl, true, CurContext, Results);
|
||||
Results.ExitScope();
|
||||
|
||||
// This also suppresses remaining diagnostics.
|
||||
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
|
||||
}
|
||||
|
||||
@@ -25,10 +25,10 @@ void func() {
|
||||
}
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:23:19 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
|
||||
// CHECK-CC1: categoryClassMethod : 0
|
||||
// CHECK-CC1: classMethod1:withKeyword: : 0
|
||||
// CHECK-CC1: classMethod2 : 0
|
||||
// CHECK-CC1: new : 0
|
||||
// CHECK-CC1: protocolClassMethod : 0
|
||||
// CHECK-CC1: classMethod1:withKeyword: : 0
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:24:8 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
|
||||
// CHECK-CC2: categoryInstanceMethod : 0
|
||||
// CHECK-CC2: instanceMethod1 : 0
|
||||
|
||||
@@ -76,21 +76,21 @@ void test_super_var(MySubClass *super) {
|
||||
|
||||
// RUN: c-index-test -code-completion-at=%s:23:19 %s | FileCheck -check-prefix=CHECK-CC1 %s
|
||||
// CHECK-CC1: {TypedText categoryClassMethod}
|
||||
// CHECK-CC1: {TypedText classMethod1:}{Placeholder (id)a}{Text withKeyword:}{Placeholder (int)b}
|
||||
// CHECK-CC1: {TypedText classMethod2}
|
||||
// CHECK-CC1: {TypedText new}
|
||||
// CHECK-CC1: {TypedText protocolClassMethod}
|
||||
// CHECK-CC1: {TypedText classMethod1:}{Placeholder (id)a}{Text withKeyword:}{Placeholder (int)b}
|
||||
// RUN: c-index-test -code-completion-at=%s:24:8 %s | FileCheck -check-prefix=CHECK-CC2 %s
|
||||
// CHECK-CC2: {TypedText categoryInstanceMethod}
|
||||
// CHECK-CC2: {TypedText instanceMethod1}
|
||||
// CHECK-CC2: {TypedText protocolInstanceMethod:}{Placeholder (int)value}
|
||||
// RUN: c-index-test -code-completion-at=%s:61:16 %s | FileCheck -check-prefix=CHECK-CC3 %s
|
||||
// CHECK-CC3: ObjCClassMethodDecl:{TypedText MyClassMethod:}{Placeholder (id)obj}
|
||||
// FIXME-CC3: ObjCClassMethodDecl:{TypedText MyPrivateMethod}
|
||||
// CHECK-CC3: ObjCClassMethodDecl:{TypedText MyPrivateMethod}
|
||||
// RUN: c-index-test -code-completion-at=%s:65:16 %s | FileCheck -check-prefix=CHECK-CC4 %s
|
||||
// CHECK-CC4: ObjCInstanceMethodDecl:{TypedText MyInstMethod:}{Placeholder (id)x}{Text second:}{Placeholder (id)y}
|
||||
// FIXME-CC4: ObjCInstanceMethodDecl:{TypedText MyPrivateInstMethod}
|
||||
// CHECK-CC4: ObjCInstanceMethodDecl:{TypedText MyPrivateInstMethod}
|
||||
// RUN: c-index-test -code-completion-at=%s:74:9 %s | FileCheck -check-prefix=CHECK-CC5 %s
|
||||
// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText MySubInstMethod}
|
||||
// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText MyInstMethod:}{Placeholder (id)x}{Text second:}{Placeholder (id)y}
|
||||
// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText MySubInstMethod}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user