Index: cfe/trunk/include/clang/Sema/Sema.h =================================================================== --- cfe/trunk/include/clang/Sema/Sema.h +++ cfe/trunk/include/clang/Sema/Sema.h @@ -229,6 +229,10 @@ /// not have a corresponding nullability annotation. SourceLocation PointerLoc; + /// The end location for the first pointer declarator in the file. Used for + /// placing fix-its. + SourceLocation PointerEndLoc; + /// Which kind of pointer declarator we saw. uint8_t PointerKind; Index: cfe/trunk/lib/Sema/SemaType.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaType.cpp +++ cfe/trunk/lib/Sema/SemaType.cpp @@ -3500,7 +3500,8 @@ static void emitNullabilityConsistencyWarning(Sema &S, SimplePointerKind PointerKind, - SourceLocation PointerLoc) { + SourceLocation PointerLoc, + SourceLocation PointerEndLoc) { assert(PointerLoc.isValid()); if (PointerKind == SimplePointerKind::Array) { @@ -3510,14 +3511,15 @@ << static_cast(PointerKind); } - if (PointerLoc.isMacroID()) + auto FixItLoc = PointerEndLoc.isValid() ? PointerEndLoc : PointerLoc; + if (FixItLoc.isMacroID()) return; auto addFixIt = [&](NullabilityKind Nullability) { - auto Diag = S.Diag(PointerLoc, diag::note_nullability_fix_it); + auto Diag = S.Diag(FixItLoc, diag::note_nullability_fix_it); Diag << static_cast(Nullability); Diag << static_cast(PointerKind); - fixItNullability(S, Diag, PointerLoc, Nullability); + fixItNullability(S, Diag, FixItLoc, Nullability); }; addFixIt(NullabilityKind::Nullable); addFixIt(NullabilityKind::NonNull); @@ -3529,9 +3531,10 @@ /// /// If the file has \e not seen other uses of nullability, this particular /// pointer is saved for possible later diagnosis. See recordNullabilitySeen(). -static void checkNullabilityConsistency(Sema &S, - SimplePointerKind pointerKind, - SourceLocation pointerLoc) { +static void +checkNullabilityConsistency(Sema &S, SimplePointerKind pointerKind, + SourceLocation pointerLoc, + SourceLocation pointerEndLoc = SourceLocation()) { // Determine which file we're performing consistency checking for. FileID file = getNullabilityCompletenessCheckFileID(S, pointerLoc); if (file.isInvalid()) @@ -3552,6 +3555,7 @@ if (fileNullability.PointerLoc.isInvalid() && !S.Context.getDiagnostics().isIgnored(diagKind, pointerLoc)) { fileNullability.PointerLoc = pointerLoc; + fileNullability.PointerEndLoc = pointerEndLoc; fileNullability.PointerKind = static_cast(pointerKind); } @@ -3559,7 +3563,7 @@ } // Complain about missing nullability. - emitNullabilityConsistencyWarning(S, pointerKind, pointerLoc); + emitNullabilityConsistencyWarning(S, pointerKind, pointerLoc, pointerEndLoc); } /// Marks that a nullability feature has been used in the file containing @@ -3585,7 +3589,8 @@ return; auto kind = static_cast(fileNullability.PointerKind); - emitNullabilityConsistencyWarning(S, kind, fileNullability.PointerLoc); + emitNullabilityConsistencyWarning(S, kind, fileNullability.PointerLoc, + fileNullability.PointerEndLoc); } /// Returns true if any of the declarator chunks before \p endIndex include a @@ -3895,6 +3900,7 @@ // Returns true if _Nonnull was inferred. auto inferPointerNullability = [&](SimplePointerKind pointerKind, SourceLocation pointerLoc, + SourceLocation pointerEndLoc, AttributeList *&attrs) -> AttributeList * { // We've seen a pointer. if (NumPointersRemaining > 0) @@ -3950,7 +3956,7 @@ // Fallthrough. case CAMN_Yes: - checkNullabilityConsistency(S, pointerKind, pointerLoc); + checkNullabilityConsistency(S, pointerKind, pointerLoc, pointerEndLoc); } return nullptr; }; @@ -3973,6 +3979,7 @@ if (auto *attr = inferPointerNullability( pointerKind, D.getDeclSpec().getTypeSpecTypeLoc(), + D.getDeclSpec().getLocEnd(), D.getMutableDeclSpec().getAttributes().getListRef())) { T = Context.getAttributedType( AttributedType::getNullabilityAttrKind(*inferNullability),T,T); @@ -4008,8 +4015,8 @@ S.Diag(DeclType.Loc, diag::err_blocks_disable) << LangOpts.OpenCL; // Handle pointer nullability. - inferPointerNullability(SimplePointerKind::BlockPointer, - DeclType.Loc, DeclType.getAttrListRef()); + inferPointerNullability(SimplePointerKind::BlockPointer, DeclType.Loc, + DeclType.EndLoc, DeclType.getAttrListRef()); T = S.BuildBlockPointerType(T, D.getIdentifierLoc(), Name); if (DeclType.Cls.TypeQuals || LangOpts.OpenCL) { @@ -4031,7 +4038,7 @@ // Handle pointer nullability inferPointerNullability(SimplePointerKind::Pointer, DeclType.Loc, - DeclType.getAttrListRef()); + DeclType.EndLoc, DeclType.getAttrListRef()); if (LangOpts.ObjC1 && T->getAs()) { T = Context.getObjCObjectPointerType(T); @@ -4530,8 +4537,8 @@ QualType ClsType; // Handle pointer nullability. - inferPointerNullability(SimplePointerKind::MemberPointer, - DeclType.Loc, DeclType.getAttrListRef()); + inferPointerNullability(SimplePointerKind::MemberPointer, DeclType.Loc, + DeclType.EndLoc, DeclType.getAttrListRef()); if (SS.isInvalid()) { // Avoid emitting extra errors if we already errored on the scope. Index: cfe/trunk/test/FixIt/Inputs/nullability-objc.h =================================================================== --- cfe/trunk/test/FixIt/Inputs/nullability-objc.h +++ cfe/trunk/test/FixIt/Inputs/nullability-objc.h @@ -0,0 +1,48 @@ +@class Item; +@class Container; +@protocol Protocol; + +// rdar://problem/34260995 +// The first pointer in the file is handled in a different way so need +// a separate test for this case even if the parameter type is the same as in +// objcIdParameterWithProtocol. +void objcIdParameterWithProtocolFirstInFile(id i); // expected-warning {{pointer is missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable'}} +// expected-note@-2 {{insert '_Nonnull'}} +// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-3]]:57-[[@LINE-3]]:57}:" _Nullable" +// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-4]]:57-[[@LINE-4]]:57}:" _Nonnull" + +int * _Nonnull forceNullabilityWarningsObjC(void); + +void objcClassParameter(Item *i); // expected-warning {{pointer is missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable'}} +// expected-note@-2 {{insert '_Nonnull'}} +// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-3]]:31-[[@LINE-3]]:31}:" _Nullable " +// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-4]]:31-[[@LINE-4]]:31}:" _Nonnull " + +void objcClassParameterWithProtocol(Item *i); // expected-warning {{pointer is missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable'}} +// expected-note@-2 {{insert '_Nonnull'}} +// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-3]]:53-[[@LINE-3]]:53}:" _Nullable " +// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-4]]:53-[[@LINE-4]]:53}:" _Nonnull " + +// rdar://problem/34260995 +void objcIdParameterWithProtocol(id i); // expected-warning {{pointer is missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable'}} +// expected-note@-2 {{insert '_Nonnull'}} +// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-3]]:46-[[@LINE-3]]:46}:" _Nullable" +// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-4]]:46-[[@LINE-4]]:46}:" _Nonnull" + +// Class parameters don't have nullability type specifier. +void objcParameterizedClassParameter(Container *c); // expected-warning {{pointer is missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable'}} +// expected-note@-2 {{insert '_Nonnull'}} +// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-3]]:57-[[@LINE-3]]:57}:" _Nullable " +// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-4]]:57-[[@LINE-4]]:57}:" _Nonnull " + +// Class parameters don't have nullability type specifier. +void objcParameterizedClassParameterWithProtocol(Container> *c); // expected-warning {{pointer is missing a nullability type specifier}} +// expected-note@-1 {{insert '_Nullable'}} +// expected-note@-2 {{insert '_Nonnull'}} +// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-3]]:75-[[@LINE-3]]:75}:" _Nullable " +// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-4]]:75-[[@LINE-4]]:75}:" _Nonnull " Index: cfe/trunk/test/FixIt/nullability.mm =================================================================== --- cfe/trunk/test/FixIt/nullability.mm +++ cfe/trunk/test/FixIt/nullability.mm @@ -2,8 +2,10 @@ // 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 +// RUN: FileCheck %S/Inputs/nullability-objc.h < %t.txt #include "nullability.h" +#include "nullability-objc.h" #pragma clang assume_nonnull begin Index: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-2.h =================================================================== --- cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-2.h +++ cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-2.h @@ -6,9 +6,9 @@ void g3(const id // expected-warning{{missing a nullability type specifier}} + volatile // 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}}