forked from OSchip/llvm-project
Add basic code completion support for ObjC messages.
Still a work in progress... llvm-svn: 86323
This commit is contained in:
parent
4141d8ee92
commit
eae650366d
|
@ -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) { }
|
||||
//@}
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
//@}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue