r240159 - Code completion for nullability type specifiers.

Douglas Gregor dgregor at apple.com
Fri Jun 19 11:27:52 PDT 2015


Author: dgregor
Date: Fri Jun 19 13:27:52 2015
New Revision: 240159

URL: http://llvm.org/viewvc/llvm-project?rev=240159&view=rev
Log:
Code completion for nullability type specifiers.

Another part of rdar://problem/18868820.

Modified:
    cfe/trunk/lib/AST/DeclPrinter.cpp
    cfe/trunk/lib/Sema/SemaCodeComplete.cpp
    cfe/trunk/test/Index/complete-method-decls.m
    cfe/trunk/test/Index/complete-objc-message.m
    cfe/trunk/test/Index/complete-property-flags.m
    cfe/trunk/test/Index/complete-stmt.c

Modified: cfe/trunk/lib/AST/DeclPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclPrinter.cpp?rev=240159&r1=240158&r2=240159&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclPrinter.cpp (original)
+++ cfe/trunk/lib/AST/DeclPrinter.cpp Fri Jun 19 13:27:52 2015
@@ -937,18 +937,6 @@ void DeclPrinter::VisitClassTemplateDecl
 // Objective-C declarations
 //----------------------------------------------------------------------------
 
-/// Strip off the top-level nullability annotation, if it's there.
-static Optional<NullabilityKind> stripOuterNullability(QualType &T) {
-  if (auto attributed = dyn_cast<AttributedType>(T.getTypePtr())) {
-    if (auto nullability = attributed->getImmediateNullability()) {
-      T = attributed->getModifiedType();
-      return nullability;
-    }
-  }
-
-  return None;
- }
-
 void DeclPrinter::PrintObjCMethodType(ASTContext &Ctx, 
                                       Decl::ObjCDeclQualifier Quals, 
                                       QualType T) {
@@ -966,7 +954,7 @@ void DeclPrinter::PrintObjCMethodType(AS
   if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_Oneway)
     Out << "oneway ";
   if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_CSNullability) {
-    if (auto nullability = stripOuterNullability(T)) {
+    if (auto nullability = AttributedType::stripOuterNullability(T)) {
       Out << getNullabilitySpelling(*nullability).substr(2) << ' ';
     }
   }
@@ -1212,7 +1200,7 @@ void DeclPrinter::VisitObjCPropertyDecl(
     
     if (PDecl->getPropertyAttributes() &
         ObjCPropertyDecl::OBJC_PR_nullability) {
-      if (auto nullability = stripOuterNullability(T)) {
+      if (auto nullability = AttributedType::stripOuterNullability(T)) {
         if (*nullability == NullabilityKind::Unspecified &&
             (PDecl->getPropertyAttributes() &
                ObjCPropertyDecl::OBJC_PR_null_resettable)) {

Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=240159&r1=240158&r2=240159&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Fri Jun 19 13:27:52 2015
@@ -1341,6 +1341,11 @@ static void AddTypeSpecifierResults(cons
     Builder.AddChunk(CodeCompletionString::CK_RightParen);
     Results.AddResult(Result(Builder.TakeString()));
   }
+
+  // Nullability
+  Results.AddResult(Result("__nonnull", CCP_Type));
+  Results.AddResult(Result("__null_unspecified", CCP_Type));
+  Results.AddResult(Result("__nullable", CCP_Type));
 }
 
 static void AddStorageSpecifiers(Sema::ParserCompletionContext CCC,
@@ -2097,7 +2102,8 @@ static void MaybeAddSentinel(Preprocesso
     }
 }
 
-static std::string formatObjCParamQualifiers(unsigned ObjCQuals) {
+static std::string formatObjCParamQualifiers(unsigned ObjCQuals, 
+                                             QualType &Type) {
   std::string Result;
   if (ObjCQuals & Decl::OBJC_TQ_In)
     Result += "in ";
@@ -2111,6 +2117,23 @@ static std::string formatObjCParamQualif
     Result += "byref ";
   if (ObjCQuals & Decl::OBJC_TQ_Oneway)
     Result += "oneway ";
+  if (ObjCQuals & Decl::OBJC_TQ_CSNullability) {
+    if (auto nullability = AttributedType::stripOuterNullability(Type)) {
+      switch (*nullability) {
+      case NullabilityKind::NonNull:
+        Result += "nonnull ";
+        break;
+
+      case NullabilityKind::Nullable:
+        Result += "nullable ";
+        break;
+
+      case NullabilityKind::Unspecified:
+        Result += "null_unspecified ";
+        break;
+      }
+    }
+  }
   return Result;
 }
 
@@ -2128,13 +2151,15 @@ static std::string FormatFunctionParamet
     if (Param->getIdentifier() && !ObjCMethodParam && !SuppressName)
       Result = Param->getIdentifier()->getName();
     
-    Param->getType().getAsStringInternal(Result, Policy);
-    
+    QualType Type = Param->getType();
     if (ObjCMethodParam) {
-      Result = "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier())
-             + Result + ")";
+      Result = "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier(),
+                                               Type);
+      Result += Type.getAsString(Policy) + ")";
       if (Param->getIdentifier() && !SuppressName)
         Result += Param->getIdentifier()->getName();
+    } else {
+      Type.getAsStringInternal(Result, Policy);
     }
     return Result;
   }
@@ -2182,13 +2207,16 @@ static std::string FormatFunctionParamet
     if (!ObjCMethodParam && Param->getIdentifier())
       Result = Param->getIdentifier()->getName();
 
-    Param->getType().getUnqualifiedType().getAsStringInternal(Result, Policy);
+    QualType Type = Param->getType().getUnqualifiedType();
     
     if (ObjCMethodParam) {
-      Result = "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier())
-             + Result + ")";
+      Result = "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier(),
+                                               Type);
+      Result += Type.getAsString(Policy) + Result + ")";
       if (Param->getIdentifier())
         Result += Param->getIdentifier()->getName();
+    } else {
+      Type.getAsStringInternal(Result, Policy);
     }
       
     return Result;
@@ -2762,9 +2790,10 @@ CodeCompletionResult::CreateCodeCompleti
       if ((*P)->getType()->isBlockPointerType() && !DeclaringEntity)
         Arg = FormatFunctionParameter(Policy, *P, true);
       else {
-        (*P)->getType().getAsStringInternal(Arg, Policy);
-        Arg = "(" + formatObjCParamQualifiers((*P)->getObjCDeclQualifier()) 
-            + Arg + ")";
+        QualType Type = (*P)->getType();
+        Arg = "(" + formatObjCParamQualifiers((*P)->getObjCDeclQualifier(),
+                                              Type);
+        Arg += Type.getAsString(Policy) + ")";
         if (IdentifierInfo *II = (*P)->getIdentifier())
           if (DeclaringEntity || AllParametersAreInformative)
             Arg += II->getName();
@@ -4858,6 +4887,12 @@ void Sema::CodeCompleteObjCPropertyFlags
     Getter.AddPlaceholderChunk("method");
     Results.AddResult(CodeCompletionResult(Getter.TakeString()));
   }
+  if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_nullability)) {
+    Results.AddResult(CodeCompletionResult("nonnull"));
+    Results.AddResult(CodeCompletionResult("nullable"));
+    Results.AddResult(CodeCompletionResult("null_unspecified"));
+    Results.AddResult(CodeCompletionResult("null_resettable"));
+  }
   Results.ExitScope();
   HandleCodeCompleteResults(this, CodeCompleter, 
                             CodeCompletionContext::CCC_Other,
@@ -5107,6 +5142,11 @@ void Sema::CodeCompleteObjCPassingType(S
      Results.AddResult("byref");
      Results.AddResult("oneway");
   }
+  if ((DS.getObjCDeclQualifier() & ObjCDeclSpec::DQ_CSNullability) == 0) {
+    Results.AddResult("nonnull");
+    Results.AddResult("nullable");
+    Results.AddResult("null_unspecified");
+  }
   
   // If we're completing the return type of an Objective-C method and the 
   // identifier IBAction refers to a macro, provide a completion item for
@@ -6279,7 +6319,7 @@ static void AddObjCPassingTypeChunk(Qual
                                     const PrintingPolicy &Policy,
                                     CodeCompletionBuilder &Builder) {
   Builder.AddChunk(CodeCompletionString::CK_LeftParen);
-  std::string Quals = formatObjCParamQualifiers(ObjCDeclQuals);
+  std::string Quals = formatObjCParamQualifiers(ObjCDeclQuals, Type);
   if (!Quals.empty())
     Builder.AddTextChunk(Builder.getAllocator().CopyString(Quals));
   Builder.AddTextChunk(GetCompletionTypeString(Type, Context, Policy,
@@ -7018,7 +7058,12 @@ void Sema::CodeCompleteObjCMethodDecl(Sc
         break;
 
       // Add the parameter type.
-      AddObjCPassingTypeChunk((*P)->getOriginalType(),
+      QualType ParamType;
+      if ((*P)->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability)
+        ParamType = (*P)->getType();
+      else
+        ParamType = (*P)->getOriginalType();
+      AddObjCPassingTypeChunk(ParamType,
                               (*P)->getObjCDeclQualifier(),
                               Context, Policy,
                               Builder);

Modified: cfe/trunk/test/Index/complete-method-decls.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/complete-method-decls.m?rev=240159&r1=240158&r2=240159&view=diff
==============================================================================
--- cfe/trunk/test/Index/complete-method-decls.m (original)
+++ cfe/trunk/test/Index/complete-method-decls.m Fri Jun 19 13:27:52 2015
@@ -82,6 +82,14 @@ typedef A *MyObjectRef;
 @end
 
 @implementation I1
+-(void)foo {}
+ at end
+
+ at interface I2
+-(nonnull I2 *)produceI2:(nullable I2 *)i2;
+ at end
+
+ at implementation I2
 -
 @end
 
@@ -153,6 +161,8 @@ typedef A *MyObjectRef;
 // CHECK-CCF: NotImplemented:{TypedText byref} (40)
 // CHECK-CCF: NotImplemented:{TypedText in} (40)
 // CHECK-CCF: NotImplemented:{TypedText inout} (40)
+// CHECK-CCF: NotImplemented:{TypedText nonnull} (40)
+// CHECK-CCF: NotImplemented:{TypedText nullable} (40)
 // CHECK-CCF: NotImplemented:{TypedText oneway} (40)
 // CHECK-CCF: NotImplemented:{TypedText out} (40)
 // CHECK-CCF: NotImplemented:{TypedText unsigned} (50)
@@ -201,3 +211,6 @@ typedef A *MyObjectRef;
 // FIXME: It should be "MyObject <P1> *""
 // CHECK-CLASSTY: ObjCInstanceMethodDecl:{LeftParen (}{Text A<P1> *}{RightParen )}{TypedText meth2}
 // CHECK-CLASSTY: ObjCInstanceMethodDecl:{LeftParen (}{Text MyObjectRef}{RightParen )}{TypedText meth3}
+
+// RUN: c-index-test -code-completion-at=%s:93:2 %s | FileCheck -check-prefix=CHECK-NULLABILITY %s
+// CHECK-NULLABILITY: ObjCInstanceMethodDecl:{LeftParen (}{Text nonnull }{Text I2 *}{RightParen )}{TypedText produceI2}{TypedText :}{LeftParen (}{Text nullable }{Text I2 *}{RightParen )}{Text i2} (40)

Modified: cfe/trunk/test/Index/complete-objc-message.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/complete-objc-message.m?rev=240159&r1=240158&r2=240159&view=diff
==============================================================================
--- cfe/trunk/test/Index/complete-objc-message.m (original)
+++ cfe/trunk/test/Index/complete-objc-message.m Fri Jun 19 13:27:52 2015
@@ -189,6 +189,14 @@ void test_DO(DO *d, A* a) {
   [d method:a aout:&a];
 }
 
+ at interface Nullability
+- (nonnull A *)method:(nullable A *)param;
+ at end
+
+void test_Nullability(Nullability *n, A* a) {
+  [n method: a];
+}
+
 // RUN: c-index-test -code-completion-at=%s:23:19 %s | FileCheck -check-prefix=CHECK-CC1 %s
 // CHECK-CC1: {TypedText categoryClassMethod} (35)
 // CHECK-CC1: {TypedText classMethod1:}{Placeholder (id)}{HorizontalSpace  }{TypedText withKeyword:}{Placeholder (int)} (35)
@@ -335,3 +343,6 @@ void test_DO(DO *d, A* a) {
 
 // RUN: c-index-test -code-completion-at=%s:189:6 %s | FileCheck -check-prefix=CHECK-DISTRIB-OBJECTS %s
 // CHECK-DISTRIB-OBJECTS: ObjCInstanceMethodDecl:{ResultType void}{TypedText method:}{Placeholder (in bycopy A *)}{HorizontalSpace  }{TypedText result:}{Placeholder (out byref A **)} (35)
+
+// RUN: c-index-test -code-completion-at=%s:197:6 %s | FileCheck -check-prefix=CHECK-NULLABLE %s
+// CHECK-NULLABLE: ObjCInstanceMethodDecl:{ResultType A * __nonnull}{TypedText method:}{Placeholder (nullable A *)}

Modified: cfe/trunk/test/Index/complete-property-flags.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/complete-property-flags.m?rev=240159&r1=240158&r2=240159&view=diff
==============================================================================
--- cfe/trunk/test/Index/complete-property-flags.m (original)
+++ cfe/trunk/test/Index/complete-property-flags.m Fri Jun 19 13:27:52 2015
@@ -13,6 +13,10 @@
 // CHECK-CC1-NEXT: {TypedText copy}
 // CHECK-CC1-NEXT: {TypedText getter}{Text =}{Placeholder method}
 // CHECK-CC1-NEXT: {TypedText nonatomic}
+// CHECK-CC1: {TypedText nonnull}
+// CHECK-CC1-NEXT: {TypedText null_resettable}
+// CHECK-CC1-NEXT: {TypedText null_unspecified}
+// CHECK-CC1-NEXT: {TypedText nullable}
 // CHECK-CC1-NEXT: {TypedText readonly}
 // CHECK-CC1-NEXT: {TypedText readwrite}
 // CHECK-CC1-NEXT: {TypedText retain}
@@ -27,6 +31,10 @@
 // CHECK-CC1-ARC-NEXT: {TypedText copy}
 // CHECK-CC1-ARC-NEXT: {TypedText getter}{Text =}{Placeholder method}
 // CHECK-CC1-ARC-NEXT: {TypedText nonatomic}
+// CHECK-CC1-ARC-NEXT: {TypedText nonnull}
+// CHECK-CC1-ARC-NEXT: {TypedText null_resettable}
+// CHECK-CC1-ARC-NEXT: {TypedText null_unspecified}
+// CHECK-CC1-ARC-NEXT: {TypedText nullable}
 // CHECK-CC1-ARC-NEXT: {TypedText readonly}
 // CHECK-CC1-ARC-NEXT: {TypedText readwrite}
 // CHECK-CC1-ARC-NEXT: {TypedText retain}
@@ -38,6 +46,10 @@
 // RUN: c-index-test -code-completion-at=%s:8:18 %s | FileCheck -check-prefix=CHECK-CC2 %s
 // CHECK-CC2: {TypedText getter}{Text =}{Placeholder method}
 // CHECK-CC2-NEXT: {TypedText nonatomic}
+// CHECK-CC2-NEXT: {TypedText nonnull}
+// CHECK-CC2-NEXT: {TypedText null_resettable}
+// CHECK-CC2-NEXT: {TypedText null_unspecified}
+// CHECK-CC2-NEXT: {TypedText nullable}
 // CHECK-CC2-NEXT: {TypedText readonly}
 // CHECK-CC2-NEXT: {TypedText readwrite}
 // CHECK-CC2-NEXT: {TypedText setter}{Text =}{Placeholder method}

Modified: cfe/trunk/test/Index/complete-stmt.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/complete-stmt.c?rev=240159&r1=240158&r2=240159&view=diff
==============================================================================
--- cfe/trunk/test/Index/complete-stmt.c (original)
+++ cfe/trunk/test/Index/complete-stmt.c Fri Jun 19 13:27:52 2015
@@ -16,6 +16,8 @@ void f(int x) {
 // CHECK-IF-ELSE-SIMPLE: NotImplemented:{TypedText else}{HorizontalSpace  }{Text if}{HorizontalSpace  }{LeftParen (}{Placeholder expression}{RightParen )} (40)
 
 // RUN: c-index-test -code-completion-at=%s:6:1 %s | FileCheck -check-prefix=CHECK-STMT %s
+// CHECK-STMT: NotImplemented:{TypedText __nonnull} (50)
+// CHECK-STMT: NotImplemented:{TypedText __nullable} (50)
 // CHECK-STMT: NotImplemented:{TypedText char} (50)
 // CHECK-STMT: NotImplemented:{TypedText const} (50)
 // CHECK-STMT: NotImplemented:{TypedText double} (50)





More information about the cfe-commits mailing list