r240155 - Implement the 'null_resettable' attribute for Objective-C properties.
Douglas Gregor
dgregor at apple.com
Fri Jun 19 11:14:46 PDT 2015
Author: dgregor
Date: Fri Jun 19 13:14:46 2015
New Revision: 240155
URL: http://llvm.org/viewvc/llvm-project?rev=240155&view=rev
Log:
Implement the 'null_resettable' attribute for Objective-C properties.
'null_resettable' properties are those whose getters return nonnull
but whose setters take nil, to "reset" the property to some
default. Implements rdar://problem/19051334.
Modified:
cfe/trunk/include/clang/AST/DeclObjC.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/DeclSpec.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/AST/DeclPrinter.cpp
cfe/trunk/lib/Parse/ParseObjc.cpp
cfe/trunk/lib/Sema/SemaDeclObjC.cpp
cfe/trunk/lib/Sema/SemaObjCProperty.cpp
cfe/trunk/test/SemaObjC/nullability.m
Modified: cfe/trunk/include/clang/AST/DeclObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclObjC.h?rev=240155&r1=240154&r2=240155&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclObjC.h (original)
+++ cfe/trunk/include/clang/AST/DeclObjC.h Fri Jun 19 13:14:46 2015
@@ -2206,13 +2206,14 @@ public:
OBJC_PR_unsafe_unretained = 0x800,
/// Indicates that the nullability of the type was spelled with a
/// property attribute rather than a type qualifier.
- OBJC_PR_nullability = 0x1000
+ OBJC_PR_nullability = 0x1000,
+ OBJC_PR_null_resettable = 0x2000
// Adding a property should change NumPropertyAttrsBits
};
enum {
/// \brief Number of bits fitting all the property attributes.
- NumPropertyAttrsBits = 13
+ NumPropertyAttrsBits = 14
};
enum SetterKind { Assign, Retain, Copy, Weak };
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=240155&r1=240154&r2=240155&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jun 19 13:14:46 2015
@@ -7714,6 +7714,10 @@ def note_nullability_type_specifier : No
"'%select{__nonnull|__nullable|__null_unspecified}0' to affect the innermost "
"pointer type of %1">;
+def warn_null_resettable_setter : Warning<
+ "synthesized setter %0 for null_resettable property %1 does not handle nil">,
+ InGroup<Nullability>;
+
}
} // end of sema component.
Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=240155&r1=240154&r2=240155&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Sema/DeclSpec.h Fri Jun 19 13:14:46 2015
@@ -805,7 +805,8 @@ public:
DQ_PR_weak = 0x200,
DQ_PR_strong = 0x400,
DQ_PR_unsafe_unretained = 0x800,
- DQ_PR_nullability = 0x1000
+ DQ_PR_nullability = 0x1000,
+ DQ_PR_null_resettable = 0x2000
};
ObjCDeclSpec()
@@ -865,7 +866,7 @@ private:
ObjCDeclQualifier objcDeclQualifier : 7;
// NOTE: VC++ treats enums as signed, avoid using ObjCPropertyAttributeKind
- unsigned PropertyAttributes : 13;
+ unsigned PropertyAttributes : 14;
unsigned Nullability : 2;
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=240155&r1=240154&r2=240155&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Jun 19 13:14:46 2015
@@ -2918,6 +2918,9 @@ public:
ObjCContainerDecl *CDecl,
bool SynthesizeProperties);
+ /// Diagnose any null-resettable synthesized setters.
+ void diagnoseNullResettableSynthesizedSetters(ObjCImplDecl *impDecl);
+
/// DefaultSynthesizeProperties - This routine default synthesizes all
/// properties which must be synthesized in the class's \@implementation.
void DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl,
Modified: cfe/trunk/lib/AST/DeclPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclPrinter.cpp?rev=240155&r1=240154&r2=240155&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclPrinter.cpp (original)
+++ cfe/trunk/lib/AST/DeclPrinter.cpp Fri Jun 19 13:14:46 2015
@@ -1213,8 +1213,14 @@ void DeclPrinter::VisitObjCPropertyDecl(
if (PDecl->getPropertyAttributes() &
ObjCPropertyDecl::OBJC_PR_nullability) {
if (auto nullability = stripOuterNullability(T)) {
- Out << (first ? ' ' : ',')
- << getNullabilitySpelling(*nullability).substr(2);
+ if (*nullability == NullabilityKind::Unspecified &&
+ (PDecl->getPropertyAttributes() &
+ ObjCPropertyDecl::OBJC_PR_null_resettable)) {
+ Out << (first ? ' ' : ',') << "null_resettable";
+ } else {
+ Out << (first ? ' ' : ',')
+ << getNullabilitySpelling(*nullability).substr(2);
+ }
first = false;
}
}
Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=240155&r1=240154&r2=240155&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Fri Jun 19 13:14:46 2015
@@ -611,6 +611,7 @@ static void diagnoseRedundantPropertyNul
/// nonnull
/// nullable
/// null_unspecified
+/// null_resettable
///
void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
assert(Tok.getKind() == tok::l_paren);
@@ -717,6 +718,16 @@ void Parser::ParseObjCPropertyAttribute(
Tok.getLocation());
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability);
DS.setNullability(Tok.getLocation(), NullabilityKind::Unspecified);
+ } else if (II->isStr("null_resettable")) {
+ if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
+ diagnoseRedundantPropertyNullability(*this, DS,
+ NullabilityKind::Unspecified,
+ Tok.getLocation());
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability);
+ DS.setNullability(Tok.getLocation(), NullabilityKind::Unspecified);
+
+ // Also set the null_resettable bit.
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_null_resettable);
} else {
Diag(AttrName, diag::err_objc_expected_property_attr) << II;
SkipUntil(tok::r_paren, StopAtSemi);
Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=240155&r1=240154&r2=240155&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Fri Jun 19 13:14:46 2015
@@ -2024,6 +2024,9 @@ void Sema::ImplMethodsVsClassMethods(Sco
DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, SynthesizeProperties);
}
+ // Diagnose null-resettable synthesized setters.
+ diagnoseNullResettableSynthesizedSetters(IMPDecl);
+
SelectorSet ClsMap;
for (const auto *I : IMPDecl->class_methods())
ClsMap.insert(I->getSelector());
Modified: cfe/trunk/lib/Sema/SemaObjCProperty.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaObjCProperty.cpp?rev=240155&r1=240154&r2=240155&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaObjCProperty.cpp (original)
+++ cfe/trunk/lib/Sema/SemaObjCProperty.cpp Fri Jun 19 13:14:46 2015
@@ -361,6 +361,9 @@ Sema::HandlePropertyInClassExtension(Sco
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_atomic);
if (Attributes & ObjCDeclSpec::DQ_PR_nullability)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nullability);
+ if (Attributes & ObjCDeclSpec::DQ_PR_null_resettable)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_null_resettable);
+
// Set setter/getter selector name. Needed later.
PDecl->setGetterName(GetterSel);
PDecl->setSetterName(SetterSel);
@@ -646,6 +649,9 @@ ObjCPropertyDecl *Sema::CreatePropertyDe
if (Attributes & ObjCDeclSpec::DQ_PR_nullability)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nullability);
+ if (Attributes & ObjCDeclSpec::DQ_PR_null_resettable)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_null_resettable);
+
return PDecl;
}
@@ -1760,6 +1766,33 @@ void Sema::DiagnoseUnimplementedProperti
}
}
+void Sema::diagnoseNullResettableSynthesizedSetters(ObjCImplDecl *impDecl) {
+ for (const auto *propertyImpl : impDecl->property_impls()) {
+ const auto *property = propertyImpl->getPropertyDecl();
+
+ // Warn about null_resettable properties with synthesized setters,
+ // because the setter won't properly handle nil.
+ if (propertyImpl->getPropertyImplementation()
+ == ObjCPropertyImplDecl::Synthesize &&
+ (property->getPropertyAttributes() &
+ ObjCPropertyDecl::OBJC_PR_null_resettable) &&
+ property->getGetterMethodDecl() &&
+ property->getSetterMethodDecl()) {
+ auto *getterMethod = property->getGetterMethodDecl();
+ auto *setterMethod = property->getSetterMethodDecl();
+ if (!impDecl->getInstanceMethod(setterMethod->getSelector()) &&
+ !impDecl->getInstanceMethod(getterMethod->getSelector())) {
+ SourceLocation loc = propertyImpl->getLocation();
+ if (loc.isInvalid())
+ loc = impDecl->getLocStart();
+
+ Diag(loc, diag::warn_null_resettable_setter)
+ << setterMethod->getSelector() << property->getDeclName();
+ }
+ }
+ }
+}
+
void
Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
ObjCContainerDecl* IDecl) {
@@ -1995,9 +2028,21 @@ void Sema::ProcessPropertyDecl(ObjCPrope
redeclaredProperty->getLocation() :
property->getLocation();
+ // If the property is null_resettable, the getter returns nonnull.
+ QualType resultTy = property->getType();
+ if (property->getPropertyAttributes() &
+ ObjCPropertyDecl::OBJC_PR_null_resettable) {
+ QualType modifiedTy = resultTy;
+ if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)){
+ if (*nullability == NullabilityKind::Unspecified)
+ resultTy = Context.getAttributedType(AttributedType::attr_nonnull,
+ modifiedTy, modifiedTy);
+ }
+ }
+
GetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc,
property->getGetterName(),
- property->getType(), nullptr, CD,
+ resultTy, nullptr, CD,
/*isInstance=*/true, /*isVariadic=*/false,
/*isPropertyAccessor=*/true,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false,
@@ -2058,12 +2103,25 @@ void Sema::ProcessPropertyDecl(ObjCPrope
ObjCMethodDecl::Optional :
ObjCMethodDecl::Required);
+ // If the property is null_resettable, the setter accepts a
+ // nullable value.
+ QualType paramTy = property->getType().getUnqualifiedType();
+ if (property->getPropertyAttributes() &
+ ObjCPropertyDecl::OBJC_PR_null_resettable) {
+ QualType modifiedTy = paramTy;
+ if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)){
+ if (*nullability == NullabilityKind::Unspecified)
+ paramTy = Context.getAttributedType(AttributedType::attr_nullable,
+ modifiedTy, modifiedTy);
+ }
+ }
+
// Invent the arguments for the setter. We don't bother making a
// nice name for the argument.
ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod,
Loc, Loc,
property->getIdentifier(),
- property->getType().getUnqualifiedType(),
+ paramTy,
/*TInfo=*/nullptr,
SC_None,
nullptr);
Modified: cfe/trunk/test/SemaObjC/nullability.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/nullability.m?rev=240155&r1=240154&r2=240155&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/nullability.m (original)
+++ cfe/trunk/test/SemaObjC/nullability.m Fri Jun 19 13:14:46 2015
@@ -164,6 +164,45 @@ void test_instancetype(InitializableClas
ip = [InitializableClass returnInstanceOfMe]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'InitializableClass * __nullable'}}
ip = [object returnMe]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'id __nullable'}}
}
+
+// Check null_resettable getters/setters.
+__attribute__((objc_root_class))
+ at interface NSResettable
+ at property(null_resettable,retain) NSResettable *resettable1; // expected-note{{passing argument to parameter 'resettable1' here}}
+ at property(null_resettable,retain,nonatomic) NSResettable *resettable2;
+ at property(null_resettable,retain,nonatomic) NSResettable *resettable3;
+ at property(null_resettable,retain,nonatomic) NSResettable *resettable4;
+ at property(null_resettable,retain,nonatomic) NSResettable *resettable5;
+ at property(null_resettable,retain,nonatomic) NSResettable *resettable6;
+ at end
+
+void test_null_resettable(NSResettable *r, int *ip) {
+ [r setResettable1:ip]; // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'NSResettable * __nullable'}}
+ r.resettable1 = ip; // expected-warning{{incompatible pointer types assigning to 'NSResettable * __nullable' from 'int *'}}
+}
+
+ at implementation NSResettable // expected-warning{{synthesized setter 'setResettable4:' for null_resettable property 'resettable4' does not handle nil}}
+- (NSResettable *)resettable1 {
+ int *ip = 0;
+ return ip; // expected-warning{{result type 'NSResettable * __nonnull'}}
+}
+
+- (void)setResettable1:(NSResettable *)param {
+}
+
+ at synthesize resettable2; // no warning; not synthesized
+ at synthesize resettable3; // expected-warning{{synthesized setter 'setResettable3:' for null_resettable property 'resettable3' does not handle nil}}
+
+- (void)setResettable2:(NSResettable *)param {
+}
+
+ at dynamic resettable5;
+
+- (NSResettable *)resettable6 {
+ return 0; // no warning
+}
+ at end
+
// rdar://problem/19814852
@interface MultiProp
@property (nullable, copy) id a, b, c;
More information about the cfe-commits
mailing list