diff options
author | Douglas Gregor <dgregor@apple.com> | 2015-11-03 01:15:46 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2015-11-03 01:15:46 +0000 |
commit | acf4fd30398b9c9efb51c01f2b0b0ec5865e3ecb (patch) | |
tree | 5977ff57cce5ffbfa367032ce5044a7ec2482d73 /clang/lib/AST | |
parent | fa05aacd3b775431d3a8e8815740e38880c9a662 (diff) | |
download | bcm5719-llvm-acf4fd30398b9c9efb51c01f2b0b0ec5865e3ecb.tar.gz bcm5719-llvm-acf4fd30398b9c9efb51c01f2b0b0ec5865e3ecb.zip |
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.
llvm-svn: 251874
Diffstat (limited to 'clang/lib/AST')
-rw-r--r-- | clang/lib/AST/DeclObjC.cpp | 76 |
1 files changed, 65 insertions, 11 deletions
diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index 280c412ae8f..b5dc9e122c3 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/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!"); |