[cfe-commits] r89259 - in /cfe/trunk: include/clang/Parse/Action.h lib/Parse/ParseObjc.cpp lib/Sema/Sema.h lib/Sema/SemaCodeComplete.cpp test/Index/complete-properties.m

Douglas Gregor dgregor at apple.com
Wed Nov 18 14:32:07 PST 2009


Author: dgregor
Date: Wed Nov 18 16:32:06 2009
New Revision: 89259

URL: http://llvm.org/viewvc/llvm-project?rev=89259&view=rev
Log:
Code completion for Objective-C @synthesized.

Added:
    cfe/trunk/test/Index/complete-properties.m
Modified:
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/lib/Parse/ParseObjc.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaCodeComplete.cpp

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=89259&r1=89258&r2=89259&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Wed Nov 18 16:32:06 2009
@@ -2408,6 +2408,24 @@
                                                    IdentifierInfo *ClassName) {
   }
   
+  /// \brief Code completion for the property names when synthesizing an
+  /// Objective-C property.
+  ///
+  /// This code completion action is invoked after the @synthesized and after
+  /// each "," in an @synthesized definition.
+  virtual void CodeCompleteObjCPropertySynthesize(Scope *S, 
+                                                  DeclPtrTy ObjCImpDecl) {
+  }
+
+  /// \brief Code completion for the instance variable name that should 
+  /// follow an '=' when synthesizing an Objective-C property.
+  ///
+  /// This code completion action is invoked after each '=' that occurs within
+  /// an @synthesized definition.
+  virtual void CodeCompleteObjCPropertySynthesizeIvar(Scope *S, 
+                                                   IdentifierInfo *PropertyName,
+                                                  DeclPtrTy ObjCImpDecl) {
+  }
   //@}
 };
 

Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=89259&r1=89258&r2=89259&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Wed Nov 18 16:32:06 2009
@@ -1231,12 +1231,13 @@
   assert(Tok.isObjCAtKeyword(tok::objc_synthesize) &&
          "ParseObjCPropertyDynamic(): Expected '@synthesize'");
   SourceLocation loc = ConsumeToken(); // consume synthesize
-  if (Tok.isNot(tok::identifier)) {
-    Diag(Tok, diag::err_expected_ident);
-    return DeclPtrTy();
-  }
 
   while (true) {
+    if (Tok.is(tok::code_completion)) {
+      Actions.CodeCompleteObjCPropertySynthesize(CurScope, ObjCImpDecl);
+      ConsumeToken();
+    }
+    
     if (Tok.isNot(tok::identifier)) {
       Diag(Tok, diag::err_synthesized_property_name);
       SkipUntil(tok::semi);
@@ -1249,6 +1250,13 @@
     if (Tok.is(tok::equal)) {
       // property '=' ivar-name
       ConsumeToken(); // consume '='
+      
+      if (Tok.is(tok::code_completion)) {
+        Actions.CodeCompleteObjCPropertySynthesizeIvar(CurScope, propertyId,
+                                                       ObjCImpDecl);
+        ConsumeToken();
+      }
+      
       if (Tok.isNot(tok::identifier)) {
         Diag(Tok, diag::err_expected_ident);
         break;

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=89259&r1=89258&r2=89259&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Nov 18 16:32:06 2009
@@ -3654,6 +3654,11 @@
                                                  IdentifierInfo *ClassName);
   virtual void CodeCompleteObjCImplementationCategory(Scope *S, 
                                                     IdentifierInfo *ClassName);
+  virtual void CodeCompleteObjCPropertySynthesize(Scope *S, 
+                                                  DeclPtrTy ObjCImpDecl);
+  virtual void CodeCompleteObjCPropertySynthesizeIvar(Scope *S, 
+                                                  IdentifierInfo *PropertyName,
+                                                      DeclPtrTy ObjCImpDecl);
   //@}
   
   //===--------------------------------------------------------------------===//

Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=89259&r1=89258&r2=89259&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Wed Nov 18 16:32:06 2009
@@ -1132,6 +1132,7 @@
 }
 
 static void AddObjCProperties(ObjCContainerDecl *Container, 
+                              bool AllowCategories,
                               DeclContext *CurContext,
                               ResultBuilder &Results) {
   typedef CodeCompleteConsumer::Result Result;
@@ -1148,29 +1149,32 @@
     for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(),
                                           PEnd = Protocol->protocol_end();
          P != PEnd; ++P)
-      AddObjCProperties(*P, CurContext, Results);
+      AddObjCProperties(*P, AllowCategories, CurContext, Results);
   } else if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)){
-    // Look through categories.
-    for (ObjCCategoryDecl *Category = IFace->getCategoryList();
-         Category; Category = Category->getNextClassCategory())
-      AddObjCProperties(Category, CurContext, Results);
+    if (AllowCategories) {
+      // Look through categories.
+      for (ObjCCategoryDecl *Category = IFace->getCategoryList();
+           Category; Category = Category->getNextClassCategory())
+        AddObjCProperties(Category, AllowCategories, CurContext, Results);
+    }
     
     // Look through protocols.
     for (ObjCInterfaceDecl::protocol_iterator I = IFace->protocol_begin(),
                                               E = IFace->protocol_end(); 
          I != E; ++I)
-      AddObjCProperties(*I, CurContext, Results);
+      AddObjCProperties(*I, AllowCategories, CurContext, Results);
     
     // Look in the superclass.
     if (IFace->getSuperClass())
-      AddObjCProperties(IFace->getSuperClass(), CurContext, Results);
+      AddObjCProperties(IFace->getSuperClass(), AllowCategories, CurContext, 
+                        Results);
   } else if (const ObjCCategoryDecl *Category
                                     = dyn_cast<ObjCCategoryDecl>(Container)) {
     // Look through protocols.
     for (ObjCInterfaceDecl::protocol_iterator P = Category->protocol_begin(),
                                            PEnd = Category->protocol_end(); 
          P != PEnd; ++P)
-      AddObjCProperties(*P, CurContext, Results);
+      AddObjCProperties(*P, AllowCategories, CurContext, Results);
   }
 }
 
@@ -1234,13 +1238,13 @@
     const ObjCObjectPointerType *ObjCPtr
       = BaseType->getAsObjCInterfacePointerType();
     assert(ObjCPtr && "Non-NULL pointer guaranteed above!");
-    AddObjCProperties(ObjCPtr->getInterfaceDecl(), CurContext, Results);
+    AddObjCProperties(ObjCPtr->getInterfaceDecl(), true, CurContext, Results);
     
     // Add properties from the protocols in a qualified interface.
     for (ObjCObjectPointerType::qual_iterator I = ObjCPtr->qual_begin(),
                                               E = ObjCPtr->qual_end();
          I != E; ++I)
-      AddObjCProperties(*I, CurContext, Results);
+      AddObjCProperties(*I, true, CurContext, Results);
     
     // FIXME: We could (should?) also look for "implicit" properties, identified
     // only by the presence of nullary and unary selectors.
@@ -2021,3 +2025,74 @@
   
   HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());  
 }
+
+void Sema::CodeCompleteObjCPropertySynthesize(Scope *S, DeclPtrTy ObjCImpDecl) {
+  typedef CodeCompleteConsumer::Result Result;
+  ResultBuilder Results(*this);
+
+  // Figure out where this @synthesize lives.
+  ObjCContainerDecl *Container
+    = dyn_cast_or_null<ObjCContainerDecl>(ObjCImpDecl.getAs<Decl>());
+  if (!Container || 
+      (!isa<ObjCImplementationDecl>(Container) && 
+       !isa<ObjCCategoryImplDecl>(Container)))
+    return; 
+
+  // Ignore any properties that have already been implemented.
+  for (DeclContext::decl_iterator D = Container->decls_begin(), 
+                               DEnd = Container->decls_end();
+       D != DEnd; ++D)
+    if (ObjCPropertyImplDecl *PropertyImpl = dyn_cast<ObjCPropertyImplDecl>(*D))
+      Results.Ignore(PropertyImpl->getPropertyDecl());
+  
+  // Add any properties that we find.
+  Results.EnterNewScope();
+  if (ObjCImplementationDecl *ClassImpl
+        = dyn_cast<ObjCImplementationDecl>(Container))
+    AddObjCProperties(ClassImpl->getClassInterface(), false, CurContext, 
+                      Results);
+  else
+    AddObjCProperties(cast<ObjCCategoryImplDecl>(Container)->getCategoryDecl(),
+                      false, CurContext, Results);
+  Results.ExitScope();
+  
+  HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());  
+}
+
+void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, 
+                                                  IdentifierInfo *PropertyName,
+                                                  DeclPtrTy ObjCImpDecl) {
+  typedef CodeCompleteConsumer::Result Result;
+  ResultBuilder Results(*this);
+
+  // Figure out where this @synthesize lives.
+  ObjCContainerDecl *Container
+    = dyn_cast_or_null<ObjCContainerDecl>(ObjCImpDecl.getAs<Decl>());
+  if (!Container || 
+      (!isa<ObjCImplementationDecl>(Container) && 
+       !isa<ObjCCategoryImplDecl>(Container)))
+    return; 
+  
+  // Figure out which interface we're looking into.
+  ObjCInterfaceDecl *Class = 0;
+  if (ObjCImplementationDecl *ClassImpl
+                                 = dyn_cast<ObjCImplementationDecl>(Container))  
+    Class = ClassImpl->getClassInterface();
+  else
+    Class = cast<ObjCCategoryImplDecl>(Container)->getCategoryDecl()
+                                                          ->getClassInterface();
+
+  // Add all of the instance variables in this class and its superclasses.
+  Results.EnterNewScope();
+  for(; Class; Class = Class->getSuperClass()) {
+    // FIXME: We could screen the type of each ivar for compatibility with
+    // the property, but is that being too paternal?
+    for (ObjCInterfaceDecl::ivar_iterator IVar = Class->ivar_begin(),
+                                       IVarEnd = Class->ivar_end();
+         IVar != IVarEnd; ++IVar) 
+      Results.MaybeAddResult(Result(*IVar, 0), CurContext);
+  }
+  Results.ExitScope();
+  
+  HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
+}

Added: cfe/trunk/test/Index/complete-properties.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/complete-properties.m?rev=89259&view=auto

==============================================================================
--- cfe/trunk/test/Index/complete-properties.m (added)
+++ cfe/trunk/test/Index/complete-properties.m Wed Nov 18 16:32:06 2009
@@ -0,0 +1,30 @@
+/* Note: the RUN lines are near the end of the file, since line/column
+ matter for this test. */
+
+ at interface I1 
+{
+  id StoredProp3;
+  int RandomIVar;
+}
+ at property int Prop1;
+ at property float Prop2;
+ at end
+
+ at interface I2 : I1
+ at property id Prop3;
+ at end
+
+ at implementation I2
+ at synthesize Prop2, Prop1, Prop3 = StoredProp3;
+ at end
+
+// RUN: c-index-test -code-completion-at=%s:18:13 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// CHECK-CC1: ObjCPropertyDecl:{TypedText Prop1}
+// CHECK-CC1: ObjCPropertyDecl:{TypedText Prop2}
+// CHECK-CC1: ObjCPropertyDecl:{TypedText Prop3}
+// RUN: c-index-test -code-completion-at=%s:18:20 %s | FileCheck -check-prefix=CHECK-CC2 %s
+// CHECK-CC2: ObjCPropertyDecl:{TypedText Prop1}
+// CHECK-CC2-NEXT: ObjCPropertyDecl:{TypedText Prop3}
+// RUN: c-index-test -code-completion-at=%s:18:35 %s | FileCheck -check-prefix=CHECK-CC3 %s
+// CHECK-CC3: ObjCIvarDecl:{TypedText RandomIVar}
+// CHECK-CC3: ObjCIvarDecl:{TypedText StoredProp3}





More information about the cfe-commits mailing list