From: Douglas Gregor Date: Mon, 7 Dec 2009 09:51:25 +0000 (+0000) Subject: Code completion for Objective-C @ keywords that are statements or expressions X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9a0c85e640a08174569a303db22981612f05d385;p=clang Code completion for Objective-C @ keywords that are statements or expressions git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90757 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 2db254b8f5..b5d5764a63 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -2420,6 +2420,12 @@ public: virtual void CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, bool InInterface) { } + /// \brief Code completion after the '@' in a statement. + virtual void CodeCompleteObjCAtStatement(Scope *S) { } + + /// \brief Code completion after the '@' in an expression. + virtual void CodeCompleteObjCAtExpression(Scope *S) { } + /// \brief Code completion for an ObjC property decl. /// /// This code completion action is invoked when the code-completion token is diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index f1832e5707..cc5bc737a0 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -1563,7 +1563,11 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() { } Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { - if (Tok.isObjCAtKeyword(tok::objc_try)) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCAtStatement(CurScope); + ConsumeToken(); + return StmtError(); + } else if (Tok.isObjCAtKeyword(tok::objc_try)) { return ParseObjCTryStmt(AtLoc); } else if (Tok.isObjCAtKeyword(tok::objc_throw)) return ParseObjCThrowStmt(AtLoc); @@ -1584,6 +1588,11 @@ Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { switch (Tok.getKind()) { + case tok::code_completion: + Actions.CodeCompleteObjCAtExpression(CurScope); + ConsumeToken(); + return ExprError(); + case tok::string_literal: // primary-expression: string-literal case tok::wide_string_literal: return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc)); diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 806f1e94d3..4295655528 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -3780,6 +3780,8 @@ public: virtual void CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, bool InInterface); + virtual void CodeCompleteObjCAtStatement(Scope *S); + virtual void CodeCompleteObjCAtExpression(Scope *S); virtual void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS); virtual void CodeCompleteObjCPropertyGetter(Scope *S, DeclPtrTy ClassDecl, DeclPtrTy *Methods, diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 5e231a54d1..cfeefffa60 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -778,7 +778,7 @@ static unsigned CollectLookupResults(Scope *S, } /// \brief Add type specifiers for the current language as keyword results. -static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank, +static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank, ResultBuilder &Results) { typedef CodeCompleteConsumer::Result Result; Results.MaybeAddResult(Result("short", Rank)); @@ -1935,6 +1935,95 @@ void Sema::CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } +static void AddObjCExpressionResults(unsigned Rank, ResultBuilder &Results) { + typedef CodeCompleteConsumer::Result Result; + CodeCompletionString *Pattern = 0; + + // @encode ( type-name ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("encode"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("type-name"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // @protocol ( protocol-name ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("protocol"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("protocol-name"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // @selector ( selector ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("selector"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("selector"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.MaybeAddResult(Result(Pattern, Rank)); +} + +void Sema::CodeCompleteObjCAtStatement(Scope *S) { + typedef CodeCompleteConsumer::Result Result; + ResultBuilder Results(*this); + Results.EnterNewScope(); + + CodeCompletionString *Pattern = 0; + + // @try { statements } @catch ( declaration ) { statements } @finally + // { statements } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("try"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Pattern->AddTextChunk("@catch"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("parameter"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Pattern->AddTextChunk("@finally"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.MaybeAddResult(Result(Pattern, 0)); + + // @throw + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("throw"); + Pattern->AddTextChunk(" "); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddTextChunk(";"); + Results.MaybeAddResult(Result(Pattern, 0)); // FIXME: add ';' chunk + + // @synchronized ( expression ) { statements } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("synchronized"); + Pattern->AddTextChunk(" "); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.MaybeAddResult(Result(Pattern, 0)); // FIXME: add ';' chunk + + AddObjCExpressionResults(0, Results); + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + +void Sema::CodeCompleteObjCAtExpression(Scope *S) { + ResultBuilder Results(*this); + Results.EnterNewScope(); + AddObjCExpressionResults(0, Results); + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + /// \brief Determine whether the addition of the given flag to an Objective-C /// property's attributes will cause a conflict. static bool ObjCPropertyFlagConflicts(unsigned Attributes, unsigned NewFlag) { diff --git a/test/Index/complete-at-exprstmt.m b/test/Index/complete-at-exprstmt.m new file mode 100644 index 0000000000..82c3983e82 --- /dev/null +++ b/test/Index/complete-at-exprstmt.m @@ -0,0 +1,23 @@ +/* The run lines are below, because this test is line- and + column-number sensitive. */ +@interface MyClass { } +- (int)myMethod:(int)arg; +@end + +@implementation MyClass +- (int)myMethod:(int)arg { + @synchronized (@encode(MyClass)) { } +} +@end +// RUN: c-index-test -code-completion-at=%s:9:4 %s | FileCheck -check-prefix=CHECK-CC1 %s +// CHECK-CC1: {TypedText encode}{LeftParen (}{Placeholder type-name}{RightParen )} +// CHECK-CC1: {TypedText protocol}{LeftParen (}{Placeholder protocol-name}{RightParen )} +// CHECK-CC1: {TypedText selector}{LeftParen (}{Placeholder selector}{RightParen )} +// CHECK-CC1: {TypedText synchronized}{Text }{LeftParen (}{Placeholder expression}{RightParen )}{LeftBrace {}{Placeholder statements}{RightBrace }} +// CHECK-CC1: {TypedText throw}{Text }{Placeholder expression}{Text ;} +// CHECK-CC1: {TypedText try}{LeftBrace {}{Placeholder statements}{RightBrace }}{Text @catch}{LeftParen (}{Placeholder parameter}{RightParen )}{LeftBrace {}{Placeholder statements}{RightBrace }}{Text @finally}{LeftBrace {}{Placeholder statements}{RightBrace }} +// RUN: c-index-test -code-completion-at=%s:9:19 %s | FileCheck -check-prefix=CHECK-CC2 %s +// CHECK-CC2: {TypedText encode}{LeftParen (}{Placeholder type-name}{RightParen )} +// CHECK-CC2: {TypedText protocol}{LeftParen (}{Placeholder protocol-name}{RightParen )} +// CHECK-CC2: {TypedText selector}{LeftParen (}{Placeholder selector}{RightParen )} +