diff options
Diffstat (limited to 'lib/Sema/SemaObjCProperty.cpp')
-rw-r--r-- | lib/Sema/SemaObjCProperty.cpp | 115 |
1 files changed, 94 insertions, 21 deletions
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 5e7b4b8..87fb5b6 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -103,15 +103,6 @@ static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) { << propertyLifetime; } -static unsigned deduceWeakPropertyFromType(Sema &S, QualType T) { - if ((S.getLangOpts().getGC() != LangOptions::NonGC && - T.isObjCGCWeak()) || - (S.getLangOpts().ObjCAutoRefCount && - T.getObjCLifetime() == Qualifiers::OCL_Weak)) - return ObjCDeclSpec::DQ_PR_weak; - return 0; -} - /// \brief Check this Objective-C property against a property declared in the /// given protocol. static void @@ -146,10 +137,10 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC) { unsigned Attributes = ODS.getPropertyAttributes(); + FD.D.setObjCWeakProperty((Attributes & ObjCDeclSpec::DQ_PR_weak) != 0); TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S); QualType T = TSI->getType(); - Attributes |= deduceWeakPropertyFromType(*this, T); - + Attributes |= deduceWeakPropertyFromType(T); bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) || // default is readwrite! !(Attributes & ObjCDeclSpec::DQ_PR_readonly)); @@ -173,7 +164,7 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, isAssign, isReadWrite, Attributes, ODS.getPropertyAttributes(), - isOverridingProperty, TSI, + isOverridingProperty, T, TSI, MethodImplKind); if (!Res) return nullptr; @@ -184,7 +175,7 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD, GetterSel, SetterSel, isAssign, isReadWrite, Attributes, ODS.getPropertyAttributes(), - TSI, MethodImplKind); + T, TSI, MethodImplKind); if (lexicalDC) Res->setLexicalDeclContext(lexicalDC); } @@ -322,7 +313,8 @@ Sema::HandlePropertyInClassExtension(Scope *S, const unsigned Attributes, const unsigned AttributesAsWritten, bool *isOverridingProperty, - TypeSourceInfo *T, + QualType T, + TypeSourceInfo *TSI, tok::ObjCKeywordKind MethodImplKind) { ObjCCategoryDecl *CDecl = cast<ObjCCategoryDecl>(CurContext); // Diagnose if this property is already in continuation class. @@ -348,7 +340,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, // FIXME. We should really be using CreatePropertyDecl for this. ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), - PropertyId, AtLoc, LParenLoc, T); + PropertyId, AtLoc, LParenLoc, T, TSI); PDecl->setPropertyAttributesAsWritten( makePropertyAttributesAsWritten(AttributesAsWritten)); if (Attributes & ObjCDeclSpec::DQ_PR_readonly) @@ -359,6 +351,11 @@ Sema::HandlePropertyInClassExtension(Scope *S, PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic); if (Attributes & ObjCDeclSpec::DQ_PR_atomic) 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); @@ -383,7 +380,8 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCPropertyDecl *PrimaryPDecl = CreatePropertyDecl(S, CCPrimary, AtLoc, LParenLoc, FD, GetterSel, SetterSel, isAssign, isReadWrite, - Attributes,AttributesAsWritten, T, MethodImplKind, DC); + Attributes,AttributesAsWritten, T, TSI, MethodImplKind, + DC); // A case of continuation class adding a new property in the class. This // is not what it was meant for. However, gcc supports it and so should we. @@ -427,7 +425,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) { PIkind &= ~ObjCPropertyDecl::OBJC_PR_readonly; PIkind |= ObjCPropertyDecl::OBJC_PR_readwrite; - PIkind |= deduceWeakPropertyFromType(*this, PIDecl->getType()); + PIkind |= deduceWeakPropertyFromType(PIDecl->getType()); unsigned ClassExtensionMemoryModel = getOwnershipRule(Attributes); unsigned PrimaryClassMemoryModel = getOwnershipRule(PIkind); if (PrimaryClassMemoryModel && ClassExtensionMemoryModel && @@ -531,11 +529,11 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, const bool isReadWrite, const unsigned Attributes, const unsigned AttributesAsWritten, + QualType T, TypeSourceInfo *TInfo, tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC){ IdentifierInfo *PropertyId = FD.D.getIdentifier(); - QualType T = TInfo->getType(); // Issue a warning if property is 'assign' as default and its object, which is // gc'able conforms to NSCopying protocol @@ -564,7 +562,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, DeclContext *DC = cast<DeclContext>(CDecl); ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), - PropertyId, AtLoc, LParenLoc, TInfo); + PropertyId, AtLoc, + LParenLoc, T, TInfo); if (ObjCPropertyDecl *prevDecl = ObjCPropertyDecl::findPropertyDecl(DC, PropertyId)) { @@ -639,6 +638,12 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, else if (MethodImplKind == tok::objc_optional) PDecl->setPropertyImplementation(ObjCPropertyDecl::Optional); + 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; } @@ -1753,6 +1758,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) { @@ -1988,9 +2020,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, @@ -2051,12 +2095,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); @@ -2228,6 +2285,22 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, Attributes &= ~ObjCDeclSpec::DQ_PR_weak; } + if (Attributes & ObjCDeclSpec::DQ_PR_weak) { + // 'weak' and 'nonnull' are mutually exclusive. + if (auto nullability = PropertyTy->getNullability(Context)) { + if (*nullability == NullabilityKind::NonNull) + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "nonnull" << "weak"; + } else { + PropertyTy = + Context.getAttributedType( + AttributedType::getNullabilityAttrKind(NullabilityKind::Nullable), + PropertyTy, PropertyTy); + TypeSourceInfo *TSInfo = PropertyDecl->getTypeSourceInfo(); + PropertyDecl->setType(PropertyTy, TSInfo); + } + } + if ((Attributes & ObjCDeclSpec::DQ_PR_atomic) && (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)) { Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) |