diff options
author | Steve Naroff <snaroff@apple.com> | 2009-11-07 02:08:14 +0000 |
---|---|---|
committer | Steve Naroff <snaroff@apple.com> | 2009-11-07 02:08:14 +0000 |
commit | eae650366d0bf8b14446cabb5fa0a515e22f753e (patch) | |
tree | 387dd2df34bbd23323ae80edee7893776586e09c | |
parent | 4141d8ee92dd5bc6a11317d62e21131648316f94 (diff) | |
download | bcm5719-llvm-eae650366d0bf8b14446cabb5fa0a515e22f753e.tar.gz bcm5719-llvm-eae650366d0bf8b14446cabb5fa0a515e22f753e.zip |
Add basic code completion support for ObjC messages.
Still a work in progress...
llvm-svn: 86323
-rw-r--r-- | clang/include/clang/Parse/Action.h | 20 | ||||
-rw-r--r-- | clang/lib/Parse/ParseObjc.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaCodeComplete.cpp | 111 | ||||
-rw-r--r-- | clang/test/CodeCompletion/objc-message.m | 35 |
5 files changed, 175 insertions, 0 deletions
diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index 657a14fff08..929e18ba01d 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -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) { } //@} }; diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 71aeb30927a..d06d8b6e9c7 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -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); diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index cad06d7e0a0..45d6b57437d 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -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); //@} //===--------------------------------------------------------------------===// diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 9963fc3d457..c6323956cc9 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -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()); +} diff --git a/clang/test/CodeCompletion/objc-message.m b/clang/test/CodeCompletion/objc-message.m new file mode 100644 index 00000000000..d95a36ddfa7 --- /dev/null +++ b/clang/test/CodeCompletion/objc-message.m @@ -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 |