]> granicus.if.org Git - clang/commitdiff
Provide code completion results for the context-sensitive Objective-C
authorDouglas Gregor <dgregor@apple.com>
Tue, 24 Aug 2010 01:06:58 +0000 (01:06 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 24 Aug 2010 01:06:58 +0000 (01:06 +0000)
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

include/clang/Parse/Parser.h
include/clang/Sema/Action.h
include/clang/Sema/Sema.h
lib/Parse/ParseObjc.cpp
lib/Sema/SemaCodeComplete.cpp
test/Index/complete-method-decls.m

index 6e537989bb5360c1e80dd45fff5741adaeb86d36..7aa08126df26ab2f28ced38c89b2ae3ec9acb622 100644 (file)
@@ -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);
index af4ebdfc5b3cfe957298d8f453dbf163869de3d7..a022430231db282c1a7ca40e0f9e76d06aed7319 100644 (file)
@@ -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
index ba1b08b557a6569e59859a818fa4e59a9ff5c3e9..fbcfb98ff3e27dbb4b5d47a5cbec98ec923c3182 100644 (file)
@@ -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,
index df47fdfaf9ef39e63a47f4094af264fc23e554d0..5e28e648aefd27a42d4a6e2898b92a450355da0c 100644 (file)
@@ -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<AttributeList> 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;
index aec55682180e9da3231b0a710aa629281243d5b7..568c35d559b1e4942f49bc1c54ad299e5a1cd24b 100644 (file)
@@ -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<TypeDecl>(ND);
+  if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(ND))
+    ND = Using->getTargetDecl();
+  
+  return isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(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,
index 90df54c40894f321fffcf9ddf743a36c43e46186..20f6c600783cf2b33d293ee922c0b6c124be207d 100644 (file)
 @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
 // 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)