Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -8768,6 +8768,10 @@ "array parameter is missing a nullability type specifier (_Nonnull, " "_Nullable, or _Null_unspecified)">, InGroup; +def note_nullability_fix_it : Note< + "insert '%select{_Nonnull|_Nullable|_Null_unspecified}0' if the " + "%select{pointer|block pointer|member pointer|array parameter}1 " + "%select{should never be null|may be null|should not declare nullability}0">; def warn_nullability_inferred_on_nested_type : Warning< "inferring '_Nonnull' for pointer type within %select{array|reference}0 is " Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -3486,6 +3486,57 @@ return file; } +/// Creates a fix-it to insert a C-style nullability keyword at \p pointerLoc, +/// taking into account whitespace before and after. +static FixItHint fixItNullability(Sema &S, SourceLocation pointerLoc, + NullabilityKind nullability) { + assert(pointerLoc.isValid()); + + SmallString<32> insertionTextBuf{" "}; + insertionTextBuf += getNullabilitySpelling(nullability); + insertionTextBuf += " "; + StringRef insertionText = insertionTextBuf.str(); + + SourceLocation fixItLoc = S.getLocForEndOfToken(pointerLoc); + if (const char *nextChar = S.SourceMgr.getCharacterData(fixItLoc)) { + if (isWhitespace(*nextChar)) { + insertionText = insertionText.drop_back(); + } else if (nextChar[-1] == '[') { + if (nextChar[0] == ']') + insertionText = insertionText.drop_back().drop_front(); + else + insertionText = insertionText.drop_front(); + } else if (!isIdentifierBody(nextChar[0], /*allow dollar*/true) && + !isIdentifierBody(nextChar[-1], /*allow dollar*/true)) { + insertionText = insertionText.drop_back().drop_front(); + } + } + + return FixItHint::CreateInsertion(fixItLoc, insertionText); +} + +static void emitNullabilityConsistencyWarning(Sema &S, + SimplePointerKind pointerKind, + SourceLocation pointerLoc) { + assert(pointerLoc.isValid()); + + if (pointerKind == SimplePointerKind::Array) { + S.Diag(pointerLoc, diag::warn_nullability_missing_array); + } else { + S.Diag(pointerLoc, diag::warn_nullability_missing) + << static_cast(pointerKind); + } + + auto addFixIt = [&](NullabilityKind nullability) { + S.Diag(pointerLoc, diag::note_nullability_fix_it) + << static_cast(nullability) + << static_cast(pointerKind) + << fixItNullability(S, pointerLoc, nullability); + }; + addFixIt(NullabilityKind::Nullable); + addFixIt(NullabilityKind::NonNull); +} + /// Complains about missing nullability if the file containing \p pointerLoc /// has other uses of nullability (either the keywords or the \c assume_nonnull /// pragma). @@ -3522,12 +3573,7 @@ } // Complain about missing nullability. - if (pointerKind == SimplePointerKind::Array) { - S.Diag(pointerLoc, diag::warn_nullability_missing_array); - } else { - S.Diag(pointerLoc, diag::warn_nullability_missing) - << static_cast(pointerKind); - } + emitNullabilityConsistencyWarning(S, pointerKind, pointerLoc); } /// Marks that a nullability feature has been used in the file containing @@ -3552,13 +3598,8 @@ if (fileNullability.PointerLoc.isInvalid()) return; - if (fileNullability.PointerKind == - static_cast(SimplePointerKind::Array)) { - S.Diag(fileNullability.PointerLoc, diag::warn_nullability_missing_array); - } else { - S.Diag(fileNullability.PointerLoc, diag::warn_nullability_missing) - << static_cast(fileNullability.PointerKind); - } + auto kind = static_cast(fileNullability.PointerKind); + emitNullabilityConsistencyWarning(S, kind, fileNullability.PointerLoc); } /// Returns true if any of the declarator chunks before \p endIndex include a @@ -3892,20 +3933,9 @@ if (pointerLoc.isValid() && complainAboutInferringWithinChunk != PointerWrappingDeclaratorKind::None) { - SourceLocation fixItLoc = S.getLocForEndOfToken(pointerLoc); - StringRef insertionText = " _Nonnull "; - if (const char *nextChar = S.SourceMgr.getCharacterData(fixItLoc)) { - if (isWhitespace(*nextChar)) { - insertionText = insertionText.drop_back(); - } else if (!isIdentifierBody(nextChar[0], /*allow dollar*/true) && - !isIdentifierBody(nextChar[-1], /*allow dollar*/true)) { - insertionText = insertionText.drop_back().drop_front(); - } - } - S.Diag(pointerLoc, diag::warn_nullability_inferred_on_nested_type) << static_cast(complainAboutInferringWithinChunk) - << FixItHint::CreateInsertion(fixItLoc, insertionText); + << fixItNullability(S, pointerLoc, NullabilityKind::NonNull); } if (inferNullabilityInnerOnly) Index: test/FixIt/Inputs/nullability.h =================================================================== --- /dev/null +++ test/FixIt/Inputs/nullability.h @@ -0,0 +1,19 @@ +int * _Nonnull forceNullabilityWarnings(void); + +void arrayParameter(int x[]); // expected-warning {{array parameter is missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable'}} +// expected-note@-2 {{insert '_Nonnull'}} +// CHECK: fix-it:"{{.*}}nullability.h":{[[@LINE-3]]:27-[[@LINE-3]]:27}:"_Nullable" +// CHECK: fix-it:"{{.*}}nullability.h":{[[@LINE-4]]:27-[[@LINE-4]]:27}:"_Nonnull" + +void arrayParameterWithSize(int x[5]); // expected-warning {{array parameter is missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable'}} +// expected-note@-2 {{insert '_Nonnull'}} +// CHECK: fix-it:"{{.*}}nullability.h":{[[@LINE-3]]:35-[[@LINE-3]]:35}:"_Nullable " +// CHECK: fix-it:"{{.*}}nullability.h":{[[@LINE-4]]:35-[[@LINE-4]]:35}:"_Nonnull " + +void arrayParameterWithStar(int x[*]); // expected-warning {{array parameter is missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable'}} +// expected-note@-2 {{insert '_Nonnull'}} +// CHECK: fix-it:"{{.*}}nullability.h":{[[@LINE-3]]:35-[[@LINE-3]]:35}:"_Nullable " +// CHECK: fix-it:"{{.*}}nullability.h":{[[@LINE-4]]:35-[[@LINE-4]]:35}:"_Nonnull " Index: test/FixIt/nullability.mm =================================================================== --- test/FixIt/nullability.mm +++ test/FixIt/nullability.mm @@ -1,59 +1,63 @@ -// RUN: %clang_cc1 -fsyntax-only -fblocks -std=gnu++11 -verify %s -// RUN: not %clang_cc1 -fdiagnostics-parseable-fixits -fblocks -std=gnu++11 %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -fsyntax-only -fblocks -std=gnu++11 -I %S/Inputs -verify %s +// RUN: not %clang_cc1 -fdiagnostics-parseable-fixits -fblocks -std=gnu++11 -I %S/Inputs %s >%t.txt 2>&1 +// RUN: FileCheck %s < %t.txt +// RUN: FileCheck %S/Inputs/nullability.h < %t.txt + +#include "nullability.h" #pragma clang assume_nonnull begin extern void *array[2]; // expected-warning {{inferring '_Nonnull' for pointer type within array is deprecated}} -// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:14-[[@LINE-1]]:14}:" _Nonnull " +// CHECK: fix-it:"{{.*}}nullability.mm":{[[@LINE-1]]:14-[[@LINE-1]]:14}:" _Nonnull " extern void* array2[2]; // expected-warning {{inferring '_Nonnull' for pointer type within array is deprecated}} -// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:13}:" _Nonnull" +// CHECK: fix-it:"{{.*}}nullability.mm":{[[@LINE-1]]:13-[[@LINE-1]]:13}:" _Nonnull" extern void *nestedArray[2][3]; // expected-warning {{inferring '_Nonnull' for pointer type within array is deprecated}} -// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:14-[[@LINE-1]]:14}:" _Nonnull " +// CHECK: fix-it:"{{.*}}nullability.mm":{[[@LINE-1]]:14-[[@LINE-1]]:14}:" _Nonnull " typedef const void *CFTypeRef; extern CFTypeRef typedefArray[2]; // expected-warning {{inferring '_Nonnull' for pointer type within array is deprecated}} -// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:17-[[@LINE-1]]:17}:" _Nonnull" +// CHECK: fix-it:"{{.*}}nullability.mm":{[[@LINE-1]]:17-[[@LINE-1]]:17}:" _Nonnull" extern void *&ref; // expected-warning {{inferring '_Nonnull' for pointer type within reference is deprecated}} -// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:14-[[@LINE-1]]:14}:"_Nonnull" +// CHECK: fix-it:"{{.*}}nullability.mm":{[[@LINE-1]]:14-[[@LINE-1]]:14}:"_Nonnull" extern void * &ref2; // expected-warning {{inferring '_Nonnull' for pointer type within reference is deprecated}} -// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:14-[[@LINE-1]]:14}:" _Nonnull" +// CHECK: fix-it:"{{.*}}nullability.mm":{[[@LINE-1]]:14-[[@LINE-1]]:14}:" _Nonnull" extern void *&&ref3; // expected-warning {{inferring '_Nonnull' for pointer type within reference is deprecated}} -// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:14-[[@LINE-1]]:14}:"_Nonnull" +// CHECK: fix-it:"{{.*}}nullability.mm":{[[@LINE-1]]:14-[[@LINE-1]]:14}:"_Nonnull" extern void * &&ref4; // expected-warning {{inferring '_Nonnull' for pointer type within reference is deprecated}} -// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:14-[[@LINE-1]]:14}:" _Nonnull" +// CHECK: fix-it:"{{.*}}nullability.mm":{[[@LINE-1]]:14-[[@LINE-1]]:14}:" _Nonnull" extern void *(&arrayRef)[2]; // expected-warning {{inferring '_Nonnull' for pointer type within array is deprecated}} -// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:14-[[@LINE-1]]:14}:"_Nonnull" +// CHECK: fix-it:"{{.*}}nullability.mm":{[[@LINE-1]]:14-[[@LINE-1]]:14}:"_Nonnull" extern void * (&arrayRef2)[2]; // expected-warning {{inferring '_Nonnull' for pointer type within array is deprecated}} -// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:14-[[@LINE-1]]:14}:" _Nonnull" +// CHECK: fix-it:"{{.*}}nullability.mm":{[[@LINE-1]]:14-[[@LINE-1]]:14}:" _Nonnull" extern CFTypeRef &typedefRef; // expected-warning {{inferring '_Nonnull' for pointer type within reference is deprecated}} -// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:17-[[@LINE-1]]:17}:" _Nonnull" +// CHECK: fix-it:"{{.*}}nullability.mm":{[[@LINE-1]]:17-[[@LINE-1]]:17}:" _Nonnull" extern CFTypeRef& typedefRef2; // expected-warning {{inferring '_Nonnull' for pointer type within reference is deprecated}} -// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:17-[[@LINE-1]]:17}:" _Nonnull " +// CHECK: fix-it:"{{.*}}nullability.mm":{[[@LINE-1]]:17-[[@LINE-1]]:17}:" _Nonnull " void arrayNameless(void *[]); // expected-warning {{inferring '_Nonnull' for pointer type within array is deprecated}} -// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:26-[[@LINE-1]]:26}:"_Nonnull" +// CHECK: fix-it:"{{.*}}nullability.mm":{[[@LINE-1]]:26-[[@LINE-1]]:26}:"_Nonnull" void arrayNameless2(void * []); // expected-warning {{inferring '_Nonnull' for pointer type within array is deprecated}} -// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:27-[[@LINE-1]]:27}:" _Nonnull" +// CHECK: fix-it:"{{.*}}nullability.mm":{[[@LINE-1]]:27-[[@LINE-1]]:27}:" _Nonnull" void arrayNamelessTypedef(CFTypeRef[]); // expected-warning {{inferring '_Nonnull' for pointer type within array is deprecated}} -// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:36-[[@LINE-1]]:36}:" _Nonnull " +// CHECK: fix-it:"{{.*}}nullability.mm":{[[@LINE-1]]:36-[[@LINE-1]]:36}:" _Nonnull " void arrayNamelessTypedef2(CFTypeRef []); // expected-warning {{inferring '_Nonnull' for pointer type within array is deprecated}} -// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:37-[[@LINE-1]]:37}:" _Nonnull" +// CHECK: fix-it:"{{.*}}nullability.mm":{[[@LINE-1]]:37-[[@LINE-1]]:37}:" _Nonnull" extern int (*pointerToArray)[2]; // no-warning Index: test/SemaObjCXX/Inputs/nullability-consistency-1.h =================================================================== --- test/SemaObjCXX/Inputs/nullability-consistency-1.h +++ test/SemaObjCXX/Inputs/nullability-consistency-1.h @@ -1,22 +1,32 @@ void f1(int *ptr); // expected-warning{{pointer is missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-2 {{insert '_Nonnull' if the pointer should never be null}} void f2(int * _Nonnull); #include "nullability-consistency-2.h" void f3(int *ptr) { // expected-warning{{pointer is missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-2 {{insert '_Nonnull' if the pointer should never be null}} int *other = ptr; // shouldn't warn } class X { void mf(int *ptr); // expected-warning{{pointer is missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-2 {{insert '_Nonnull' if the pointer should never be null}} int X:: *memptr; // expected-warning{{member pointer is missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable' if the member pointer may be null}} +// expected-note@-2 {{insert '_Nonnull' if the member pointer should never be null}} }; template struct Typedefs { typedef T *Base; // no-warning typedef Base *type; // expected-warning{{pointer is missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-2 {{insert '_Nonnull' if the pointer should never be null}} }; Typedefs xx; Index: test/SemaObjCXX/Inputs/nullability-consistency-2.h =================================================================== --- test/SemaObjCXX/Inputs/nullability-consistency-2.h +++ test/SemaObjCXX/Inputs/nullability-consistency-2.h @@ -1,11 +1,17 @@ void g1(int * _Nonnull); void g2(int (^block)(int, int)); // expected-warning{{block pointer is missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable' if the block pointer may be null}} +// expected-note@-2 {{insert '_Nonnull' if the block pointer should never be null}} void g3(const id // expected-warning{{missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-2 {{insert '_Nonnull' if the pointer should never be null}} volatile * // expected-warning{{missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-2 {{insert '_Nonnull' if the pointer should never be null}} ); @interface SomeClass @@ -14,8 +20,12 @@ - (nullable SomeClass *)method1; - (void)method2:(nonnull SomeClass *)param; @property (readonly, weak) SomeClass *property3; // expected-warning{{missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-2 {{insert '_Nonnull' if the pointer should never be null}} @end @interface SomeClass () @property (readonly, weak) SomeClass *property4; // expected-warning{{missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-2 {{insert '_Nonnull' if the pointer should never be null}} @end Index: test/SemaObjCXX/Inputs/nullability-consistency-3.h =================================================================== --- test/SemaObjCXX/Inputs/nullability-consistency-3.h +++ test/SemaObjCXX/Inputs/nullability-consistency-3.h @@ -1 +1,3 @@ void double_declarator1(int *_Nonnull *); // expected-warning{{pointer is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)}} +// expected-note@-1 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-2 {{insert '_Nonnull' if the pointer should never be null}} Index: test/SemaObjCXX/Inputs/nullability-consistency-4.h =================================================================== --- test/SemaObjCXX/Inputs/nullability-consistency-4.h +++ test/SemaObjCXX/Inputs/nullability-consistency-4.h @@ -1 +1,3 @@ void double_declarator1(int * * _Nonnull); // expected-warning{{pointer is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)}} +// expected-note@-1 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-2 {{insert '_Nonnull' if the pointer should never be null}} Index: test/SemaObjCXX/Inputs/nullability-consistency-5.h =================================================================== --- test/SemaObjCXX/Inputs/nullability-consistency-5.h +++ test/SemaObjCXX/Inputs/nullability-consistency-5.h @@ -7,6 +7,8 @@ void suppress1(SUPPRESS_NULLABILITY_WARNING(int *) ptr); // no warning void shouldwarn5(int *ptr); //expected-warning{{missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-2 {{insert '_Nonnull' if the pointer should never be null}} void trigger5(int * _Nonnull); Index: test/SemaObjCXX/Inputs/nullability-consistency-6.h =================================================================== --- test/SemaObjCXX/Inputs/nullability-consistency-6.h +++ test/SemaObjCXX/Inputs/nullability-consistency-6.h @@ -1,8 +1,11 @@ int *ptr; // expected-warning {{missing a nullability type specifier}} - +// expected-note@-1{{insert '_Nullable' if the pointer may be null}} +// expected-note@-2{{insert '_Nonnull' if the pointer should never be null}} #pragma clang assume_nonnull begin extern void **blah; // expected-warning 2{{missing a nullability type specifier}} +// expected-note@-1 2 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-2 2 {{insert '_Nonnull' if the pointer should never be null}} __attribute__((objc_root_class)) @interface ClassWithWeakProperties Index: test/SemaObjCXX/Inputs/nullability-consistency-7.h =================================================================== --- test/SemaObjCXX/Inputs/nullability-consistency-7.h +++ test/SemaObjCXX/Inputs/nullability-consistency-7.h @@ -33,7 +33,11 @@ @interface C : A - (instancetype)init; // expected-warning{{pointer is missing a nullability type specifier}} +// expected-note@-1{{insert '_Nullable' if the pointer may be null}} +// expected-note@-2{{insert '_Nonnull' if the pointer should never be null}} - (instancetype)initWithA:( A*)a __attribute__((objc_designated_initializer)); // expected-warning 2{{pointer is missing a nullability type specifier}} +// expected-note@-1 2{{insert '_Nullable' if the pointer may be null}} +// expected-note@-2 2{{insert '_Nonnull' if the pointer should never be null}} @end #endif Index: test/SemaObjCXX/Inputs/nullability-consistency-8.h =================================================================== --- test/SemaObjCXX/Inputs/nullability-consistency-8.h +++ test/SemaObjCXX/Inputs/nullability-consistency-8.h @@ -8,10 +8,14 @@ void func2(mynonnull i); void func3(int *); // expected-warning{{pointer is missing a nullability type specifier}} +// expected-note@-1{{insert '_Nullable' if the pointer may be null}} +// expected-note@-2{{insert '_Nonnull' if the pointer should never be null}} #define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained)) typedef void *CFTypeRef; -void cf1(CFTypeRef * p CF_RETURNS_NOT_RETAINED); // expected-warning {{pointer is missing a nullability type specifier}} +void cf1(CFTypeRef * p CF_RETURNS_NOT_RETAINED); // expected-warning{{pointer is missing a nullability type specifier}} +// expected-note@-1{{insert '_Nullable' if the pointer may be null}} +// expected-note@-2{{insert '_Nonnull' if the pointer should never be null}} void cf2(CFTypeRef * _Nullable p CF_RETURNS_NOT_RETAINED); void cf3(CFTypeRef * _Nonnull p CF_RETURNS_NOT_RETAINED); @@ -23,5 +27,7 @@ void cf7(CF_RETURNS_NOT_RETAINED CFTypeRef * _Nonnull p); typedef CFTypeRef _Nullable *CFTypeRefPtr; -void cfp1(CFTypeRefPtr p CF_RETURNS_NOT_RETAINED); // expected-warning {{pointer is missing a nullability type specifier}} +void cfp1(CFTypeRefPtr p CF_RETURNS_NOT_RETAINED); // expected-warning{{pointer is missing a nullability type specifier}} +// expected-note@-1{{insert '_Nullable' if the pointer may be null}} +// expected-note@-2{{insert '_Nonnull' if the pointer should never be null}} void cfp2(CFTypeRefPtr _Nonnull p CF_RETURNS_NOT_RETAINED); Index: test/SemaObjCXX/Inputs/nullability-consistency-arrays.h =================================================================== --- test/SemaObjCXX/Inputs/nullability-consistency-arrays.h +++ test/SemaObjCXX/Inputs/nullability-consistency-arrays.h @@ -2,12 +2,16 @@ void firstThingInTheFileThatNeedsNullabilityIsAnArray(int ints[]); #if ARRAYS_CHECKED -// expected-warning@-2 {{array parameter is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)}} +// expected-warning@-2 {{array parameter is missing a nullability type specifier}} +// expected-note@-3 {{insert '_Nullable' if the array parameter may be null}} +// expected-note@-4 {{insert '_Nonnull' if the array parameter should never be null}} #endif int *secondThingInTheFileThatNeedsNullabilityIsAPointer; #if !ARRAYS_CHECKED // expected-warning@-2 {{pointer is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)}} +// expected-note@-3 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-4 {{insert '_Nonnull' if the pointer should never be null}} #endif int *_Nonnull triggerConsistencyWarnings; @@ -15,21 +19,35 @@ void test( int ints[], #if ARRAYS_CHECKED -// expected-warning@-2 {{array parameter is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)}} +// expected-warning@-2 {{array parameter is missing a nullability type specifier}} +// expected-note@-3 {{insert '_Nullable' if the array parameter may be null}} +// expected-note@-4 {{insert '_Nonnull' if the array parameter should never be null}} #endif void *ptrs[], // expected-warning {{pointer is missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-2 {{insert '_Nonnull' if the pointer should never be null}} #if ARRAYS_CHECKED -// expected-warning@-2 {{array parameter is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)}} +// expected-warning@-4 {{array parameter is missing a nullability type specifier}} +// expected-note@-5 {{insert '_Nullable' if the array parameter may be null}} +// expected-note@-6 {{insert '_Nonnull' if the array parameter should never be null}} #endif void **nestedPtrs[]); // expected-warning 2 {{pointer is missing a nullability type specifier}} +// expected-note@-1 2 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-2 2 {{insert '_Nonnull' if the pointer should never be null}} #if ARRAYS_CHECKED -// expected-warning@-2 {{array parameter is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)}} +// expected-warning@-4 {{array parameter is missing a nullability type specifier}} +// expected-note@-5 {{insert '_Nullable' if the array parameter may be null}} +// expected-note@-6 {{insert '_Nonnull' if the array parameter should never be null}} #endif void testArraysOK( int ints[_Nonnull], void *ptrs[_Nonnull], // expected-warning {{pointer is missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-2 {{insert '_Nonnull' if the pointer should never be null}} void **nestedPtrs[_Nonnull]); // expected-warning 2 {{pointer is missing a nullability type specifier}} +// expected-note@-1 2 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-2 2 {{insert '_Nonnull' if the pointer should never be null}} void testAllOK( int ints[_Nonnull], void * _Nullable ptrs[_Nonnull], @@ -57,7 +75,9 @@ void nestedArrays(int x[5][1]) {} #if ARRAYS_CHECKED -// expected-warning@-2 {{array parameter is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)}} +// expected-warning@-2 {{array parameter is missing a nullability type specifier}} +// expected-note@-3 {{insert '_Nullable' if the array parameter may be null}} +// expected-note@-4 {{insert '_Nonnull' if the array parameter should never be null}} #endif void nestedArraysOK(int x[_Nonnull 5][1]) {} @@ -72,13 +92,17 @@ void typedefTest( INTS x, #if ARRAYS_CHECKED -// expected-warning@-2 {{array parameter is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)}} +// expected-warning@-2 {{array parameter is missing a nullability type specifier}} +// expected-note@-3 {{insert '_Nullable' if the array parameter may be null}} +// expected-note@-4 {{insert '_Nonnull' if the array parameter should never be null}} #endif INTS _Nonnull x2, _Nonnull INTS x3, INTS y[2], #if ARRAYS_CHECKED -// expected-warning@-2 {{array parameter is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)}} +// expected-warning@-2 {{array parameter is missing a nullability type specifier}} +// expected-note@-3 {{insert '_Nullable' if the array parameter may be null}} +// expected-note@-4 {{insert '_Nonnull' if the array parameter should never be null}} #endif INTS y2[_Nonnull 2]); @@ -87,15 +111,23 @@ void testAssumeNonnull( int ints[], #if ARRAYS_CHECKED -// expected-warning@-2 {{array parameter is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)}} +// expected-warning@-2 {{array parameter is missing a nullability type specifier}} +// expected-note@-3 {{insert '_Nullable' if the array parameter may be null}} +// expected-note@-4 {{insert '_Nonnull' if the array parameter should never be null}} #endif void *ptrs[], #if ARRAYS_CHECKED -// expected-warning@-2 {{array parameter is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)}} +// expected-warning@-2 {{array parameter is missing a nullability type specifier}} +// expected-note@-3 {{insert '_Nullable' if the array parameter may be null}} +// expected-note@-4 {{insert '_Nonnull' if the array parameter should never be null}} #endif void **nestedPtrs[]); // expected-warning 2 {{pointer is missing a nullability type specifier}} +// expected-note@-1 2 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-2 2 {{insert '_Nonnull' if the pointer should never be null}} #if ARRAYS_CHECKED -// expected-warning@-2 {{array parameter is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)}} +// expected-warning@-4 {{array parameter is missing a nullability type specifier}} +// expected-note@-5 {{insert '_Nullable' if the array parameter may be null}} +// expected-note@-6 {{insert '_Nonnull' if the array parameter should never be null}} #endif void testAssumeNonnullAllOK( Index: test/SemaObjCXX/Inputs/nullability-consistency-system/nullability-consistency-system.h =================================================================== --- test/SemaObjCXX/Inputs/nullability-consistency-system/nullability-consistency-system.h +++ test/SemaObjCXX/Inputs/nullability-consistency-system/nullability-consistency-system.h @@ -3,6 +3,8 @@ void system1(int *ptr); #if WARN_IN_SYSTEM_HEADERS // expected-warning@-2{{pointer is missing a nullability type specifier}} +// expected-note@-3 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-4 {{insert '_Nonnull' if the pointer should never be null}} #endif void system2(int * _Nonnull); Index: test/SemaObjCXX/Inputs/nullability-pragmas-1.h =================================================================== --- test/SemaObjCXX/Inputs/nullability-pragmas-1.h +++ test/SemaObjCXX/Inputs/nullability-pragmas-1.h @@ -9,6 +9,8 @@ struct X { }; void f1(int *x); // expected-warning{{pointer is missing a nullability type specifier}} +// expected-note@-1{{insert '_Nullable' if the pointer may be null}} +// expected-note@-2{{insert '_Nonnull' if the pointer should never be null}} typedef struct __attribute__((objc_bridge(NSError))) __CFError *CFErrorRef; typedef NSError *NSErrorPtr; @@ -39,15 +41,29 @@ A * _Null_unspecified f16(void); void f17(CFErrorRef *error); // expected-note{{no known conversion from 'A * _Nonnull' to 'CFErrorRef _Nullable * _Nullable' (aka '__CFError **') for 1st argument}} void f18(A **); // expected-warning 2{{pointer is missing a nullability type specifier}} +// expected-note@-1 2 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-2 2 {{insert '_Nonnull' if the pointer should never be null}} void f19(CFErrorRefPtr error); // expected-warning{{pointer is missing a nullability type specifier}} +// expected-note@-1{{insert '_Nullable' if the pointer may be null}} +// expected-note@-2{{insert '_Nonnull' if the pointer should never be null}} void g1(int (^)(int, int)); void g2(int (^ *bp)(int, int)); // expected-warning{{block pointer is missing a nullability type specifier}} -// expected-warning@-1{{pointer is missing a nullability type specifier}} +// expected-note@-1{{insert '_Nullable' if the block pointer may be null}} +// expected-note@-2{{insert '_Nonnull' if the block pointer should never be null}} +// expected-warning@-3{{pointer is missing a nullability type specifier}} +// expected-note@-4{{insert '_Nullable' if the pointer may be null}} +// expected-note@-5{{insert '_Nonnull' if the pointer should never be null}} void g3(block_ptr *bp); // expected-warning{{block pointer is missing a nullability type specifier}} -// expected-warning@-1{{pointer is missing a nullability type specifier}} +// expected-note@-1{{insert '_Nullable' if the block pointer may be null}} +// expected-note@-2{{insert '_Nonnull' if the block pointer should never be null}} +// expected-warning@-3{{pointer is missing a nullability type specifier}} +// expected-note@-4{{insert '_Nullable' if the pointer may be null}} +// expected-note@-5{{insert '_Nonnull' if the pointer should never be null}} void g4(int (*fp)(int, int)); void g5(int (**fp)(int, int)); // expected-warning 2{{pointer is missing a nullability type specifier}} +// expected-note@-1 2 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-2 2 {{insert '_Nonnull' if the pointer should never be null}} @interface A(Pragmas1) + (instancetype)aWithA:(A *)a; @@ -57,9 +73,13 @@ - (void)method4:(NSErrorPtr *)error; // expected-note{{passing argument to parameter 'error' here}} - (void)method5:(NSErrorPtrPtr)error; // expected-warning@-1{{pointer is missing a nullability type specifier}} +// expected-note@-2{{insert '_Nullable' if the pointer may be null}} +// expected-note@-3{{insert '_Nonnull' if the pointer should never be null}} @property A *aProp; @property NSError **anError; // expected-warning 2{{pointer is missing a nullability type specifier}} +// expected-note@-1 2 {{insert '_Nullable' if the pointer may be null}} +// expected-note@-2 2 {{insert '_Nonnull' if the pointer should never be null}} @end int *global_int_ptr; @@ -68,6 +88,8 @@ typedef int *int_ptr_2; typedef int * // expected-warning{{pointer is missing a nullability type specifier}} +// expected-note@-1{{insert '_Nullable' if the pointer may be null}} +// expected-note@-2{{insert '_Nonnull' if the pointer should never be null}} *int_ptr_ptr; static inline void f30(void) { @@ -90,12 +112,22 @@ #pragma clang assume_nonnull end void f20(A *a); // expected-warning{{pointer is missing a nullability type specifier}} +// expected-note@-1{{insert '_Nullable' if the pointer may be null}} +// expected-note@-2{{insert '_Nonnull' if the pointer should never be null}} void f21(int_ptr x); // expected-warning{{pointer is missing a nullability type specifier}} +// expected-note@-1{{insert '_Nullable' if the pointer may be null}} +// expected-note@-2{{insert '_Nonnull' if the pointer should never be null}} void f22(A_ptr y); // expected-warning{{pointer is missing a nullability type specifier}} +// expected-note@-1{{insert '_Nullable' if the pointer may be null}} +// expected-note@-2{{insert '_Nonnull' if the pointer should never be null}} void f23(int_ptr _Nullable x); void f24(A_ptr _Nullable y); void f25(int_ptr_2 x); // expected-warning{{pointer is missing a nullability type specifier}} +// expected-note@-1{{insert '_Nullable' if the pointer may be null}} +// expected-note@-2{{insert '_Nonnull' if the pointer should never be null}} @interface A(OutsidePragmas1) + (instancetype)aWithInt:(int)value; // expected-warning{{pointer is missing a nullability type specifier}} +// expected-note@-1{{insert '_Nullable' if the pointer may be null}} +// expected-note@-2{{insert '_Nonnull' if the pointer should never be null}} @end