diff options
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/AST/DeclPrinter.cpp | 10 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseObjc.cpp | 11 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclObjC.cpp | 3 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaObjCProperty.cpp | 62 |
4 files changed, 82 insertions, 4 deletions
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 609cc08545a..d6c03169d9c 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -1213,8 +1213,14 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { 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; } } diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index e0f716e82f2..83236602df7 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -611,6 +611,7 @@ static void diagnoseRedundantPropertyNullability(Parser &P, /// nonnull /// nullable /// null_unspecified +/// null_resettable /// void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { assert(Tok.getKind() == tok::l_paren); @@ -717,6 +718,16 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { 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); diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 78c76abd4c7..62ba7d5633c 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -2024,6 +2024,9 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, 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()); diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index f62af8eb81d..d8e7f64836f 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -361,6 +361,9 @@ Sema::HandlePropertyInClassExtension(Scope *S, 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::CreatePropertyDecl(Scope *S, 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::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, } } +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(ObjCPropertyDecl *property, 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(ObjCPropertyDecl *property, 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); |

