r251874 - Stop back-patching 'readonly' Objective-C properties with 'readwrite' ones.
Nico Weber via cfe-commits
cfe-commits at lists.llvm.org
Thu Dec 3 08:58:07 PST 2015
Here's a version that gets that right.
On Wed, Dec 2, 2015 at 8:16 PM, Douglas Gregor <dgregor at apple.com> wrote:
>
> On Dec 2, 2015, at 7:22 PM, Nico Weber <thakis at chromium.org> wrote:
>
> It looks like one place in CGObjCMac.cpp still walks
> ObjCContainerDecl::properties(), while it probably should
> use collectPropertiesToImplement() which you extended to also find
> properites from known_extensions(). The attached patch has a fix that
> restores the observed prior behavior and a reduced lit test that makes sure
> this doesn't regress. Does this look right?
>
>
> Thank you for working on this!
>
> It’s close; I suggest testing the case where you have a readonly property
> in the class definition and a readwrite property with the same name in an
> extension, to make sure we get the correct metadata (readwrite, without
> duplicates).
>
>
> If so, something like this would probably be needed
> in CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty) in
> CGDebugInfo.cpp too.
>
>
> Yep, there too.
>
> - Doug
>
>
> On Tue, Dec 1, 2015 at 2:44 PM, Nico Weber <thakis at chromium.org> wrote:
>
>> Actually, looking at it again Foo derives from NSObject and shouldn't
>> shadow anything. So maybe this isn't an intentional behavior change even?
>>
>> On Tue, Dec 1, 2015 at 2:39 PM, Nico Weber <thakis at chromium.org> wrote:
>>
>>> Hi Doug and Argyrios,
>>>
>>> this is breaking things for us. We have a class ObjCPropertyReleaser
>>> that automatically releases synthesized Objective-C properties marked
>>> retain or copy [1]. It does this by looking at the result
>>> of property_getAttributes() and looking for 'C' or '&' (copy or retain).
>>>
>>> After this change, this longer works. Here's a reduced example:
>>>
>>> $ cat main.mm
>>> #import <Foundation/Foundation.h>
>>> #import <UIKit/UIKit.h>
>>>
>>> @interface Foo : NSObject
>>> @end
>>>
>>> @interface Foo ()
>>>
>>> @property(nonatomic, retain) UIView* contentView;
>>> @end
>>>
>>> @implementation Foo
>>> @synthesize contentView = _contentView;
>>> @end
>>>
>>> $ newclang++ -isysroot
>>> /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator9.1.sdk
>>> -c main.mm -o main.o && strings main.o | grep "&,N,V_contentView"
>>> # Nothing found.
>>>
>>> $ oldclang++ -isysroot
>>> /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator9.1.sdk
>>> -c main.mm -o main.o && strings main.o | grep "&,N,V_contentView"
>>> T@"UIView",&,N,V_contentView
>>> # ^ Found as expected
>>>
>>>
>>> I suppose this is intentional and the fix is to not shadow readonly
>>> superclass properties? Finding these is a bit difficult though as clang
>>> doesn't warn about this as far as I can tell.
>>>
>>> Thanks,
>>> Nico
>>>
>>> 1:
>>> https://code.google.com/p/chromium/codesearch#chromium/src/base/mac/objc_property_releaser.h
>>>
>>> On Mon, Nov 2, 2015 at 8:22 PM, Douglas Gregor via cfe-commits <
>>> cfe-commits at lists.llvm.org> wrote:
>>>
>>>> … and I forgot the most important part, which is that this is based on
>>>> the good work of Mr. Kyrtzidis that I failed to acknowledge in the commit
>>>> message.
>>>>
>>>> - Doug
>>>>
>>>>
>>>> > On Nov 2, 2015, at 5:15 PM, Douglas Gregor via cfe-commits <
>>>> cfe-commits at lists.llvm.org> wrote:
>>>> >
>>>> > Author: dgregor
>>>> > Date: Mon Nov 2 19:15:46 2015
>>>> > New Revision: 251874
>>>> >
>>>> > URL: http://llvm.org/viewvc/llvm-project?rev=251874&view=rev
>>>> > Log:
>>>> > 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.
>>>> >
>>>> >
>>>> > Modified:
>>>> > cfe/trunk/include/clang/AST/ASTMutationListener.h
>>>> > cfe/trunk/include/clang/AST/DeclObjC.h
>>>> > cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>>>> > cfe/trunk/include/clang/Sema/Sema.h
>>>> > cfe/trunk/include/clang/Serialization/ASTWriter.h
>>>> > cfe/trunk/lib/ARCMigrate/TransProperties.cpp
>>>> > cfe/trunk/lib/AST/DeclObjC.cpp
>>>> > cfe/trunk/lib/CodeGen/CGDebugInfo.cpp
>>>> > cfe/trunk/lib/Frontend/MultiplexConsumer.cpp
>>>> > cfe/trunk/lib/Sema/SemaDeclObjC.cpp
>>>> > cfe/trunk/lib/Sema/SemaExprObjC.cpp
>>>> > cfe/trunk/lib/Sema/SemaObjCProperty.cpp
>>>> > cfe/trunk/lib/Serialization/ASTWriter.cpp
>>>> > cfe/trunk/test/FixIt/atomic-property.m
>>>> > cfe/trunk/test/Index/complete-kvc.m
>>>> > cfe/trunk/test/Modules/ModuleDebugInfo.m
>>>> > cfe/trunk/test/PCH/chain-categories.m
>>>> > cfe/trunk/test/SemaObjC/atomoic-property-synnthesis-rules.m
>>>> > cfe/trunk/test/SemaObjC/property-3.m
>>>> > cfe/trunk/test/SemaObjC/property-in-class-extension-1.m
>>>> > cfe/trunk/test/SemaObjCXX/property-invalid-type.mm
>>>> >
>>>> > Modified: cfe/trunk/include/clang/AST/ASTMutationListener.h
>>>> > URL:
>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTMutationListener.h?rev=251874&r1=251873&r2=251874&view=diff
>>>> >
>>>> ==============================================================================
>>>> > --- cfe/trunk/include/clang/AST/ASTMutationListener.h (original)
>>>> > +++ cfe/trunk/include/clang/AST/ASTMutationListener.h Mon Nov 2
>>>> 19:15:46 2015
>>>> > @@ -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
>>>> >
>>>> > Modified: cfe/trunk/include/clang/AST/DeclObjC.h
>>>> > URL:
>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclObjC.h?rev=251874&r1=251873&r2=251874&view=diff
>>>> >
>>>> ==============================================================================
>>>> > --- cfe/trunk/include/clang/AST/DeclObjC.h (original)
>>>> > +++ cfe/trunk/include/clang/AST/DeclObjC.h Mon Nov 2 19:15:46 2015
>>>> > @@ -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.
>>>> >
>>>> > Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>>>> > URL:
>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=251874&r1=251873&r2=251874&view=diff
>>>> >
>>>> ==============================================================================
>>>> > --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
>>>> > +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Nov 2
>>>> 19:15:46 2015
>>>> > @@ -884,7 +884,8 @@ def err_property_type : Error<"property
>>>> > 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">;
>>>> >
>>>> > Modified: cfe/trunk/include/clang/Sema/Sema.h
>>>> > URL:
>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=251874&r1=251873&r2=251874&view=diff
>>>> >
>>>> ==============================================================================
>>>> > --- cfe/trunk/include/clang/Sema/Sema.h (original)
>>>> > +++ cfe/trunk/include/clang/Sema/Sema.h Mon Nov 2 19:15:46 2015
>>>> > @@ -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);
>>>> >
>>>> >
>>>> > Modified: cfe/trunk/include/clang/Serialization/ASTWriter.h
>>>> > URL:
>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTWriter.h?rev=251874&r1=251873&r2=251874&view=diff
>>>> >
>>>> ==============================================================================
>>>> > --- cfe/trunk/include/clang/Serialization/ASTWriter.h (original)
>>>> > +++ cfe/trunk/include/clang/Serialization/ASTWriter.h Mon Nov 2
>>>> 19:15:46 2015
>>>> > @@ -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;
>>>> >
>>>> > Modified: cfe/trunk/lib/ARCMigrate/TransProperties.cpp
>>>> > URL:
>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/TransProperties.cpp?rev=251874&r1=251873&r2=251874&view=diff
>>>> >
>>>> ==============================================================================
>>>> > --- cfe/trunk/lib/ARCMigrate/TransProperties.cpp (original)
>>>> > +++ cfe/trunk/lib/ARCMigrate/TransProperties.cpp Mon Nov 2 19:15:46
>>>> 2015
>>>> > @@ -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);
>>>> >
>>>> >
>>>> > Modified: cfe/trunk/lib/AST/DeclObjC.cpp
>>>> > URL:
>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclObjC.cpp?rev=251874&r1=251873&r2=251874&view=diff
>>>> >
>>>> ==============================================================================
>>>> > --- cfe/trunk/lib/AST/DeclObjC.cpp (original)
>>>> > +++ cfe/trunk/lib/AST/DeclObjC.cpp Mon Nov 2 19:15:46 2015
>>>> > @@ -161,6 +161,15 @@ ObjCPropertyDecl::findPropertyDecl(const
>>>> > 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::Fin
>>>> > 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::Fin
>>>> > }
>>>> > 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::collectPropertie
>>>> > 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 Ch
>>>> >
>>>> > 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!");
>>>> >
>>>> > Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp
>>>> > URL:
>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.cpp?rev=251874&r1=251873&r2=251874&view=diff
>>>> >
>>>> ==============================================================================
>>>> > --- cfe/trunk/lib/CodeGen/CGDebugInfo.cpp (original)
>>>> > +++ cfe/trunk/lib/CodeGen/CGDebugInfo.cpp Mon Nov 2 19:15:46 2015
>>>> > @@ -216,6 +216,13 @@ StringRef CGDebugInfo::getObjCMethodName
>>>> > } 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()
>>>> << '('
>>>> >
>>>> > Modified: cfe/trunk/lib/Frontend/MultiplexConsumer.cpp
>>>> > URL:
>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/MultiplexConsumer.cpp?rev=251874&r1=251873&r2=251874&view=diff
>>>> >
>>>> ==============================================================================
>>>> > --- cfe/trunk/lib/Frontend/MultiplexConsumer.cpp (original)
>>>> > +++ cfe/trunk/lib/Frontend/MultiplexConsumer.cpp Mon Nov 2 19:15:46
>>>> 2015
>>>> > @@ -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::Funct
>>>> > 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);
>>>> >
>>>> > Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
>>>> > URL:
>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=251874&r1=251873&r2=251874&view=diff
>>>> >
>>>> ==============================================================================
>>>> > --- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
>>>> > +++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Mon Nov 2 19:15:46 2015
>>>> > @@ -2844,6 +2844,20 @@ void Sema::ImplMethodsVsClassMethods(Sco
>>>> > 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.
>>>> >
>>>> > Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
>>>> > URL:
>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=251874&r1=251873&r2=251874&view=diff
>>>> >
>>>> ==============================================================================
>>>> > --- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
>>>> > +++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Mon Nov 2 19:15:46 2015
>>>> > @@ -1779,8 +1779,7 @@ HandleExprPropertyRefExpr(const ObjCObje
>>>> > 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))
>>>> >
>>>> > Modified: cfe/trunk/lib/Sema/SemaObjCProperty.cpp
>>>> > URL:
>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaObjCProperty.cpp?rev=251874&r1=251873&r2=251874&view=diff
>>>> >
>>>> ==============================================================================
>>>> > --- cfe/trunk/lib/Sema/SemaObjCProperty.cpp (original)
>>>> > +++ cfe/trunk/lib/Sema/SemaObjCProperty.cpp Mon Nov 2 19:15:46 2015
>>>> > @@ -262,8 +262,12 @@ Decl *Sema::ActOnProperty(Scope *S, Sour
>>>> > }
>>>> > }
>>>> > } 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(Sco
>>>> > 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(Sco
>>>> > 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(Sco
>>>> > 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(Sco
>>>> > 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(O
>>>> > 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(O
>>>> > }
>>>> > }
>>>> > 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(Obj
>>>> > (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::diagnoseNullResettableSynthes
>>>> >
>>>> > 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 (O
>>>> > << 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(ObjCPrope
>>>> > 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(ObjCPrope
>>>> > // 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(ObjCPrope
>>>> > // 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,
>>>> >
>>>> > Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
>>>> > URL:
>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=251874&r1=251873&r2=251874&view=diff
>>>> >
>>>> ==============================================================================
>>>> > --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
>>>> > +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Mon Nov 2 19:15:46 2015
>>>> > @@ -5756,21 +5756,6 @@ void ASTWriter::AddedObjCCategoryToInter
>>>> > 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())
>>>> >
>>>> > Modified: cfe/trunk/test/FixIt/atomic-property.m
>>>> > URL:
>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/atomic-property.m?rev=251874&r1=251873&r2=251874&view=diff
>>>> >
>>>> ==============================================================================
>>>> > --- cfe/trunk/test/FixIt/atomic-property.m (original)
>>>> > +++ cfe/trunk/test/FixIt/atomic-property.m Mon Nov 2 19:15:46 2015
>>>> > @@ -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, "
>>>> >
>>>> >
>>>> > Modified: cfe/trunk/test/Index/complete-kvc.m
>>>> > URL:
>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/complete-kvc.m?rev=251874&r1=251873&r2=251874&view=diff
>>>> >
>>>> ==============================================================================
>>>> > --- cfe/trunk/test/Index/complete-kvc.m (original)
>>>> > +++ cfe/trunk/test/Index/complete-kvc.m Mon Nov 2 19:15:46 2015
>>>> > @@ -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)
>>>> >
>>>> > Modified: cfe/trunk/test/Modules/ModuleDebugInfo.m
>>>> > URL:
>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/ModuleDebugInfo.m?rev=251874&r1=251873&r2=251874&view=diff
>>>> >
>>>> ==============================================================================
>>>> > --- cfe/trunk/test/Modules/ModuleDebugInfo.m (original)
>>>> > +++ cfe/trunk/test/Modules/ModuleDebugInfo.m Mon Nov 2 19:15:46 2015
>>>> > @@ -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]+]],
>>>> >
>>>> > Modified: cfe/trunk/test/PCH/chain-categories.m
>>>> > URL:
>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/chain-categories.m?rev=251874&r1=251873&r2=251874&view=diff
>>>> >
>>>> ==============================================================================
>>>> > --- cfe/trunk/test/PCH/chain-categories.m (original)
>>>> > +++ cfe/trunk/test/PCH/chain-categories.m Mon Nov 2 19:15:46 2015
>>>> > @@ -16,6 +16,10 @@
>>>> > - (void)finalize;
>>>> > @end
>>>> >
>>>> > + at interface NSObject (Properties)
>>>> > + at property (readonly,nonatomic) int intProp;
>>>> > + at end
>>>> > +
>>>> >
>>>> //===----------------------------------------------------------------------===//
>>>> > #elif !defined(HEADER2)
>>>> > #define HEADER2
>>>> > @@ -34,6 +38,12 @@
>>>> > -(void)extMeth;
>>>> > @end
>>>> >
>>>> > + at interface NSObject ()
>>>> > + at property (readwrite,nonatomic) int intProp;
>>>> > + at end
>>>> > +
>>>> > + at 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;
>>>> > }
>>>> >
>>>> >
>>>> //===----------------------------------------------------------------------===//
>>>> >
>>>> > Modified: cfe/trunk/test/SemaObjC/atomoic-property-synnthesis-rules.m
>>>> > URL:
>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/atomoic-property-synnthesis-rules.m?rev=251874&r1=251873&r2=251874&view=diff
>>>> >
>>>> ==============================================================================
>>>> > --- cfe/trunk/test/SemaObjC/atomoic-property-synnthesis-rules.m
>>>> (original)
>>>> > +++ cfe/trunk/test/SemaObjC/atomoic-property-synnthesis-rules.m Mon
>>>> Nov 2 19:15:46 2015
>>>> > @@ -129,10 +129,8 @@
>>>> >
>>>> > // read-only in class, read-write in class extension - might warn
>>>> > @property(readonly) int GetSet_ReadWriteInExt;
>>>> > - at property(readonly) int Get_ReadWriteInExt; // expected-note
>>>> {{property declared here}} \
>>>> > - // expected-note
>>>> {{setter and getter must both be synthesized}}
>>>> > - at property(readonly) int Set_ReadWriteInExt; // expected-note
>>>> {{property declared here}} \
>>>> > - // expected-note
>>>> {{setter and getter must both be synthesized}}
>>>> > + at property(readonly) int Get_ReadWriteInExt;
>>>> > + at 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;
>>>> > - at property(readonly) int Get_ReadWriteInExt_LateSynthesize; //
>>>> expected-note {{property declared here}} \
>>>> > - //
>>>> expected-note {{setter and getter must both be synthesized}}
>>>> > - at property(readonly) int Set_ReadWriteInExt_LateSynthesize; //
>>>> expected-note {{property declared here}} \
>>>> > - //
>>>> expected-note {{setter and getter must both be synthesized}}
>>>> > + at property(readonly) int Get_ReadWriteInExt_LateSynthesize;
>>>> > + at 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;
>>>> > - at property(readwrite) int Get_ReadWriteInExt;
>>>> > - at property(readwrite) int Set_ReadWriteInExt;
>>>> > + at property(readwrite) int Get_ReadWriteInExt; // expected-note
>>>> {{property declared here}} \
>>>> > + // expected-note
>>>> {{setter and getter must both be synthesized}}
>>>> > + at 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;
>>>> > - at property(readwrite) int Get_ReadWriteInExt_LateSynthesize;
>>>> > - at property(readwrite) int Set_ReadWriteInExt_LateSynthesize;
>>>> > + at property(readwrite) int Get_ReadWriteInExt_LateSynthesize; //
>>>> expected-note {{property declared here}} \
>>>> > + //
>>>> expected-note {{setter and getter must both be synthesized}}
>>>> > + at 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;
>>>> >
>>>> > Modified: cfe/trunk/test/SemaObjC/property-3.m
>>>> > URL:
>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/property-3.m?rev=251874&r1=251873&r2=251874&view=diff
>>>> >
>>>> ==============================================================================
>>>> > --- cfe/trunk/test/SemaObjC/property-3.m (original)
>>>> > +++ cfe/trunk/test/SemaObjC/property-3.m Mon Nov 2 19:15:46 2015
>>>> > @@ -29,5 +29,5 @@ typedef signed char BOOL;
>>>> >
>>>> > @interface EKCalendar () <EKProtocolMutableCalendar>
>>>> > @property (nonatomic, assign) BOOL allowReminders;
>>>> > - at property (nonatomic, assign) BOOL allowNonatomicProperty; //
>>>> expected-warning {{'atomic' attribute on property 'allowNonatomicProperty'
>>>> does not match the property inherited from 'EKProtocolCalendar'}}
>>>> > + at property (nonatomic, assign) BOOL allowNonatomicProperty; //
>>>> expected-warning {{'atomic' attribute on property 'allowNonatomicProperty'
>>>> does not match the property inherited from EKProtocolCalendar}}
>>>> > @end
>>>> >
>>>> > Modified: cfe/trunk/test/SemaObjC/property-in-class-extension-1.m
>>>> > URL:
>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/property-in-class-extension-1.m?rev=251874&r1=251873&r2=251874&view=diff
>>>> >
>>>> ==============================================================================
>>>> > --- cfe/trunk/test/SemaObjC/property-in-class-extension-1.m (original)
>>>> > +++ cfe/trunk/test/SemaObjC/property-in-class-extension-1.m Mon Nov
>>>> 2 19:15:46 2015
>>>> > @@ -10,7 +10,7 @@
>>>> >
>>>> > @property (nonatomic, copy, readonly) NSString* matchingMemoryModel;
>>>> >
>>>> > - at property (nonatomic, retain, readonly) NSString*
>>>> addingNoNewMemoryModel;
>>>> > + at 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}}
>>>> > +
>>>> > + at 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}}
>>>> > +
>>>> > + at property (atomic, readwrite) float propertyName2; //
>>>> expected-warning {{'atomic' attribute on property 'propertyName2' does not
>>>> match the property inherited from radar12214070}}
>>>> > @end
>>>> >
>>>> >
>>>> > Modified: cfe/trunk/test/SemaObjCXX/property-invalid-type.mm
>>>> > URL:
>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/property-invalid-type.mm?rev=251874&r1=251873&r2=251874&view=diff
>>>> >
>>>> ==============================================================================
>>>> > --- cfe/trunk/test/SemaObjCXX/property-invalid-type.mm (original)
>>>> > +++ cfe/trunk/test/SemaObjCXX/property-invalid-type.mm Mon Nov 2
>>>> 19:15:46 2015
>>>> > @@ -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}}
>>>> > }
>>>> >
>>>> >
>>>> > _______________________________________________
>>>> > cfe-commits mailing list
>>>> > cfe-commits at lists.llvm.org
>>>> > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>>
>>>> _______________________________________________
>>>> cfe-commits mailing list
>>>> cfe-commits at lists.llvm.org
>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>>
>>>
>>>
>>
> <propregression.patch>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20151203/124bbab5/attachment-0001.html>
-------------- next part --------------
Index: lib/CodeGen/CGObjCMac.cpp
===================================================================
--- lib/CodeGen/CGObjCMac.cpp (revision 254610)
+++ lib/CodeGen/CGObjCMac.cpp (working copy)
@@ -2908,15 +2908,26 @@
const ObjCCommonTypesHelper &ObjCTypes) {
SmallVector<llvm::Constant *, 16> Properties;
llvm::SmallPtrSet<const IdentifierInfo*, 16> PropertySet;
+
+ auto AddProperty = [&](const ObjCPropertyDecl *PD) {
+ llvm::Constant *Prop[] = {GetPropertyName(PD->getIdentifier()),
+ GetPropertyTypeString(PD, Container)};
+ Properties.push_back(llvm::ConstantStruct::get(ObjCTypes.PropertyTy, Prop));
+ };
+ if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD))
+ for (const ObjCCategoryDecl *ClassExt : OID->known_extensions())
+ for (auto *PD : ClassExt->properties()) {
+ PropertySet.insert(PD->getIdentifier());
+ AddProperty(PD);
+ }
for (const auto *PD : OCD->properties()) {
- PropertySet.insert(PD->getIdentifier());
- llvm::Constant *Prop[] = {
- GetPropertyName(PD->getIdentifier()),
- GetPropertyTypeString(PD, Container)
- };
- Properties.push_back(llvm::ConstantStruct::get(ObjCTypes.PropertyTy,
- Prop));
+ // Don't emit duplicate metadata for properties that were already in a
+ // class extension.
+ if (!PropertySet.insert(PD->getIdentifier()).second)
+ continue;
+ AddProperty(PD);
}
+
if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD)) {
for (const auto *P : OID->all_referenced_protocols())
PushProtocolProperties(PropertySet, Properties, Container, P, ObjCTypes);
Index: test/CodeGenObjC/property-list-in-extension.m
===================================================================
--- test/CodeGenObjC/property-list-in-extension.m (revision 0)
+++ test/CodeGenObjC/property-list-in-extension.m (working copy)
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s
+
+// Checks metadata for properties in a few cases.
+
+
+// Property from a class extension:
+ at interface Foo
+ at end
+
+ at interface Foo()
+ at property int myprop;
+ at end
+
+ at implementation Foo
+ at synthesize myprop = _myprop;
+ at end
+// Metadata for _myprop should be present, and PROP_LIST for Foo should have
+// only one entry.
+// CHECK: = private global [12 x i8] c"Ti,V_myprop\00",
+// CHECK: @"\01l_OBJC_$_PROP_LIST_Foo" = private global { i32, i32, [1 x %struct._prop_t] }
+
+// Readonly property in interface made readwrite in a category:
+ at interface FooRO
+ at property (readonly) int evolvingprop;
+ at end
+
+ at interface FooRO ()
+ at property int evolvingprop;
+ at end
+
+ at implementation FooRO
+ at synthesize evolvingprop = _evolvingprop;
+ at end
+// Metadata for _evolvingprop should be present, and PROP_LIST for FooRO should
+// still have only one entry, and the one entry should point to the version of
+// the property with a getter and setter.
+// CHECK: [[getter:@OBJC_PROP_NAME_ATTR[^ ]+]] = private global [13 x i8] c"evolvingprop\00"
+// CHECK: [[setter:@OBJC_PROP_NAME_ATTR[^ ]+]] = private global [18 x i8] c"Ti,V_evolvingprop\00",
+// CHECK: @"\01l_OBJC_$_PROP_LIST_FooRO" = private global { i32, i32, [1 x %struct._prop_t] }{{.*}}[[getter]]{{.*}}[[setter]]
More information about the cfe-commits
mailing list