Author: arphaman
Date: Thu Dec  8 09:09:40 2016
New Revision: 289058

URL: http://llvm.org/viewvc/llvm-project?rev=289058&view=rev
Log:
[CodeCompletion] Provide Objective-C class property completion results

This commit provides class property code completion results. It supports
explicit and implicit class properties, but the special block completion is done
only for explicit properties right now.

rdar://25636195

Differential Revision: https://reviews.llvm.org/D27053

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

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=289058&r1=289057&r2=289058&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Dec  8 09:09:40 2016
@@ -9662,6 +9662,9 @@ public:
                                           bool AtParameterName,
                                           ParsedType ReturnType,
                                           ArrayRef<IdentifierInfo *> 
SelIdents);
+  void CodeCompleteObjCClassPropertyRefExpr(Scope *S, IdentifierInfo 
&ClassName,
+                                            SourceLocation ClassNameLoc,
+                                            bool IsBaseExprStatement);
   void CodeCompletePreprocessorDirective(bool InConditional);
   void CodeCompleteInPreprocessorConditionalExclusion(Scope *S);
   void CodeCompletePreprocessorMacroName(bool IsDefinition);

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=289058&r1=289057&r2=289058&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Thu Dec  8 09:09:40 2016
@@ -885,7 +885,13 @@ ExprResult Parser::ParseCastExpression(b
          // Allow the base to be 'super' if in an objc-method.
          (&II == Ident_super && getCurScope()->isInObjcMethodScope()))) {
       ConsumeToken();
-      
+
+      if (Tok.is(tok::code_completion) && &II != Ident_super) {
+        Actions.CodeCompleteObjCClassPropertyRefExpr(
+            getCurScope(), II, ILoc, ExprStatementTokLoc == ILoc);
+        cutOffParsing();
+        return ExprError();
+      }
       // Allow either an identifier or the keyword 'class' (in C++).
       if (Tok.isNot(tok::identifier) && 
           !(getLangOpts().CPlusPlus && Tok.is(tok::kw_class))) {

Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=289058&r1=289057&r2=289058&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Thu Dec  8 09:09:40 2016
@@ -3654,22 +3654,20 @@ static void AddObjCBlockCall(ASTContext
   Builder.AddChunk(CodeCompletionString::CK_RightParen);
 }
 
-static void AddObjCProperties(const CodeCompletionContext &CCContext,
-                              ObjCContainerDecl *Container,
-                              bool AllowCategories, bool AllowNullaryMethods,
-                              DeclContext *CurContext,
-                              AddedPropertiesSet &AddedProperties,
-                              ResultBuilder &Results,
-                              bool IsBaseExprStatement = false) {
+static void AddObjCProperties(
+    const CodeCompletionContext &CCContext, ObjCContainerDecl *Container,
+    bool AllowCategories, bool AllowNullaryMethods, DeclContext *CurContext,
+    AddedPropertiesSet &AddedProperties, ResultBuilder &Results,
+    bool IsBaseExprStatement = false, bool IsClassProperty = false) {
   typedef CodeCompletionResult Result;
 
   // Retrieve the definition.
   Container = getContainerDef(Container);
   
   // Add properties in this container.
-  for (const auto *P : Container->instance_properties()) {
+  const auto AddProperty = [&](const ObjCPropertyDecl *P) {
     if (!AddedProperties.insert(P->getIdentifier()).second)
-      continue;
+      return;
 
     // FIXME: Provide block invocation completion for non-statement
     // expressions.
@@ -3677,7 +3675,7 @@ static void AddObjCProperties(const Code
         !IsBaseExprStatement) {
       Results.MaybeAddResult(Result(P, Results.getBasePriority(P), nullptr),
                              CurContext);
-      continue;
+      return;
     }
 
     // Block setter and invocation completion is provided only when we are able
@@ -3689,7 +3687,7 @@ static void AddObjCProperties(const Code
     if (!BlockLoc) {
       Results.MaybeAddResult(Result(P, Results.getBasePriority(P), nullptr),
                              CurContext);
-      continue;
+      return;
     }
 
     // The default completion result for block properties should be the block
@@ -3727,64 +3725,89 @@ static void AddObjCProperties(const Code
                  Results.getBasePriority(P) + CCD_BlockPropertySetter),
           CurContext);
     }
+  };
+
+  if (IsClassProperty) {
+    for (const auto *P : Container->class_properties())
+      AddProperty(P);
+  } else {
+    for (const auto *P : Container->instance_properties())
+      AddProperty(P);
   }
 
-  // Add nullary methods
+  // Add nullary methods or implicit class properties
   if (AllowNullaryMethods) {
     ASTContext &Context = Container->getASTContext();
     PrintingPolicy Policy = getCompletionPrintingPolicy(Results.getSema());
-    for (auto *M : Container->methods()) {
-      if (M->getSelector().isUnarySelector())
-        if (IdentifierInfo *Name = 
M->getSelector().getIdentifierInfoForSlot(0))
-          if (AddedProperties.insert(Name).second) {
-            CodeCompletionBuilder Builder(Results.getAllocator(),
-                                          Results.getCodeCompletionTUInfo());
-            AddResultTypeChunk(Context, Policy, M, CCContext.getBaseType(),
-                               Builder);
-            Builder.AddTypedTextChunk(
-                            
Results.getAllocator().CopyString(Name->getName()));
-            
-            Results.MaybeAddResult(Result(Builder.TakeString(), M,
-                                  CCP_MemberDeclaration + 
CCD_MethodAsProperty),
-                                          CurContext);
-          }
+    // Adds a method result
+    const auto AddMethod = [&](const ObjCMethodDecl *M) {
+      IdentifierInfo *Name = M->getSelector().getIdentifierInfoForSlot(0);
+      if (!Name)
+        return;
+      if (!AddedProperties.insert(Name).second)
+        return;
+      CodeCompletionBuilder Builder(Results.getAllocator(),
+                                    Results.getCodeCompletionTUInfo());
+      AddResultTypeChunk(Context, Policy, M, CCContext.getBaseType(), Builder);
+      Builder.AddTypedTextChunk(
+          Results.getAllocator().CopyString(Name->getName()));
+      Results.MaybeAddResult(
+          Result(Builder.TakeString(), M,
+                 CCP_MemberDeclaration + CCD_MethodAsProperty),
+          CurContext);
+    };
+
+    if (IsClassProperty) {
+      for (const auto *M : Container->methods()) {
+        // Gather the class method that can be used as implicit property
+        // getters. Methods with arguments or methods that return void aren't
+        // added to the results as they can't be used as a getter.
+        if (!M->getSelector().isUnarySelector() ||
+            M->getReturnType()->isVoidType() || M->isInstanceMethod())
+          continue;
+        AddMethod(M);
+      }
+    } else {
+      for (auto *M : Container->methods()) {
+        if (M->getSelector().isUnarySelector())
+          AddMethod(M);
+      }
     }
   }
-    
   
   // Add properties in referenced protocols.
   if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {
     for (auto *P : Protocol->protocols())
       AddObjCProperties(CCContext, P, AllowCategories, AllowNullaryMethods,
                         CurContext, AddedProperties, Results,
-                        IsBaseExprStatement);
+                        IsBaseExprStatement, IsClassProperty);
   } else if (ObjCInterfaceDecl *IFace = 
dyn_cast<ObjCInterfaceDecl>(Container)){
     if (AllowCategories) {
       // Look through categories.
       for (auto *Cat : IFace->known_categories())
         AddObjCProperties(CCContext, Cat, AllowCategories, AllowNullaryMethods,
                           CurContext, AddedProperties, Results,
-                          IsBaseExprStatement);
+                          IsBaseExprStatement, IsClassProperty);
     }
 
     // Look through protocols.
     for (auto *I : IFace->all_referenced_protocols())
       AddObjCProperties(CCContext, I, AllowCategories, AllowNullaryMethods,
                         CurContext, AddedProperties, Results,
-                        IsBaseExprStatement);
+                        IsBaseExprStatement, IsClassProperty);
 
     // Look in the superclass.
     if (IFace->getSuperClass())
       AddObjCProperties(CCContext, IFace->getSuperClass(), AllowCategories,
                         AllowNullaryMethods, CurContext, AddedProperties,
-                        Results, IsBaseExprStatement);
+                        Results, IsBaseExprStatement, IsClassProperty);
   } else if (const ObjCCategoryDecl *Category
                                     = dyn_cast<ObjCCategoryDecl>(Container)) {
     // Look through protocols.
     for (auto *P : Category->protocols())
       AddObjCProperties(CCContext, P, AllowCategories, AllowNullaryMethods,
                         CurContext, AddedProperties, Results,
-                        IsBaseExprStatement);
+                        IsBaseExprStatement, IsClassProperty);
   }
 }
 
@@ -3909,6 +3932,30 @@ void Sema::CodeCompleteMemberReferenceEx
                             Results.data(),Results.size());
 }
 
+void Sema::CodeCompleteObjCClassPropertyRefExpr(Scope *S,
+                                                IdentifierInfo &ClassName,
+                                                SourceLocation ClassNameLoc,
+                                                bool IsBaseExprStatement) {
+  IdentifierInfo *ClassNamePtr = &ClassName;
+  ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(ClassNamePtr, ClassNameLoc);
+  if (!IFace)
+    return;
+  CodeCompletionContext CCContext(
+      CodeCompletionContext::CCC_ObjCPropertyAccess);
+  ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+                        CodeCompleter->getCodeCompletionTUInfo(), CCContext,
+                        &ResultBuilder::IsMember);
+  Results.EnterNewScope();
+  AddedPropertiesSet AddedProperties;
+  AddObjCProperties(CCContext, IFace, true,
+                    /*AllowNullaryMethods=*/true, CurContext, AddedProperties,
+                    Results, IsBaseExprStatement,
+                    /*IsClassProperty=*/true);
+  Results.ExitScope();
+  HandleCodeCompleteResults(this, CodeCompleter, 
Results.getCompletionContext(),
+                            Results.data(), Results.size());
+}
+
 void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) {
   if (!CodeCompleter)
     return;

Modified: cfe/trunk/test/Index/complete-block-properties.m
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/complete-block-properties.m?rev=289058&r1=289057&r2=289058&view=diff
==============================================================================
--- cfe/trunk/test/Index/complete-block-properties.m (original)
+++ cfe/trunk/test/Index/complete-block-properties.m Thu Dec  8 09:09:40 2016
@@ -70,3 +70,19 @@ void noQualifierParens(NoQualifierParens
 //CHECK-CC2-NEXT: ObjCInstanceMethodDecl:{ResultType BarBlock}{TypedText 
blockProperty2} (35)
 //CHECK-CC2-NEXT: ObjCInstanceMethodDecl:{ResultType void}{TypedText 
setBlockProperty2:}{Placeholder BarBlock blockProperty2} (35)
 //CHECK-CC2-NEXT: ObjCInstanceMethodDecl:{ResultType void}{TypedText 
setBlockProperty:}{Placeholder void (^)(void)blockProperty} (35)
+
+@interface ClassProperties
+
+@property(class) void (^explicit)();
+@property(class, readonly) void (^explicitReadonly)();
+
+@end
+
+void classBlockProperties() {
+  ClassProperties.explicit;
+}
+
+// RUN: c-index-test -code-completion-at=%s:82:19 %s | FileCheck 
-check-prefix=CHECK-CC3 %s
+//CHECK-CC3: ObjCPropertyDecl:{ResultType void}{TypedText explicit}{LeftParen 
(}{RightParen )} (35)
+//CHECK-CC3-NEXT: ObjCPropertyDecl:{ResultType void (^)()}{TypedText 
explicit}{Equal  = }{Placeholder ^(void)} (38)
+//CHECK-CC3-NEXT: ObjCPropertyDecl:{ResultType void}{TypedText 
explicitReadonly}{LeftParen (}{RightParen )} (35)

Modified: cfe/trunk/test/Index/complete-properties.m
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/complete-properties.m?rev=289058&r1=289057&r2=289058&view=diff
==============================================================================
--- cfe/trunk/test/Index/complete-properties.m (original)
+++ cfe/trunk/test/Index/complete-properties.m Thu Dec  8 09:09:40 2016
@@ -94,3 +94,84 @@ id test(I3 *i3) {
 
 // RUN: c-index-test -code-completion-at=%s:57:13 -fobjc-nonfragile-abi %s | 
FileCheck -check-prefix=CHECK-CC8 %s
 // CHECK-CC8: ObjCPropertyDecl:{ResultType int}{TypedText Prop5} (35)
+
+@interface ClassProperties
+
+@property int instanceProperty;
+@property(class) int explicit;
+@property(class, readonly) int explicitReadonly;
+
++ (int)implicit;
++ (int)setImplicit:(int)x;
+
++ (int)implicitReadonly;
+
++ (void)noProperty;
+
+- (int)implicitInstance;
+
++ (int)shadowedImplicit;
+
+@end
+
+@interface ClassProperties (Category)
+
++ (int)implicitInCategory;
+
+@end
+
+@protocol ProtocolClassProperties
+
+@property(class, readonly) int explicitInProtocol;
+
+@end
+
+@interface SubClassProperties: ClassProperties <ProtocolClassProperties>
+
+@property(class) ClassProperties *shadowedImplicit;
+
+@end
+
+@implementation SubClassProperties
+
+-(void) foo {
+  super.instanceProperty;
+}
+
+@end
+
+void classProperties() {
+  (void)ClassProperties.implicit;
+  (void)SubClassProperties.explicit;
+}
+
+// RUN: c-index-test -code-completion-at=%s:144:25 -fobjc-nonfragile-abi %s | 
FileCheck -check-prefix=CHECK-CC9 %s
+// CHECK-CC9: ObjCPropertyDecl:{ResultType int}{TypedText explicit} (35)
+// CHECK-CC9-NEXT: ObjCPropertyDecl:{ResultType int}{TypedText 
explicitReadonly} (35)
+// CHECK-CC9-NEXT: ObjCClassMethodDecl:{ResultType int}{TypedText implicit} 
(37)
+// CHECK-CC9-NEXT: ObjCClassMethodDecl:{ResultType int}{TypedText 
implicitInCategory} (37)
+// CHECK-CC9-NEXT: ObjCClassMethodDecl:{ResultType int}{TypedText 
implicitReadonly} (37)
+// CHECK-CC9-NEXT: ObjCClassMethodDecl:{ResultType int}{TypedText 
shadowedImplicit} (37)
+// CHECK-CC9-NOT: implicitInstance
+// CHECK-CC9-NOT: noProperty
+// CHECK-CC9-NOT: instanceProperty
+
+// RUN: c-index-test -code-completion-at=%s:145:28 -fobjc-nonfragile-abi %s | 
FileCheck -check-prefix=CHECK-CC10 %s
+// CHECK-CC10: ObjCPropertyDecl:{ResultType int}{TypedText explicit} (35)
+// CHECK-CC10-NEXT: ObjCPropertyDecl:{ResultType int}{TypedText 
explicitInProtocol} (35)
+// CHECK-CC10-NEXT: ObjCPropertyDecl:{ResultType int}{TypedText 
explicitReadonly} (35)
+// CHECK-CC10-NEXT: ObjCClassMethodDecl:{ResultType int}{TypedText implicit} 
(37)
+// CHECK-CC10-NEXT: ObjCClassMethodDecl:{ResultType int}{TypedText 
implicitInCategory} (37)
+// CHECK-CC10-NEXT: ObjCClassMethodDecl:{ResultType int}{TypedText 
implicitReadonly} (37)
+// CHECK-CC10-NEXT: ObjCPropertyDecl:{ResultType ClassProperties *}{TypedText 
shadowedImplicit} (35)
+// CHECK-CC10-NOT: implicitInstance
+// CHECK-CC10-NOT: noProperty
+// CHECK-CC10-NOT: instanceProperty
+
+// RUN: c-index-test -code-completion-at=%s:138:9 -fobjc-nonfragile-abi %s | 
FileCheck -check-prefix=CHECK-CC11 %s
+// CHECK-CC11-NOT: explicit
+// CHECK-CC11-NOT: explicitReadonly
+// CHECK-CC11-NOT: implicit
+// CHECK-CC11-NOT: implicitReadonly
+// CHECK-CC11-NOT: shadowedImplicit
+// CHECK-CC11-NOT: implicitInCategory


_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to