summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2015-11-03 01:15:46 +0000
committerDouglas Gregor <dgregor@apple.com>2015-11-03 01:15:46 +0000
commit249d7a566d3169e9f75918c3a0170cf90662224f (patch)
tree5a32b44955ab9aa8b816c990a4729a5988a731b8 /lib
parent97e5436f69f1bfa7f3e7fd2ecd80cdee0ae95bef (diff)
downloadclang-249d7a566d3169e9f75918c3a0170cf90662224f.tar.gz
Stop back-patching 'readonly' Objective-C properties with 'readwrite' ones.
A 'readonly' Objective-C property declared in the primary class can effectively be shadowed by a 'readwrite' property declared within an extension of that class, so long as the types and attributes of the two property declarations are compatible. Previously, this functionality was implemented by back-patching the original 'readonly' property to make it 'readwrite', destroying source information and causing some hideously redundant, incorrect code. Simplify the implementation to express how this should actually be modeled: as a separate property declaration in the extension that shadows (via the name lookup rules) the declaration in the primary class. While here, correct some broken Fix-Its, eliminate a pile of redundant code, clean up the ARC migrator's handling of properties declared in extensions, and fix debug info's naming of methods that come from categories. A wonderous side effect of doing this write is that it eliminates the "AddedObjCPropertyInClassExtension" method from the AST mutation listener, which in turn eliminates the last place where we rewrite entire declarations in a chained PCH file or a module file. This change (which fixes rdar://problem/18475765) will allow us to eliminate the rewritten-decls logic from the serialization library, and fixes a crash (rdar://problem/23247794) illustrated by the test/PCH/chain-categories.m example. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@251874 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-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
8 files changed, 227 insertions, 236 deletions
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())