[Sema] Put nullability fix-it after the end of the pointer.

Fixes nullability fix-it for `id<SomeProtocol>`. With this change
nullability specifier is inserted after ">" instead of between
"id" and "<".

rdar://problem/34260995

Reviewers: jordan_rose, doug.gregor, ahatanak, arphaman

Reviewed By: jordan_rose

Subscribers: cfe-commits

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

llvm-svn: 314473
This commit is contained in:
Volodymyr Sapsai 2017-09-28 23:18:49 +00:00
parent 99ead70fea
commit 43e6f7bee5
5 changed files with 77 additions and 16 deletions

View File

@ -229,6 +229,10 @@ struct FileNullability {
/// 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;

View File

@ -3500,7 +3500,8 @@ static void fixItNullability(Sema &S, DiagnosticBuilder &Diag,
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 void emitNullabilityConsistencyWarning(Sema &S,
<< static_cast<unsigned>(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<unsigned>(Nullability);
Diag << static_cast<unsigned>(PointerKind);
fixItNullability(S, Diag, PointerLoc, Nullability);
fixItNullability(S, Diag, FixItLoc, Nullability);
};
addFixIt(NullabilityKind::Nullable);
addFixIt(NullabilityKind::NonNull);
@ -3529,9 +3531,10 @@ static void emitNullabilityConsistencyWarning(Sema &S,
///
/// 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 @@ static void checkNullabilityConsistency(Sema &S,
if (fileNullability.PointerLoc.isInvalid() &&
!S.Context.getDiagnostics().isIgnored(diagKind, pointerLoc)) {
fileNullability.PointerLoc = pointerLoc;
fileNullability.PointerEndLoc = pointerEndLoc;
fileNullability.PointerKind = static_cast<unsigned>(pointerKind);
}
@ -3559,7 +3563,7 @@ static void checkNullabilityConsistency(Sema &S,
}
// 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 @@ static void recordNullabilitySeen(Sema &S, SourceLocation loc) {
return;
auto kind = static_cast<SimplePointerKind>(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 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// 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 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Fallthrough.
case CAMN_Yes:
checkNullabilityConsistency(S, pointerKind, pointerLoc);
checkNullabilityConsistency(S, pointerKind, pointerLoc, pointerEndLoc);
}
return nullptr;
};
@ -3973,6 +3979,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
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 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
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 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Handle pointer nullability
inferPointerNullability(SimplePointerKind::Pointer, DeclType.Loc,
DeclType.getAttrListRef());
DeclType.EndLoc, DeclType.getAttrListRef());
if (LangOpts.ObjC1 && T->getAs<ObjCObjectType>()) {
T = Context.getObjCObjectPointerType(T);
@ -4530,8 +4537,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
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.

View File

@ -0,0 +1,48 @@
@class Item;
@class Container<ObjectType>;
@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<Protocol> 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<Protocol> *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<Protocol> 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<Item *> *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<id<Protocol>> *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 "

View File

@ -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

View File

@ -6,9 +6,9 @@ void g2(int (^block)(int, int)); // expected-warning{{block pointer is missing a
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}}