summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2015-06-19 18:27:52 +0000
committerDouglas Gregor <dgregor@apple.com>2015-06-19 18:27:52 +0000
commit86b4268153c9e903065f23f533b67393a39f9503 (patch)
treedfed20d71f573ada1a686a3b244ddaa06ff13264 /clang
parentbec595a6412104306926278f811fd7a75fd0d25f (diff)
downloadbcm5719-llvm-86b4268153c9e903065f23f533b67393a39f9503.tar.gz
bcm5719-llvm-86b4268153c9e903065f23f533b67393a39f9503.zip
Code completion for nullability type specifiers.
Another part of rdar://problem/18868820. llvm-svn: 240159
Diffstat (limited to 'clang')
-rw-r--r--clang/lib/AST/DeclPrinter.cpp16
-rw-r--r--clang/lib/Sema/SemaCodeComplete.cpp71
-rw-r--r--clang/test/Index/complete-method-decls.m13
-rw-r--r--clang/test/Index/complete-objc-message.m11
-rw-r--r--clang/test/Index/complete-property-flags.m12
-rw-r--r--clang/test/Index/complete-stmt.c2
6 files changed, 98 insertions, 27 deletions
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index d6c03169d9c..c3ce4760097 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -937,18 +937,6 @@ void DeclPrinter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// 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(ASTContext &Ctx,
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(ObjCPropertyDecl *PDecl) {
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)) {
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index fd97809295a..ebb6bbcd345 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -1341,6 +1341,11 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts,
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(Preprocessor &PP,
}
}
-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 formatObjCParamQualifiers(unsigned ObjCQuals) {
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 FormatFunctionParameter(const PrintingPolicy &Policy,
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 FormatFunctionParameter(const PrintingPolicy &Policy,
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::CreateCodeCompletionString(ASTContext &Ctx,
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(Scope *S, ObjCDeclSpec &ODS) {
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(Scope *S, ObjCDeclSpec &DS,
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(QualType Type,
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(Scope *S,
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);
diff --git a/clang/test/Index/complete-method-decls.m b/clang/test/Index/complete-method-decls.m
index eceaa833fc3..0e3780ba3d5 100644
--- a/clang/test/Index/complete-method-decls.m
+++ b/clang/test/Index/complete-method-decls.m
@@ -82,6 +82,14 @@ typedef A *MyObjectRef;
@end
@implementation I1
+-(void)foo {}
+@end
+
+@interface I2
+-(nonnull I2 *)produceI2:(nullable I2 *)i2;
+@end
+
+@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)
diff --git a/clang/test/Index/complete-objc-message.m b/clang/test/Index/complete-objc-message.m
index 5a7200570be..a62b49194e8 100644
--- a/clang/test/Index/complete-objc-message.m
+++ b/clang/test/Index/complete-objc-message.m
@@ -189,6 +189,14 @@ void test_DO(DO *d, A* a) {
[d method:a aout:&a];
}
+@interface Nullability
+- (nonnull A *)method:(nullable A *)param;
+@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 *)}
diff --git a/clang/test/Index/complete-property-flags.m b/clang/test/Index/complete-property-flags.m
index 13ec1e725f2..9e3fc1aff31 100644
--- a/clang/test/Index/complete-property-flags.m
+++ b/clang/test/Index/complete-property-flags.m
@@ -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}
diff --git a/clang/test/Index/complete-stmt.c b/clang/test/Index/complete-stmt.c
index 3d31ca2f908..8bbfe2db56d 100644
--- a/clang/test/Index/complete-stmt.c
+++ b/clang/test/Index/complete-stmt.c
@@ -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)
OpenPOWER on IntegriCloud