From: Douglas Gregor Date: Tue, 24 Aug 2010 01:06:58 +0000 (+0000) Subject: Provide code completion results for the context-sensitive Objective-C X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d32b0225e29fcafb2b2b2a4b1c51dcb1518af9c6;p=clang Provide code completion results for the context-sensitive Objective-C keywords "in", "out", "inout", "byref", "bycopy", and "oneway". git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111884 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 6e537989bb..7aa08126df 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -908,7 +908,7 @@ private: bool isTokIdentifier_in() const; - TypeTy *ParseObjCTypeName(ObjCDeclSpec &DS); + TypeTy *ParseObjCTypeName(ObjCDeclSpec &DS, bool IsParameter); void ParseObjCMethodRequirement(); Decl *ParseObjCMethodPrototype(Decl *classOrCat, tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword); @@ -1185,7 +1185,7 @@ private: void ParseSpecifierQualifierList(DeclSpec &DS); - void ParseObjCTypeQualifierList(ObjCDeclSpec &DS); + void ParseObjCTypeQualifierList(ObjCDeclSpec &DS, bool IsParameter); void ParseEnumSpecifier(SourceLocation TagLoc, DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), AccessSpecifier AS = AS_none); diff --git a/include/clang/Sema/Action.h b/include/clang/Sema/Action.h index af4ebdfc5b..a022430231 100644 --- a/include/clang/Sema/Action.h +++ b/include/clang/Sema/Action.h @@ -2782,7 +2782,9 @@ public: /// \brief Code completion occurs within the body of a function on a /// recovery path, where we do not have a specific handle on our position /// in the grammar. - PCC_RecoveryInFunction + PCC_RecoveryInFunction, + /// \brief Code completion occurs where only a type is permitted. + PCC_Type }; /// \brief Code completion for an ordinary name that occurs within the given @@ -2999,6 +3001,16 @@ public: unsigned NumMethods) { } + /// \brief Code completion for an Objective-C method parameter or return type. + /// + /// This code completion action is invoked when we are parsing the type of + /// an Objective-C method parameter or return type. + /// + /// \param S The scope in which the code-completion occurs. + /// \param DS The Objective-C declaration specifiers so far. + virtual void CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS){ + } + /// \brief Code completion for the receiver in an Objective-C message send. /// /// This code completion action is invoked when we see a '[' that indicates diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index ba1b08b557..fbcfb98ff3 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -4679,6 +4679,7 @@ public: virtual void CodeCompleteObjCPropertySetter(Scope *S, Decl *ClassDecl, Decl **Methods, unsigned NumMethods); + virtual void CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS); virtual void CodeCompleteObjCMessageReceiver(Scope *S); virtual void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, IdentifierInfo **SelIdents, diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index df47fdfaf9..5e28e648ae 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -680,8 +680,13 @@ bool Parser::isTokIdentifier_in() const { /// objc-type-qualifier /// objc-type-qualifiers objc-type-qualifier /// -void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS) { +void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, bool IsParameter) { while (1) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCPassingType(getCurScope(), DS); + ConsumeCodeCompletionToken(); + } + if (Tok.isNot(tok::identifier)) return; @@ -715,14 +720,14 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS) { /// '(' objc-type-qualifiers[opt] type-name ')' /// '(' objc-type-qualifiers[opt] ')' /// -Parser::TypeTy *Parser::ParseObjCTypeName(ObjCDeclSpec &DS) { +Parser::TypeTy *Parser::ParseObjCTypeName(ObjCDeclSpec &DS, bool IsParameter) { assert(Tok.is(tok::l_paren) && "expected ("); SourceLocation LParenLoc = ConsumeParen(); SourceLocation TypeStartLoc = Tok.getLocation(); // Parse type qualifiers, in, inout, etc. - ParseObjCTypeQualifierList(DS); + ParseObjCTypeQualifierList(DS, IsParameter); TypeTy *Ty = 0; if (isTypeSpecifierQualifier()) { @@ -789,7 +794,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, TypeTy *ReturnType = 0; ObjCDeclSpec DSRet; if (Tok.is(tok::l_paren)) - ReturnType = ParseObjCTypeName(DSRet); + ReturnType = ParseObjCTypeName(DSRet, false); // If attributes exist before the method, parse them. llvm::OwningPtr MethodAttrs; @@ -849,7 +854,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, ArgInfo.Type = 0; if (Tok.is(tok::l_paren)) // Parse the argument type if present. - ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec); + ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec, true); // If attributes exist before the argument name, parse them. ArgInfo.ArgAttrs = 0; diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index aec5568218..568c35d559 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -895,7 +895,10 @@ bool ResultBuilder::IsNamespaceOrAlias(NamedDecl *ND) const { /// \brief Determines whether the given declaration is a type. bool ResultBuilder::IsType(NamedDecl *ND) const { - return isa(ND); + if (UsingShadowDecl *Using = dyn_cast(ND)) + ND = Using->getTargetDecl(); + + return isa(ND) || isa(ND); } /// \brief Determines which members of a class should be visible via @@ -1107,6 +1110,7 @@ static void AddFunctionSpecifiers(Action::ParserCompletionContext CCC, case Action::PCC_ForInit: case Action::PCC_Condition: case Action::PCC_RecoveryInFunction: + case Action::PCC_Type: break; } } @@ -1147,6 +1151,7 @@ static bool WantTypesInContext(Action::ParserCompletionContext CCC, case Action::PCC_MemberTemplate: case Action::PCC_Statement: case Action::PCC_RecoveryInFunction: + case Action::PCC_Type: return true; case Action::PCC_ObjCInterface: @@ -1621,12 +1626,15 @@ static void AddOrdinaryNameResults(Action::ParserCompletionContext CCC, Results.AddResult(Result(Pattern)); break; } + + case Action::PCC_Type: + break; } if (WantTypesInContext(CCC, SemaRef.getLangOptions())) AddTypeSpecifierResults(SemaRef.getLangOptions(), Results); - if (SemaRef.getLangOptions().CPlusPlus) + if (SemaRef.getLangOptions().CPlusPlus && CCC != Action::PCC_Type) Results.AddResult(Result("operator")); } @@ -3526,6 +3534,51 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S, Decl *ObjCImplDecl, Results.data(),Results.size()); } +void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS) { + typedef CodeCompleteConsumer::Result Result; + ResultBuilder Results(*this); + Results.EnterNewScope(); + + // Add context-sensitive, Objective-C parameter-passing keywords. + bool AddedInOut = false; + if ((DS.getObjCDeclQualifier() & + (ObjCDeclSpec::DQ_In | ObjCDeclSpec::DQ_Inout)) == 0) { + Results.AddResult("in"); + Results.AddResult("inout"); + AddedInOut = true; + } + if ((DS.getObjCDeclQualifier() & + (ObjCDeclSpec::DQ_Out | ObjCDeclSpec::DQ_Inout)) == 0) { + Results.AddResult("out"); + if (!AddedInOut) + Results.AddResult("inout"); + } + if ((DS.getObjCDeclQualifier() & + (ObjCDeclSpec::DQ_Bycopy | ObjCDeclSpec::DQ_Byref | + ObjCDeclSpec::DQ_Oneway)) == 0) { + Results.AddResult("bycopy"); + Results.AddResult("byref"); + Results.AddResult("oneway"); + } + + // Add various builtin type names and specifiers. + AddOrdinaryNameResults(PCC_Type, S, *this, Results); + Results.ExitScope(); + + // Add the various type names + Results.setFilter(&ResultBuilder::IsOrdinaryNonValueName); + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer, + CodeCompleter->includeGlobals()); + + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, Results); + + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Type, + Results.data(), Results.size()); +} + /// \brief When we have an expression with type "id", we may assume /// that it has some more-specific class type based on knowledge of /// common uses of Objective-C. This routine returns that class type, diff --git a/test/Index/complete-method-decls.m b/test/Index/complete-method-decls.m index 90df54c408..20f6c60078 100644 --- a/test/Index/complete-method-decls.m +++ b/test/Index/complete-method-decls.m @@ -53,7 +53,11 @@ @end @implementation D -- (int)first:(int)x second2:(float)y third:(double)z; +- (int)first:(int)x second2:(float)y third:(double)z { } +@end + +@interface Passing +- (oneway void)method:(in id x); @end // RUN: c-index-test -code-completion-at=%s:17:3 %s | FileCheck -check-prefix=CHECK-CC1 %s @@ -116,3 +120,40 @@ // RUN: c-index-test -code-completion-at=%s:56:38 %s | FileCheck -check-prefix=CHECK-CCE %s // CHECK-CCE: ObjCInstanceMethodDecl:{ResultType id}{Informative first:}{Informative second2:}{TypedText third:}{Text (double)z} (20) // CHECK-CCE: ObjCInstanceMethodDecl:{ResultType int}{Informative first:}{Informative second2:}{TypedText third:}{Text (double)z} (5) +// RUN: c-index-test -code-completion-at=%s:60:4 %s | FileCheck -check-prefix=CHECK-CCF %s +// CHECK-CCF: ObjCInterfaceDecl:{TypedText A} (40) +// CHECK-CCF: ObjCInterfaceDecl:{TypedText B} (40) +// CHECK-CCF: NotImplemented:{TypedText bycopy} (30) +// CHECK-CCF: NotImplemented:{TypedText byref} (30) +// CHECK-CCF: NotImplemented:{TypedText in} (30) +// CHECK-CCF: NotImplemented:{TypedText inout} (30) +// CHECK-CCF: NotImplemented:{TypedText oneway} (30) +// CHECK-CCF: NotImplemented:{TypedText out} (30) +// CHECK-CCF: NotImplemented:{TypedText unsigned} (40) +// CHECK-CCF: NotImplemented:{TypedText void} (40) +// CHECK-CCF: NotImplemented:{TypedText volatile} (40) +// RUN: c-index-test -code-completion-at=%s:60:11 %s | FileCheck -check-prefix=CHECK-CCG %s +// CHECK-CCG: ObjCInterfaceDecl:{TypedText A} (40) +// CHECK-CCG: ObjCInterfaceDecl:{TypedText B} (40) +// CHECK-CCG-NOT: NotImplemented:{TypedText bycopy} (30) +// CHECK-CCG-NOT: NotImplemented:{TypedText byref} (30) +// CHECK-CCG: NotImplemented:{TypedText in} (30) +// CHECK-CCG: NotImplemented:{TypedText inout} (30) +// CHECK-CCG-NOT: NotImplemented:{TypedText oneway} (30) +// CHECK-CCG: NotImplemented:{TypedText out} (30) +// CHECK-CCG: NotImplemented:{TypedText unsigned} (40) +// CHECK-CCG: NotImplemented:{TypedText void} (40) +// CHECK-CCG: NotImplemented:{TypedText volatile} (40) +// RUN: c-index-test -code-completion-at=%s:60:24 %s | FileCheck -check-prefix=CHECK-CCF %s +// RUN: c-index-test -code-completion-at=%s:60:26 %s | FileCheck -check-prefix=CHECK-CCH %s +// CHECK-CCH: ObjCInterfaceDecl:{TypedText A} (40) +// CHECK-CCH: ObjCInterfaceDecl:{TypedText B} (40) +// CHECK-CCH: NotImplemented:{TypedText bycopy} (30) +// CHECK-CCH: NotImplemented:{TypedText byref} (30) +// CHECK-CCH-NOT: NotImplemented:{TypedText in} (30) +// CHECK-CCH: NotImplemented:{TypedText inout} (30) +// CHECK-CCH: NotImplemented:{TypedText oneway} (30) +// CHECK-CCH: NotImplemented:{TypedText out} (30) +// CHECK-CCH: NotImplemented:{TypedText unsigned} (40) +// CHECK-CCH: NotImplemented:{TypedText void} (40) +// CHECK-CCH: NotImplemented:{TypedText volatile} (40)