Add basic code completion support for ObjC messages.

Still a work in progress...

llvm-svn: 86323
This commit is contained in:
Steve Naroff 2009-11-07 02:08:14 +00:00
parent 4141d8ee92
commit eae650366d
5 changed files with 175 additions and 0 deletions

View File

@ -2329,6 +2329,26 @@ public:
///
/// \param S the scope in which the operator keyword occurs.
virtual void CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS) { }
/// \brief Code completion for an ObjC factory method (from within a message
/// expression).
///
/// This code completion action is invoked when the code-completion token is
/// found after the class name.
///
/// \param S the scope in which the message expression occurs.
/// \param FName the factory name.
virtual void CodeCompleteObjCFactoryMethod(Scope *S, IdentifierInfo *FName){ }
/// \brief Code completion for an ObjC instance method (from within a message
/// expression).
///
/// This code completion action is invoked when the code-completion token is
/// found after the receiver expression.
///
/// \param S the scope in which the operator keyword occurs.
/// \param Receiver an expression for the receiver of the message.
virtual void CodeCompleteObjCInstanceMethod(Scope *S, ExprTy *Receiver) { }
//@}
};

View File

@ -1549,6 +1549,13 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
SourceLocation NameLoc,
IdentifierInfo *ReceiverName,
ExprArg ReceiverExpr) {
if (Tok.is(tok::code_completion)) {
if (ReceiverName)
Actions.CodeCompleteObjCFactoryMethod(CurScope, ReceiverName);
else
Actions.CodeCompleteObjCInstanceMethod(CurScope, ReceiverExpr.release());
ConsumeToken();
}
// Parse objc-selector
SourceLocation Loc;
IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc);

View File

@ -3764,6 +3764,8 @@ public:
virtual void CodeCompleteOperatorName(Scope *S);
virtual void CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS);
virtual void CodeCompleteObjCFactoryMethod(Scope *S, IdentifierInfo *FName);
virtual void CodeCompleteObjCInstanceMethod(Scope *S, ExprTy *Receiver);
//@}
//===--------------------------------------------------------------------===//

View File

@ -1518,3 +1518,114 @@ void Sema::CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS) {
Results.ExitScope();
HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
}
void Sema::CodeCompleteObjCFactoryMethod(Scope *S, IdentifierInfo *FName) {
typedef CodeCompleteConsumer::Result Result;
ResultBuilder Results(*this);
Results.EnterNewScope();
ObjCInterfaceDecl *CDecl = getObjCInterfaceDecl(FName);
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();
}
Results.ExitScope();
// This also suppresses remaining diagnostics.
HandleCodeCompleteResults(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 (!OCOPT)
return;
// FIXME: handle 'id', 'Class', and qualified types.
ObjCInterfaceDecl *CDecl = OCOPT->getInterfaceDecl();
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();
}
Results.ExitScope();
// This also suppresses remaining diagnostics.
HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
}

View File

@ -0,0 +1,35 @@
// Note: the run lines follow their respective tests, since line/column
// matter in this test.
@protocol FooTestProtocol
+ protocolClassMethod;
- protocolInstanceMethod;
@end
@interface Foo <FooTestProtocol> {
void *isa;
}
+ (int)classMethod1:a withKeyword:b;
+ (void)classMethod2;
+ new;
- instanceMethod1;
@end
@interface Foo (FooTestCategory)
+ categoryClassMethod;
- categoryInstanceMethod;
@end
void func() {
Foo *obj = [Foo new];
[obj xx];
}
// 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: 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
// CHECK-CC2: protocolInstanceMethod : 0