summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/ASTMutationListener.h12
-rw-r--r--include/clang/AST/DeclObjC.h5
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td3
-rw-r--r--include/clang/Sema/Sema.h2
-rw-r--r--include/clang/Serialization/ASTWriter.h3
-rw-r--r--lib/ARCMigrate/TransProperties.cpp26
-rw-r--r--lib/AST/DeclObjC.cpp76
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp7
-rw-r--r--lib/Frontend/MultiplexConsumer.cpp10
-rw-r--r--lib/Sema/SemaDeclObjC.cpp14
-rw-r--r--lib/Sema/SemaExprObjC.cpp3
-rw-r--r--lib/Sema/SemaObjCProperty.cpp312
-rw-r--r--lib/Serialization/ASTWriter.cpp15
-rw-r--r--test/FixIt/atomic-property.m6
-rw-r--r--test/Index/complete-kvc.m2
-rw-r--r--test/Modules/ModuleDebugInfo.m2
-rw-r--r--test/PCH/chain-categories.m13
-rw-r--r--test/SemaObjC/atomoic-property-synnthesis-rules.m24
-rw-r--r--test/SemaObjC/property-3.m2
-rw-r--r--test/SemaObjC/property-in-class-extension-1.m6
-rw-r--r--test/SemaObjCXX/property-invalid-type.mm4
21 files changed, 268 insertions, 279 deletions
diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h
index f4026e9526..3ff392de11 100644
--- a/include/clang/AST/ASTMutationListener.h
+++ b/include/clang/AST/ASTMutationListener.h
@@ -92,18 +92,6 @@ public:
virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
const ObjCInterfaceDecl *IFD) {}
- /// \brief A objc class extension redeclared or introduced a property.
- ///
- /// \param Prop the property in the class extension
- ///
- /// \param OrigProp the property from the original interface that was declared
- /// or null if the property was introduced.
- ///
- /// \param ClassExt the class extension.
- virtual void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
- const ObjCPropertyDecl *OrigProp,
- const ObjCCategoryDecl *ClassExt) {}
-
/// \brief A declaration is marked used which was not previously marked used.
///
/// \param D the declaration marked used
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index 96563ee688..833683fae2 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -2524,11 +2524,6 @@ public:
PropertyAttributesAsWritten = PRVal;
}
- void makeitReadWriteAttribute() {
- PropertyAttributes &= ~OBJC_PR_readonly;
- PropertyAttributes |= OBJC_PR_readwrite;
- }
-
// Helper methods for accessing attributes.
/// isReadOnly - Return true iff the property has a setter.
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 97910798f1..542ccbef76 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -884,7 +884,8 @@ def err_property_type : Error<"property cannot have array or function type %0">;
def error_missing_property_context : Error<
"missing context for property implementation declaration">;
def error_bad_property_decl : Error<
- "property implementation must have its declaration in interface %0">;
+ "property implementation must have its declaration in interface %0 or one of "
+ "its extensions">;
def error_category_property : Error<
"property declared in category %0 cannot be implemented in "
"class implementation">;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 89964ff3a4..c97d2cd790 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -3047,7 +3047,7 @@ public:
/// warning) when atomic property has one but not the other user-declared
/// setter or getter.
void AtomicPropertySetterGetterRules(ObjCImplDecl* IMPDecl,
- ObjCContainerDecl* IDecl);
+ ObjCInterfaceDecl* IDecl);
void DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D);
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index 700f44cd61..b00b7d2d06 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -876,9 +876,6 @@ public:
void FunctionDefinitionInstantiated(const FunctionDecl *D) override;
void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
const ObjCInterfaceDecl *IFD) override;
- void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
- const ObjCPropertyDecl *OrigProp,
- const ObjCCategoryDecl *ClassExt) override;
void DeclarationMarkedUsed(const Decl *D) override;
void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override;
void RedefinedHiddenDefinition(const NamedDecl *D, Module *M) override;
diff --git a/lib/ARCMigrate/TransProperties.cpp b/lib/ARCMigrate/TransProperties.cpp
index ab128844b4..8667bc2a37 100644
--- a/lib/ARCMigrate/TransProperties.cpp
+++ b/lib/ARCMigrate/TransProperties.cpp
@@ -96,6 +96,10 @@ public:
collectProperties(iface, AtProps);
+ // Look through extensions.
+ for (auto *Ext : iface->visible_extensions())
+ collectProperties(Ext, AtProps);
+
typedef DeclContext::specific_decl_iterator<ObjCPropertyImplDecl>
prop_impl_iterator;
for (prop_impl_iterator
@@ -137,19 +141,6 @@ public:
Transaction Trans(Pass.TA);
rewriteProperty(props, atLoc);
}
-
- AtPropDeclsTy AtExtProps;
- // Look through extensions.
- for (auto *Ext : iface->visible_extensions())
- collectProperties(Ext, AtExtProps, &AtProps);
-
- for (AtPropDeclsTy::iterator
- I = AtExtProps.begin(), E = AtExtProps.end(); I != E; ++I) {
- SourceLocation atLoc = SourceLocation::getFromRawEncoding(I->first);
- PropsTy &props = I->second;
- Transaction Trans(Pass.TA);
- doActionForExtensionProp(props, atLoc);
- }
}
private:
@@ -177,15 +168,6 @@ private:
}
}
- void doActionForExtensionProp(PropsTy &props, SourceLocation atLoc) {
- llvm::DenseMap<IdentifierInfo *, PropActionKind>::iterator I;
- I = ActionOnProp.find(props[0].PropD->getIdentifier());
- if (I == ActionOnProp.end())
- return;
-
- doPropAction(I->second, props, atLoc, false);
- }
-
void rewriteProperty(PropsTy &props, SourceLocation atLoc) {
ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props);
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 280c412ae8..b5dc9e122c 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -161,6 +161,15 @@ ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC,
return nullptr;
}
+ // If context is class, then lookup property in its extensions.
+ // This comes before property is looked up in primary class.
+ if (auto *IDecl = dyn_cast<ObjCInterfaceDecl>(DC)) {
+ for (const auto *Ext : IDecl->known_extensions())
+ if (ObjCPropertyDecl *PD = ObjCPropertyDecl::findPropertyDecl(Ext,
+ propertyID))
+ return PD;
+ }
+
DeclContext::lookup_result R = DC->lookup(propertyID);
for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
++I)
@@ -190,6 +199,15 @@ ObjCPropertyDecl *ObjCContainerDecl::FindPropertyDeclaration(
if (Def->isHidden())
return nullptr;
}
+
+ // Search the extensions of a class first; they override what's in
+ // the class itself.
+ if (const auto *ClassDecl = dyn_cast<ObjCInterfaceDecl>(this)) {
+ for (const auto *Ext : ClassDecl->visible_extensions()) {
+ if (auto *P = Ext->FindPropertyDeclaration(PropertyId))
+ return P;
+ }
+ }
if (ObjCPropertyDecl *PD =
ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId))
@@ -207,7 +225,7 @@ ObjCPropertyDecl *ObjCContainerDecl::FindPropertyDeclaration(
}
case Decl::ObjCInterface: {
const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(this);
- // Look through categories (but not extensions).
+ // Look through categories (but not extensions; they were handled above).
for (const auto *Cat : OID->visible_categories()) {
if (!Cat->IsClassExtension())
if (ObjCPropertyDecl *P = Cat->FindPropertyDeclaration(PropertyId))
@@ -327,6 +345,13 @@ void ObjCInterfaceDecl::collectPropertiesToImplement(PropertyMap &PM,
PM[Prop->getIdentifier()] = Prop;
PO.push_back(Prop);
}
+ for (const auto *Ext : known_extensions()) {
+ const ObjCCategoryDecl *ClassExt = Ext;
+ for (auto *Prop : ClassExt->properties()) {
+ PM[Prop->getIdentifier()] = Prop;
+ PO.push_back(Prop);
+ }
+ }
for (const auto *PI : all_referenced_protocols())
PI->collectPropertiesToImplement(PM, PO);
// Note, the properties declared only in class extensions are still copied
@@ -1182,18 +1207,47 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
if (isPropertyAccessor()) {
const ObjCContainerDecl *Container = cast<ObjCContainerDecl>(getParent());
- // If container is class extension, find its primary class.
- if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(Container))
- if (CatDecl->IsClassExtension())
- Container = CatDecl->getClassInterface();
-
bool IsGetter = (NumArgs == 0);
- for (const auto *I : Container->properties()) {
- Selector NextSel = IsGetter ? I->getGetterName()
- : I->getSetterName();
- if (NextSel == Sel)
- return I;
+ /// Local function that attempts to find a matching property within the
+ /// given Objective-C container.
+ auto findMatchingProperty =
+ [&](const ObjCContainerDecl *Container) -> const ObjCPropertyDecl * {
+
+ for (const auto *I : Container->properties()) {
+ Selector NextSel = IsGetter ? I->getGetterName()
+ : I->getSetterName();
+ if (NextSel == Sel)
+ return I;
+ }
+
+ return nullptr;
+ };
+
+ // Look in the container we were given.
+ if (const auto *Found = findMatchingProperty(Container))
+ return Found;
+
+ // If we're in a category or extension, look in the main class.
+ const ObjCInterfaceDecl *ClassDecl = nullptr;
+ if (const auto *Category = dyn_cast<ObjCCategoryDecl>(Container)) {
+ ClassDecl = Category->getClassInterface();
+ if (const auto *Found = findMatchingProperty(ClassDecl))
+ return Found;
+ } else {
+ // Determine whether the container is a class.
+ ClassDecl = dyn_cast<ObjCInterfaceDecl>(Container);
+ }
+
+ // If we have a class, check its visible extensions.
+ if (ClassDecl) {
+ for (const auto *Ext : ClassDecl->visible_extensions()) {
+ if (Ext == Container)
+ continue;
+
+ if (const auto *Found = findMatchingProperty(Ext))
+ return Found;
+ }
}
llvm_unreachable("Marked as a property accessor but no property found!");
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 96649c6706..7efd1ecba9 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -216,6 +216,13 @@ StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) {
} else if (const ObjCInterfaceDecl *OID =
dyn_cast<const ObjCInterfaceDecl>(DC)) {
OS << OID->getName();
+ } else if (const ObjCCategoryDecl *OC = dyn_cast<ObjCCategoryDecl>(DC)) {
+ if (OC->IsClassExtension()) {
+ OS << OC->getClassInterface()->getName();
+ } else {
+ OS << ((const NamedDecl *)OC)->getIdentifier()->getNameStart() << '('
+ << OC->getIdentifier()->getNameStart() << ')';
+ }
} else if (const ObjCCategoryImplDecl *OCD =
dyn_cast<const ObjCCategoryImplDecl>(DC)) {
OS << ((const NamedDecl *)OCD)->getIdentifier()->getNameStart() << '('
diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp
index 91ee100f63..12c85240bd 100644
--- a/lib/Frontend/MultiplexConsumer.cpp
+++ b/lib/Frontend/MultiplexConsumer.cpp
@@ -122,9 +122,6 @@ public:
void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
const ObjCInterfaceDecl *IFD) override;
void FunctionDefinitionInstantiated(const FunctionDecl *D) override;
- void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
- const ObjCPropertyDecl *OrigProp,
- const ObjCCategoryDecl *ClassExt) override;
void DeclarationMarkedUsed(const Decl *D) override;
void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override;
void RedefinedHiddenDefinition(const NamedDecl *D, Module *M) override;
@@ -207,13 +204,6 @@ void MultiplexASTMutationListener::FunctionDefinitionInstantiated(
for (auto &Listener : Listeners)
Listener->FunctionDefinitionInstantiated(D);
}
-void MultiplexASTMutationListener::AddedObjCPropertyInClassExtension(
- const ObjCPropertyDecl *Prop,
- const ObjCPropertyDecl *OrigProp,
- const ObjCCategoryDecl *ClassExt) {
- for (size_t i = 0, e = Listeners.size(); i != e; ++i)
- Listeners[i]->AddedObjCPropertyInClassExtension(Prop, OrigProp, ClassExt);
-}
void MultiplexASTMutationListener::DeclarationMarkedUsed(const Decl *D) {
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->DeclarationMarkedUsed(D);
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 90c829e740..2622e5ed83 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -2844,6 +2844,20 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
for (const auto *I : IMPDecl->instance_methods())
InsMap.insert(I->getSelector());
+ // Add the selectors for getters/setters of @dynamic properties.
+ for (const auto *PImpl : IMPDecl->property_impls()) {
+ // We only care about @dynamic implementations.
+ if (PImpl->getPropertyImplementation() != ObjCPropertyImplDecl::Dynamic)
+ continue;
+
+ const auto *P = PImpl->getPropertyDecl();
+ if (!P) continue;
+
+ InsMap.insert(P->getGetterName());
+ if (!P->getSetterName().isNull())
+ InsMap.insert(P->getSetterName());
+ }
+
// Check and see if properties declared in the interface have either 1)
// an implementation or 2) there is a @synthesize/@dynamic implementation
// of the property in the @implementation.
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 227b322adb..3257741429 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -1779,8 +1779,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
diag::err_property_not_found_forward_class,
MemberName, BaseRange))
return ExprError();
-
- // Search for a declared property first.
+
if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) {
// Check whether we can reference this property.
if (DiagnoseUseOfDecl(PD, MemberLoc))
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index bd99143d4c..1d5d8b9489 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -262,8 +262,12 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
}
}
} else if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
- for (auto *P : Cat->protocols())
- CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos);
+ // We don't check if class extension. Because properties in class extension
+ // are meant to override some of the attributes and checking has already done
+ // when property in class extension is constructed.
+ if (!Cat->IsClassExtension())
+ for (auto *P : Cat->protocols())
+ CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos);
} else {
ObjCProtocolDecl *Proto = cast<ObjCProtocolDecl>(ClassDecl);
for (auto *P : Proto->protocols())
@@ -355,46 +359,6 @@ Sema::HandlePropertyInClassExtension(Scope *S,
IdentifierInfo *PropertyId = FD.D.getIdentifier();
ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface();
- if (CCPrimary) {
- // Check for duplicate declaration of this property in current and
- // other class extensions.
- for (const auto *Ext : CCPrimary->known_extensions()) {
- if (ObjCPropertyDecl *prevDecl
- = ObjCPropertyDecl::findPropertyDecl(Ext, PropertyId)) {
- Diag(AtLoc, diag::err_duplicate_property);
- Diag(prevDecl->getLocation(), diag::note_property_declare);
- return nullptr;
- }
- }
- }
-
- // Create a new ObjCPropertyDecl with the DeclContext being
- // the class extension.
- // FIXME. We should really be using CreatePropertyDecl for this.
- ObjCPropertyDecl *PDecl =
- ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(),
- PropertyId, AtLoc, LParenLoc, T, TSI);
- PDecl->setPropertyAttributesAsWritten(
- makePropertyAttributesAsWritten(AttributesAsWritten));
- if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
- if (Attributes & ObjCDeclSpec::DQ_PR_readwrite)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite);
- if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
- 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);
- ProcessDeclAttributes(S, PDecl, FD.D);
- DC->addDecl(PDecl);
-
// We need to look in the @interface to see if the @property was
// already declared.
if (!CCPrimary) {
@@ -403,32 +367,35 @@ Sema::HandlePropertyInClassExtension(Scope *S,
return nullptr;
}
- // Find the property in continuation class's primary class only.
+ // Find the property in the extended class's primary class or
+ // extensions.
ObjCPropertyDecl *PIDecl =
CCPrimary->FindPropertyVisibleInPrimaryClass(PropertyId);
+ // If we found a property in an extension, complain.
+ if (PIDecl && isa<ObjCCategoryDecl>(PIDecl->getDeclContext())) {
+ Diag(AtLoc, diag::err_duplicate_property);
+ Diag(PIDecl->getLocation(), diag::note_property_declare);
+ return nullptr;
+ }
+
+ // Create a new ObjCPropertyDecl with the DeclContext being
+ // the class extension.
+ ObjCPropertyDecl *PDecl = CreatePropertyDecl(S, CDecl, AtLoc, LParenLoc,
+ FD, GetterSel, SetterSel,
+ isAssign, isReadWrite,
+ Attributes, AttributesAsWritten,
+ T, TSI, MethodImplKind, DC);
+
+ // If there was no declaration of a property with the same name in
+ // the primary class, we're done.
if (!PIDecl) {
- // No matching property found in the primary class. Just fall thru
- // and add property to continuation class's primary class.
- ObjCPropertyDecl *PrimaryPDecl =
- CreatePropertyDecl(S, CCPrimary, AtLoc, LParenLoc,
- FD, GetterSel, SetterSel, isAssign, isReadWrite,
- 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.
- // Make sure setter/getters are declared here.
- ProcessPropertyDecl(PrimaryPDecl, CCPrimary,
+ ProcessPropertyDecl(PDecl, CDecl,
/* redeclaredProperty = */ nullptr,
/* lexicalDC = */ CDecl);
- PDecl->setGetterMethodDecl(PrimaryPDecl->getGetterMethodDecl());
- PDecl->setSetterMethodDecl(PrimaryPDecl->getSetterMethodDecl());
- if (ASTMutationListener *L = Context.getASTMutationListener())
- L->AddedObjCPropertyInClassExtension(PrimaryPDecl, /*OrigProp=*/nullptr,
- CDecl);
- return PrimaryPDecl;
+ return PDecl;
}
+
if (!Context.hasSameType(PIDecl->getType(), PDecl->getType())) {
bool IncompatibleObjC = false;
QualType ConvertedType;
@@ -451,82 +418,12 @@ Sema::HandlePropertyInClassExtension(Scope *S,
return nullptr;
}
}
-
- // The property 'PIDecl's readonly attribute will be over-ridden
- // with continuation class's readwrite property attribute!
+
+ // A readonly property declared in the primary class can be refined
+ // by adding a rewrite property within an extension.
+ // Anything else is an error.
unsigned PIkind = PIDecl->getPropertyAttributesAsWritten();
- if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) {
- PIkind &= ~ObjCPropertyDecl::OBJC_PR_readonly;
- PIkind |= ObjCPropertyDecl::OBJC_PR_readwrite;
- PIkind |= deducePropertyOwnershipFromType(*this, PIDecl->getType());
- unsigned ClassExtensionMemoryModel = getOwnershipRule(Attributes);
- unsigned PrimaryClassMemoryModel = getOwnershipRule(PIkind);
- if (PrimaryClassMemoryModel && ClassExtensionMemoryModel &&
- (PrimaryClassMemoryModel != ClassExtensionMemoryModel)) {
- Diag(AtLoc, diag::warn_property_attr_mismatch);
- Diag(PIDecl->getLocation(), diag::note_property_declare);
- }
- else if (getLangOpts().ObjCAutoRefCount) {
- QualType PrimaryPropertyQT =
- Context.getCanonicalType(PIDecl->getType()).getUnqualifiedType();
- if (isa<ObjCObjectPointerType>(PrimaryPropertyQT)) {
- bool PropertyIsWeak = ((PIkind & ObjCPropertyDecl::OBJC_PR_weak) != 0);
- Qualifiers::ObjCLifetime PrimaryPropertyLifeTime =
- PrimaryPropertyQT.getObjCLifetime();
- if (PrimaryPropertyLifeTime == Qualifiers::OCL_None &&
- (Attributes & ObjCDeclSpec::DQ_PR_weak) &&
- !PropertyIsWeak) {
- Diag(AtLoc, diag::warn_property_implicitly_mismatched);
- Diag(PIDecl->getLocation(), diag::note_property_declare);
- }
- }
- }
-
- DeclContext *DC = cast<DeclContext>(CCPrimary);
- if (!ObjCPropertyDecl::findPropertyDecl(DC,
- PIDecl->getDeclName().getAsIdentifierInfo())) {
- // In mrr mode, 'readwrite' property must have an explicit
- // memory attribute. If none specified, select the default (assign).
- if (!getLangOpts().ObjCAutoRefCount) {
- if (!(PIkind & (ObjCDeclSpec::DQ_PR_assign |
- ObjCDeclSpec::DQ_PR_retain |
- ObjCDeclSpec::DQ_PR_strong |
- ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_unsafe_unretained |
- ObjCDeclSpec::DQ_PR_weak)))
- PIkind |= ObjCPropertyDecl::OBJC_PR_assign;
- }
-
- // Protocol is not in the primary class. Must build one for it.
- ObjCDeclSpec ProtocolPropertyODS;
- // FIXME. Assuming that ObjCDeclSpec::ObjCPropertyAttributeKind
- // and ObjCPropertyDecl::PropertyAttributeKind have identical
- // values. Should consolidate both into one enum type.
- ProtocolPropertyODS.
- setPropertyAttributes((ObjCDeclSpec::ObjCPropertyAttributeKind)
- PIkind);
- // Must re-establish the context from class extension to primary
- // class context.
- ContextRAII SavedContext(*this, CCPrimary);
-
- Decl *ProtocolPtrTy =
- ActOnProperty(S, AtLoc, LParenLoc, FD, ProtocolPropertyODS,
- PIDecl->getGetterName(),
- PIDecl->getSetterName(),
- isOverridingProperty,
- MethodImplKind,
- /* lexicalDC = */ CDecl);
- PIDecl = cast<ObjCPropertyDecl>(ProtocolPtrTy);
- }
- PIDecl->makeitReadWriteAttribute();
- if (Attributes & ObjCDeclSpec::DQ_PR_retain)
- PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
- if (Attributes & ObjCDeclSpec::DQ_PR_strong)
- PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
- if (Attributes & ObjCDeclSpec::DQ_PR_copy)
- PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
- PIDecl->setSetterName(SetterSel);
- } else {
+ if (!(isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly))) {
// Tailor the diagnostics for the common case where a readwrite
// property is declared both in the @interface and the continuation.
// This is a common error where the user often intended the original
@@ -541,13 +438,53 @@ Sema::HandlePropertyInClassExtension(Scope *S,
Diag(PIDecl->getLocation(), diag::note_property_declare);
return nullptr;
}
+
+ PIkind &= ~ObjCPropertyDecl::OBJC_PR_readonly;
+ PIkind |= ObjCPropertyDecl::OBJC_PR_readwrite;
+ PIkind |= deducePropertyOwnershipFromType(*this, PIDecl->getType());
+ unsigned ClassExtensionMemoryModel = getOwnershipRule(Attributes);
+ unsigned PrimaryClassMemoryModel = getOwnershipRule(PIkind);
+ if (PrimaryClassMemoryModel && ClassExtensionMemoryModel &&
+ (PrimaryClassMemoryModel != ClassExtensionMemoryModel)) {
+ Diag(AtLoc, diag::warn_property_attr_mismatch);
+ Diag(PIDecl->getLocation(), diag::note_property_declare);
+ } else if (getLangOpts().ObjCAutoRefCount) {
+ QualType PrimaryPropertyQT =
+ Context.getCanonicalType(PIDecl->getType()).getUnqualifiedType();
+ if (isa<ObjCObjectPointerType>(PrimaryPropertyQT)) {
+ bool PropertyIsWeak = ((PIkind & ObjCPropertyDecl::OBJC_PR_weak) != 0);
+ Qualifiers::ObjCLifetime PrimaryPropertyLifeTime =
+ PrimaryPropertyQT.getObjCLifetime();
+ if (PrimaryPropertyLifeTime == Qualifiers::OCL_None &&
+ (Attributes & ObjCDeclSpec::DQ_PR_weak) &&
+ !PropertyIsWeak) {
+ Diag(AtLoc, diag::warn_property_implicitly_mismatched);
+ Diag(PIDecl->getLocation(), diag::note_property_declare);
+ }
+ }
+ }
+
+ // Check that atomicity of property in class extension matches the previous
+ // declaration.
+ unsigned PDeclAtomicity =
+ PDecl->getPropertyAttributes() & (ObjCDeclSpec::DQ_PR_atomic | ObjCDeclSpec::DQ_PR_nonatomic);
+ unsigned PIDeclAtomicity =
+ PIDecl->getPropertyAttributes() & (ObjCDeclSpec::DQ_PR_atomic | ObjCDeclSpec::DQ_PR_nonatomic);
+ if (PDeclAtomicity != PIDeclAtomicity) {
+ bool PDeclAtomic = (!PDeclAtomicity || PDeclAtomicity & ObjCDeclSpec::DQ_PR_atomic);
+ bool PIDeclAtomic = (!PIDeclAtomicity || PIDeclAtomicity & ObjCDeclSpec::DQ_PR_atomic);
+ if (PDeclAtomic != PIDeclAtomic) {
+ Diag(PDecl->getLocation(), diag::warn_property_attribute)
+ << PDecl->getDeclName() << "atomic"
+ << cast<ObjCContainerDecl>(PIDecl->getDeclContext())->getName();
+ Diag(PIDecl->getLocation(), diag::note_property_declare);
+ }
+ }
+
*isOverridingProperty = true;
- // Make sure setter decl is synthesized, and added to primary class's list.
- ProcessPropertyDecl(PIDecl, CCPrimary, PDecl, CDecl);
- PDecl->setGetterMethodDecl(PIDecl->getGetterMethodDecl());
- PDecl->setSetterMethodDecl(PIDecl->getSetterMethodDecl());
- if (ASTMutationListener *L = Context.getASTMutationListener())
- L->AddedObjCPropertyInClassExtension(PDecl, PIDecl, CDecl);
+
+ // Make sure setter decl is synthesized, and added to continuation class's list.
+ ProcessPropertyDecl(PDecl, CDecl, PIDecl, CDecl);
return PDecl;
}
@@ -1480,6 +1417,11 @@ static void CollectImmediateProperties(ObjCContainerDecl *CDecl,
if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
for (auto *Prop : IDecl->properties())
PropMap[Prop->getIdentifier()] = Prop;
+
+ // Collect the properties from visible extensions.
+ for (auto *Ext : IDecl->visible_extensions())
+ CollectImmediateProperties(Ext, PropMap, SuperPropMap, IncludeProtocols);
+
if (IncludeProtocols) {
// Scan through class's protocols.
for (auto *PI : IDecl->all_referenced_protocols())
@@ -1487,9 +1429,8 @@ static void CollectImmediateProperties(ObjCContainerDecl *CDecl,
}
}
if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
- if (!CATDecl->IsClassExtension())
- for (auto *Prop : CATDecl->properties())
- PropMap[Prop->getIdentifier()] = Prop;
+ for (auto *Prop : CATDecl->properties())
+ PropMap[Prop->getIdentifier()] = Prop;
if (IncludeProtocols) {
// Scan through class's protocols.
for (auto *PI : CATDecl->protocols())
@@ -1549,6 +1490,14 @@ Sema::IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace,
(Property->getPropertyIvarDecl() == IV))
return true;
}
+ // Also look up property declaration in class extension whose one of its
+ // accessors is implemented by this method.
+ for (const auto *Ext : IFace->known_extensions())
+ for (const auto *Property : Ext->properties())
+ if ((Property->getGetterName() == IMD->getSelector() ||
+ Property->getSetterName() == IMD->getSelector()) &&
+ (Property->getPropertyIvarDecl() == IV))
+ return true;
return false;
}
@@ -1833,11 +1782,20 @@ void Sema::diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl)
void
Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
- ObjCContainerDecl* IDecl) {
+ ObjCInterfaceDecl* IDecl) {
// Rules apply in non-GC mode only
if (getLangOpts().getGC() != LangOptions::NonGC)
return;
- for (const auto *Property : IDecl->properties()) {
+ ObjCContainerDecl::PropertyMap PM;
+ for (auto *Prop : IDecl->properties())
+ PM[Prop->getIdentifier()] = Prop;
+ for (const auto *Ext : IDecl->known_extensions())
+ for (auto *Prop : Ext->properties())
+ PM[Prop->getIdentifier()] = Prop;
+
+ for (ObjCContainerDecl::PropertyMap::iterator I = PM.begin(), E = PM.end();
+ I != E; ++I) {
+ const ObjCPropertyDecl *Property = I->second;
ObjCMethodDecl *GetterMethod = nullptr;
ObjCMethodDecl *SetterMethod = nullptr;
bool LookedUpGetterSetter = false;
@@ -1884,30 +1842,23 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
<< Property->getIdentifier() << (GetterMethod != nullptr)
<< (SetterMethod != nullptr);
// fixit stuff.
- if (!AttributesAsWritten) {
- if (Property->getLParenLoc().isValid()) {
- // @property () ... case.
- SourceRange PropSourceRange(Property->getAtLoc(),
- Property->getLParenLoc());
- Diag(Property->getLocation(), diag::note_atomic_property_fixup_suggest) <<
- FixItHint::CreateReplacement(PropSourceRange, "@property (nonatomic");
- }
- else {
- //@property id etc.
- SourceLocation endLoc =
- Property->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
- endLoc = endLoc.getLocWithOffset(-1);
- SourceRange PropSourceRange(Property->getAtLoc(), endLoc);
- Diag(Property->getLocation(), diag::note_atomic_property_fixup_suggest) <<
- FixItHint::CreateReplacement(PropSourceRange, "@property (nonatomic) ");
- }
- }
- else if (!(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_atomic)) {
+ if (Property->getLParenLoc().isValid() &&
+ !(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_atomic)) {
// @property () ... case.
- SourceLocation endLoc = Property->getLParenLoc();
- SourceRange PropSourceRange(Property->getAtLoc(), endLoc);
- Diag(Property->getLocation(), diag::note_atomic_property_fixup_suggest) <<
- FixItHint::CreateReplacement(PropSourceRange, "@property (nonatomic, ");
+ SourceLocation AfterLParen =
+ getLocForEndOfToken(Property->getLParenLoc());
+ StringRef NonatomicStr = AttributesAsWritten? "nonatomic, "
+ : "nonatomic";
+ Diag(Property->getLocation(),
+ diag::note_atomic_property_fixup_suggest)
+ << FixItHint::CreateInsertion(AfterLParen, NonatomicStr);
+ } else if (Property->getLParenLoc().isInvalid()) {
+ //@property id etc.
+ SourceLocation startLoc =
+ Property->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
+ Diag(Property->getLocation(),
+ diag::note_atomic_property_fixup_suggest)
+ << FixItHint::CreateInsertion(startLoc, "(nonatomic) ");
}
else
Diag(MethodLoc, diag::note_atomic_property_fixup_suggest);
@@ -2035,7 +1986,20 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
return;
GetterMethod = CD->getInstanceMethod(property->getGetterName());
+ // if setter or getter is not found in class extension, it might be
+ // in the primary class.
+ if (!GetterMethod)
+ if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD))
+ if (CatDecl->IsClassExtension())
+ GetterMethod = CatDecl->getClassInterface()->
+ getInstanceMethod(property->getGetterName());
+
SetterMethod = CD->getInstanceMethod(property->getSetterName());
+ if (!SetterMethod)
+ if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD))
+ if (CatDecl->IsClassExtension())
+ SetterMethod = CatDecl->getClassInterface()->
+ getInstanceMethod(property->getSetterName());
DiagnosePropertyAccessorMismatch(property, GetterMethod,
property->getLocation());
@@ -2068,9 +2032,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
// No instance method of same name as property getter name was found.
// Declare a getter method and add it to the list of methods
// for this class.
- SourceLocation Loc = redeclaredProperty ?
- redeclaredProperty->getLocation() :
- property->getLocation();
+ SourceLocation Loc = property->getLocation();
// If the property is null_resettable, the getter returns nonnull.
QualType resultTy = property->getType();
@@ -2130,9 +2092,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
// No instance method of same name as property setter name was found.
// Declare a setter method and add it to the list of methods
// for this class.
- SourceLocation Loc = redeclaredProperty ?
- redeclaredProperty->getLocation() :
- property->getLocation();
+ SourceLocation Loc = property->getLocation();
SetterMethod =
ObjCMethodDecl::Create(Context, Loc, Loc,
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 331fa38590..4399fdcb2f 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -5756,21 +5756,6 @@ void ASTWriter::AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
const_cast<ObjCInterfaceDecl *>(IFD->getDefinition()));
}
-
-void ASTWriter::AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
- const ObjCPropertyDecl *OrigProp,
- const ObjCCategoryDecl *ClassExt) {
- const ObjCInterfaceDecl *D = ClassExt->getClassInterface();
- if (!D)
- return;
-
- assert(!WritingAST && "Already writing the AST!");
- if (!D->isFromASTFile())
- return; // Declaration not imported from PCH.
-
- RewriteDecl(D);
-}
-
void ASTWriter::DeclarationMarkedUsed(const Decl *D) {
assert(!WritingAST && "Already writing the AST!");
if (!D->isFromASTFile())
diff --git a/test/FixIt/atomic-property.m b/test/FixIt/atomic-property.m
index 9ede7f1e76..84dd820e1c 100644
--- a/test/FixIt/atomic-property.m
+++ b/test/FixIt/atomic-property.m
@@ -23,7 +23,7 @@
- (id) atomic_prop1 { return 0; }
@end
-// CHECK: {4:1-4:10}:"@property (nonatomic) "
-// CHECK: {9:1-9:12}:"@property (nonatomic"
-// CHECK: {13:1-13:12}:"@property (nonatomic, "
+// CHECK-DAG: {4:11-4:11}:"(nonatomic) "
+// CHECK-DAG: {9:12-9:12}:"nonatomic"
+// CHECK-DAG: {13:12-13:12}:"nonatomic, "
diff --git a/test/Index/complete-kvc.m b/test/Index/complete-kvc.m
index 62d98a9b20..336d41d759 100644
--- a/test/Index/complete-kvc.m
+++ b/test/Index/complete-kvc.m
@@ -101,5 +101,5 @@ typedef signed char BOOL;
// RUN: c-index-test -code-completion-at=%s:52:8 %s | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: ObjCInstanceMethodDecl:{TypedText countOfIntProperty} (55)
-// CHECK-CC3-NEXT: ObjCInstanceMethodDecl:{TypedText intProperty} (40)
+// CHECK-CC3-NEXT: ObjCInstanceMethodDecl:{TypedText intProperty} (42)
// CHECK-CC3-NEXT: ObjCInstanceMethodDecl:{TypedText isIntProperty} (40)
diff --git a/test/Modules/ModuleDebugInfo.m b/test/Modules/ModuleDebugInfo.m
index b7dfb22b71..0974f38cc2 100644
--- a/test/Modules/ModuleDebugInfo.m
+++ b/test/Modules/ModuleDebugInfo.m
@@ -33,7 +33,7 @@
// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "InnerEnum"
// CHECK: !DISubprogram(name: "+[ObjCClass classMethod]"
// CHECK: !DISubprogram(name: "-[ObjCClass instanceMethodWithInt:]"
-// CHECK: !DISubprogram(name: "-[ categoryMethod]"
+// CHECK: !DISubprogram(name: "-[Category(Category) categoryMethod]"
// MODULE-CHECK: !DICompositeType(tag: DW_TAG_enumeration_type,
// MODULE-CHECK-SAME: scope: ![[MODULE:[0-9]+]],
diff --git a/test/PCH/chain-categories.m b/test/PCH/chain-categories.m
index 7836e09d88..dc57387fd5 100644
--- a/test/PCH/chain-categories.m
+++ b/test/PCH/chain-categories.m
@@ -16,6 +16,10 @@
- (void)finalize;
@end
+@interface NSObject (Properties)
+@property (readonly,nonatomic) int intProp;
+@end
+
//===----------------------------------------------------------------------===//
#elif !defined(HEADER2)
#define HEADER2
@@ -34,6 +38,12 @@
-(void)extMeth;
@end
+@interface NSObject ()
+@property (readwrite,nonatomic) int intProp;
+@end
+
+@class NSObject;
+
//===----------------------------------------------------------------------===//
#else
//===----------------------------------------------------------------------===//
@@ -47,6 +57,9 @@
void test(NSObject *o) {
[o extMeth];
+
+ // Make sure the property is treated as read-write.
+ o.intProp = 17;
}
//===----------------------------------------------------------------------===//
diff --git a/test/SemaObjC/atomoic-property-synnthesis-rules.m b/test/SemaObjC/atomoic-property-synnthesis-rules.m
index b681558220..c7fac7b618 100644
--- a/test/SemaObjC/atomoic-property-synnthesis-rules.m
+++ b/test/SemaObjC/atomoic-property-synnthesis-rules.m
@@ -129,10 +129,8 @@
// read-only in class, read-write in class extension - might warn
@property(readonly) int GetSet_ReadWriteInExt;
-@property(readonly) int Get_ReadWriteInExt; // expected-note {{property declared here}} \
- // expected-note {{setter and getter must both be synthesized}}
-@property(readonly) int Set_ReadWriteInExt; // expected-note {{property declared here}} \
- // expected-note {{setter and getter must both be synthesized}}
+@property(readonly) int Get_ReadWriteInExt;
+@property(readonly) int Set_ReadWriteInExt;
@property(readonly) int None_ReadWriteInExt;
@property(nonatomic,readonly) int GetSet_Nonatomic_ReadWriteInExt;
@property(nonatomic,readonly) int Get_Nonatomic_ReadWriteInExt;
@@ -162,10 +160,8 @@
@property(nonatomic,readonly) int None_Nonatomic_ReadOnly_LateSynthesize;
@property(readonly) int GetSet_ReadWriteInExt_LateSynthesize;
-@property(readonly) int Get_ReadWriteInExt_LateSynthesize; // expected-note {{property declared here}} \
- // expected-note {{setter and getter must both be synthesized}}
-@property(readonly) int Set_ReadWriteInExt_LateSynthesize; // expected-note {{property declared here}} \
- // expected-note {{setter and getter must both be synthesized}}
+@property(readonly) int Get_ReadWriteInExt_LateSynthesize;
+@property(readonly) int Set_ReadWriteInExt_LateSynthesize;
@property(readonly) int None_ReadWriteInExt_LateSynthesize;
@property(nonatomic,readonly) int GetSet_Nonatomic_ReadWriteInExt_LateSynthesize;
@property(nonatomic,readonly) int Get_Nonatomic_ReadWriteInExt_LateSynthesize;
@@ -207,8 +203,10 @@
@interface Foo ()
@property(readwrite) int GetSet_ReadWriteInExt;
-@property(readwrite) int Get_ReadWriteInExt;
-@property(readwrite) int Set_ReadWriteInExt;
+@property(readwrite) int Get_ReadWriteInExt; // expected-note {{property declared here}} \
+ // expected-note {{setter and getter must both be synthesized}}
+@property(readwrite) int Set_ReadWriteInExt; // expected-note {{property declared here}} \
+ // expected-note {{setter and getter must both be synthesized}}
@property(readwrite) int None_ReadWriteInExt;
@property(nonatomic,readwrite) int GetSet_Nonatomic_ReadWriteInExt;
@property(nonatomic,readwrite) int Get_Nonatomic_ReadWriteInExt;
@@ -216,8 +214,10 @@
@property(nonatomic,readwrite) int None_Nonatomic_ReadWriteInExt;
@property(readwrite) int GetSet_ReadWriteInExt_LateSynthesize;
-@property(readwrite) int Get_ReadWriteInExt_LateSynthesize;
-@property(readwrite) int Set_ReadWriteInExt_LateSynthesize;
+@property(readwrite) int Get_ReadWriteInExt_LateSynthesize; // expected-note {{property declared here}} \
+ // expected-note {{setter and getter must both be synthesized}}
+@property(readwrite) int Set_ReadWriteInExt_LateSynthesize; // expected-note {{property declared here}} \
+ // expected-note {{setter and getter must both be synthesized}}
@property(readwrite) int None_ReadWriteInExt_LateSynthesize;
@property(nonatomic,readwrite) int GetSet_Nonatomic_ReadWriteInExt_LateSynthesize;
@property(nonatomic,readwrite) int Get_Nonatomic_ReadWriteInExt_LateSynthesize;
diff --git a/test/SemaObjC/property-3.m b/test/SemaObjC/property-3.m
index 3f82bcc3b7..7c0ba579ee 100644
--- a/test/SemaObjC/property-3.m
+++ b/test/SemaObjC/property-3.m
@@ -29,5 +29,5 @@ typedef signed char BOOL;
@interface EKCalendar () <EKProtocolMutableCalendar>
@property (nonatomic, assign) BOOL allowReminders;
-@property (nonatomic, assign) BOOL allowNonatomicProperty; // expected-warning {{'atomic' attribute on property 'allowNonatomicProperty' does not match the property inherited from 'EKProtocolCalendar'}}
+@property (nonatomic, assign) BOOL allowNonatomicProperty; // expected-warning {{'atomic' attribute on property 'allowNonatomicProperty' does not match the property inherited from EKProtocolCalendar}}
@end
diff --git a/test/SemaObjC/property-in-class-extension-1.m b/test/SemaObjC/property-in-class-extension-1.m
index 6e9d476c18..8f5907b54d 100644
--- a/test/SemaObjC/property-in-class-extension-1.m
+++ b/test/SemaObjC/property-in-class-extension-1.m
@@ -10,7 +10,7 @@
@property (nonatomic, copy, readonly) NSString* matchingMemoryModel;
-@property (nonatomic, retain, readonly) NSString* addingNoNewMemoryModel;
+@property (atomic, retain, readonly) NSString* addingNoNewMemoryModel;
@property (readonly) NSString* none;
@property (readonly) NSString* none1;
@@ -50,10 +50,14 @@
// rdar://12214070
@interface radar12214070
@property (nonatomic, atomic, readonly) float propertyName; // expected-error {{property attributes 'atomic' and 'nonatomic' are mutually exclusive}}
+
+@property (nonatomic, readonly) float propertyName2; // expected-note {{property declared here}}
@end
@interface radar12214070 ()
@property (atomic, nonatomic, readonly, readwrite) float propertyName; // expected-error {{property attributes 'readonly' and 'readwrite' are mutually exclusive}} \
// expected-error {{property attributes 'atomic' and 'nonatomic' are mutually exclusive}}
+
+@property (atomic, readwrite) float propertyName2; // expected-warning {{'atomic' attribute on property 'propertyName2' does not match the property inherited from radar12214070}}
@end
diff --git a/test/SemaObjCXX/property-invalid-type.mm b/test/SemaObjCXX/property-invalid-type.mm
index 5b8a848df4..648235894e 100644
--- a/test/SemaObjCXX/property-invalid-type.mm
+++ b/test/SemaObjCXX/property-invalid-type.mm
@@ -13,11 +13,11 @@
@synthesize response;
- (void) foo :(A*) a // expected-error {{expected a type}}
{
- self.response = a;
+ self.response = a; // expected-error{{assigning to 'int *' from incompatible type 'id'}}
}
@end
void foo(I *i)
{
- i.helper;
+ i.helper; // expected-warning{{property access result unused - getters should not be used for side effects}}
}