diff options
Diffstat (limited to 'lib/Sema/SemaObjCProperty.cpp')
-rw-r--r-- | lib/Sema/SemaObjCProperty.cpp | 468 |
1 files changed, 290 insertions, 178 deletions
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 8d70860..c348a9c 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -13,16 +13,16 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/SemaInternal.h" -#include "clang/Sema/Initialization.h" +#include "clang/AST/ASTMutationListener.h" #include "clang/AST/DeclObjC.h" -#include "clang/AST/ExprObjC.h" #include "clang/AST/ExprCXX.h" -#include "clang/AST/ASTMutationListener.h" -#include "clang/Lex/Lexer.h" +#include "clang/AST/ExprObjC.h" #include "clang/Basic/SourceManager.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Sema/Initialization.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallString.h" -#include "clang/Lex/Preprocessor.h" using namespace clang; @@ -112,6 +112,33 @@ static unsigned deduceWeakPropertyFromType(Sema &S, QualType T) { return 0; } +/// \brief Check this Objective-C property against a property declared in the +/// given protocol. +static void +CheckPropertyAgainstProtocol(Sema &S, ObjCPropertyDecl *Prop, + ObjCProtocolDecl *Proto, + llvm::SmallPtrSet<ObjCProtocolDecl *, 16> &Known) { + // Have we seen this protocol before? + if (!Known.insert(Proto)) + return; + + // Look for a property with the same name. + DeclContext::lookup_result R = Proto->lookup(Prop->getDeclName()); + for (unsigned I = 0, N = R.size(); I != N; ++I) { + if (ObjCPropertyDecl *ProtoProp = dyn_cast<ObjCPropertyDecl>(R[I])) { + S.DiagnosePropertyMismatch(Prop, ProtoProp, Proto->getIdentifier()); + return; + } + } + + // Check this property against any protocols we inherit. + for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(), + PEnd = Proto->protocol_end(); + P != PEnd; ++P) { + CheckPropertyAgainstProtocol(S, Prop, *P, Known); + } +} + Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, SourceLocation LParenLoc, FieldDeclarator &FD, @@ -139,34 +166,31 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, !(Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) && !(Attributes & ObjCDeclSpec::DQ_PR_weak))); - // Proceed with constructing the ObjCPropertDecls. + // Proceed with constructing the ObjCPropertyDecls. ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(CurContext); - if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) + ObjCPropertyDecl *Res = 0; + if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) { if (CDecl->IsClassExtension()) { - Decl *Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc, + Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc, FD, GetterSel, SetterSel, isAssign, isReadWrite, Attributes, ODS.getPropertyAttributes(), isOverridingProperty, TSI, MethodImplKind); - if (Res) { - CheckObjCPropertyAttributes(Res, AtLoc, Attributes, false); - if (getLangOpts().ObjCAutoRefCount) - checkARCPropertyDecl(*this, cast<ObjCPropertyDecl>(Res)); - } - ActOnDocumentableDecl(Res); - return Res; + if (!Res) + return 0; } - - ObjCPropertyDecl *Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD, - GetterSel, SetterSel, - isAssign, isReadWrite, - Attributes, - ODS.getPropertyAttributes(), - TSI, MethodImplKind); - if (lexicalDC) - Res->setLexicalDeclContext(lexicalDC); + } + + if (!Res) { + Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD, + GetterSel, SetterSel, isAssign, isReadWrite, + Attributes, ODS.getPropertyAttributes(), + TSI, MethodImplKind); + if (lexicalDC) + Res->setLexicalDeclContext(lexicalDC); + } // Validate the attributes on the @property. CheckObjCPropertyAttributes(Res, AtLoc, Attributes, @@ -176,6 +200,52 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, if (getLangOpts().ObjCAutoRefCount) checkARCPropertyDecl(*this, Res); + llvm::SmallPtrSet<ObjCProtocolDecl *, 16> KnownProtos; + if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) { + // For a class, compare the property against a property in our superclass. + bool FoundInSuper = false; + if (ObjCInterfaceDecl *Super = IFace->getSuperClass()) { + DeclContext::lookup_result R = Super->lookup(Res->getDeclName()); + for (unsigned I = 0, N = R.size(); I != N; ++I) { + if (ObjCPropertyDecl *SuperProp = dyn_cast<ObjCPropertyDecl>(R[I])) { + DiagnosePropertyMismatch(Res, SuperProp, Super->getIdentifier()); + FoundInSuper = true; + break; + } + } + } + + if (FoundInSuper) { + // Also compare the property against a property in our protocols. + for (ObjCInterfaceDecl::protocol_iterator P = IFace->protocol_begin(), + PEnd = IFace->protocol_end(); + P != PEnd; ++P) { + CheckPropertyAgainstProtocol(*this, Res, *P, KnownProtos); + } + } else { + // Slower path: look in all protocols we referenced. + for (ObjCInterfaceDecl::all_protocol_iterator + P = IFace->all_referenced_protocol_begin(), + PEnd = IFace->all_referenced_protocol_end(); + P != PEnd; ++P) { + CheckPropertyAgainstProtocol(*this, Res, *P, KnownProtos); + } + } + } else if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(ClassDecl)) { + for (ObjCCategoryDecl::protocol_iterator P = Cat->protocol_begin(), + PEnd = Cat->protocol_end(); + P != PEnd; ++P) { + CheckPropertyAgainstProtocol(*this, Res, *P, KnownProtos); + } + } else { + ObjCProtocolDecl *Proto = cast<ObjCProtocolDecl>(ClassDecl); + for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(), + PEnd = Proto->protocol_end(); + P != PEnd; ++P) { + CheckPropertyAgainstProtocol(*this, Res, *P, KnownProtos); + } + } + ActOnDocumentableDecl(Res); return Res; } @@ -251,7 +321,7 @@ static unsigned getOwnershipRule(unsigned attr) { ObjCPropertyDecl::OBJC_PR_unsafe_unretained); } -Decl * +ObjCPropertyDecl * Sema::HandlePropertyInClassExtension(Scope *S, SourceLocation AtLoc, SourceLocation LParenLoc, @@ -270,20 +340,22 @@ Sema::HandlePropertyInClassExtension(Scope *S, IdentifierInfo *PropertyId = FD.D.getIdentifier(); ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface(); - if (CCPrimary) + if (CCPrimary) { // Check for duplicate declaration of this property in current and // other class extensions. - for (const ObjCCategoryDecl *ClsExtDecl = - CCPrimary->getFirstClassExtension(); - ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) { - if (ObjCPropertyDecl *prevDecl = - ObjCPropertyDecl::findPropertyDecl(ClsExtDecl, PropertyId)) { + for (ObjCInterfaceDecl::known_extensions_iterator + Ext = CCPrimary->known_extensions_begin(), + ExtEnd = CCPrimary->known_extensions_end(); + Ext != ExtEnd; ++Ext) { + if (ObjCPropertyDecl *prevDecl + = ObjCPropertyDecl::findPropertyDecl(*Ext, PropertyId)) { Diag(AtLoc, diag::err_duplicate_property); Diag(prevDecl->getLocation(), diag::note_property_declare); return 0; } } - + } + // Create a new ObjCPropertyDecl with the DeclContext being // the class extension. // FIXME. We should really be using CreatePropertyDecl for this. @@ -296,6 +368,10 @@ Sema::HandlePropertyInClassExtension(Scope *S, 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); // Set setter/getter selector name. Needed later. PDecl->setGetterName(GetterSel); PDecl->setSetterName(SetterSel); @@ -577,20 +653,20 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc, switch (propertyLifetime) { case Qualifiers::OCL_Strong: - S.Diag(propertyImplLoc, diag::err_arc_strong_property_ownership) + S.Diag(ivar->getLocation(), diag::err_arc_strong_property_ownership) << property->getDeclName() << ivar->getDeclName() << ivarLifetime; break; case Qualifiers::OCL_Weak: - S.Diag(propertyImplLoc, diag::error_weak_property) + S.Diag(ivar->getLocation(), diag::error_weak_property) << property->getDeclName() << ivar->getDeclName(); break; case Qualifiers::OCL_ExplicitNone: - S.Diag(propertyImplLoc, diag::err_arc_assign_property_ownership) + S.Diag(ivar->getLocation(), diag::err_arc_assign_property_ownership) << property->getDeclName() << ivar->getDeclName() << ((property->getPropertyAttributesAsWritten() @@ -606,6 +682,8 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc, } S.Diag(property->getLocation(), diag::note_property_declare); + if (propertyImplLoc.isValid()) + S.Diag(propertyImplLoc, diag::note_property_synthesize); } /// setImpliedPropertyAttributeForReadOnlyProperty - @@ -644,16 +722,18 @@ DiagnoseClassAndClassExtPropertyMismatch(Sema &S, ObjCInterfaceDecl *ClassDecl, ObjCPropertyDecl *property) { unsigned Attributes = property->getPropertyAttributesAsWritten(); bool warn = (Attributes & ObjCDeclSpec::DQ_PR_readonly); - for (const ObjCCategoryDecl *CDecl = ClassDecl->getFirstClassExtension(); - CDecl; CDecl = CDecl->getNextClassExtension()) { + for (ObjCInterfaceDecl::known_extensions_iterator + Ext = ClassDecl->known_extensions_begin(), + ExtEnd = ClassDecl->known_extensions_end(); + Ext != ExtEnd; ++Ext) { ObjCPropertyDecl *ClassExtProperty = 0; - for (ObjCContainerDecl::prop_iterator P = CDecl->prop_begin(), - E = CDecl->prop_end(); P != E; ++P) { - if ((*P)->getIdentifier() == property->getIdentifier()) { - ClassExtProperty = *P; + DeclContext::lookup_result R = Ext->lookup(property->getDeclName()); + for (unsigned I = 0, N = R.size(); I != N; ++I) { + ClassExtProperty = dyn_cast<ObjCPropertyDecl>(R[0]); + if (ClassExtProperty) break; - } } + if (ClassExtProperty) { warn = false; unsigned classExtPropertyAttr = @@ -763,22 +843,40 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, return 0; } } - if (Synthesize&& (PIkind & ObjCPropertyDecl::OBJC_PR_readonly) && property->hasAttr<IBOutletAttr>() && !AtLoc.isValid()) { - Diag(IC->getLocation(), diag::warn_auto_readonly_iboutlet_property); - Diag(property->getLocation(), diag::note_property_declare); - SourceLocation readonlyLoc; - if (LocPropertyAttribute(Context, "readonly", - property->getLParenLoc(), readonlyLoc)) { - SourceLocation endLoc = - readonlyLoc.getLocWithOffset(strlen("readonly")-1); - SourceRange ReadonlySourceRange(readonlyLoc, endLoc); - Diag(property->getLocation(), - diag::note_auto_readonly_iboutlet_fixup_suggest) << - FixItHint::CreateReplacement(ReadonlySourceRange, "readwrite"); + bool ReadWriteProperty = false; + // Search into the class extensions and see if 'readonly property is + // redeclared 'readwrite', then no warning is to be issued. + for (ObjCInterfaceDecl::known_extensions_iterator + Ext = IDecl->known_extensions_begin(), + ExtEnd = IDecl->known_extensions_end(); Ext != ExtEnd; ++Ext) { + DeclContext::lookup_result R = Ext->lookup(property->getDeclName()); + if (!R.empty()) + if (ObjCPropertyDecl *ExtProp = dyn_cast<ObjCPropertyDecl>(R[0])) { + PIkind = ExtProp->getPropertyAttributesAsWritten(); + if (PIkind & ObjCPropertyDecl::OBJC_PR_readwrite) { + ReadWriteProperty = true; + break; + } + } + } + + if (!ReadWriteProperty) { + Diag(property->getLocation(), diag::warn_auto_readonly_iboutlet_property) + << property->getName(); + SourceLocation readonlyLoc; + if (LocPropertyAttribute(Context, "readonly", + property->getLParenLoc(), readonlyLoc)) { + SourceLocation endLoc = + readonlyLoc.getLocWithOffset(strlen("readonly")-1); + SourceRange ReadonlySourceRange(readonlyLoc, endLoc); + Diag(property->getLocation(), + diag::note_auto_readonly_iboutlet_fixup_suggest) << + FixItHint::CreateReplacement(ReadonlySourceRange, "readwrite"); + } } } @@ -1036,6 +1134,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, MarkDeclRefReferenced(SelfExpr); Expr *IvarRefExpr = new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc, + Ivar->getLocation(), SelfExpr, true, true); ExprResult Res = PerformCopyInitialization(InitializedEntity::InitializeResult( @@ -1071,6 +1170,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, MarkDeclRefReferenced(SelfExpr); Expr *lhs = new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc, + Ivar->getLocation(), SelfExpr, true, true); ObjCMethodDecl::param_iterator P = setterMethod->param_begin(); ParmVarDecl *Param = (*P); @@ -1198,15 +1298,21 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property, } if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic) - != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)) + != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)) { Diag(Property->getLocation(), diag::warn_property_attribute) << Property->getDeclName() << "atomic" << inheritedName; - if (Property->getSetterName() != SuperProperty->getSetterName()) + Diag(SuperProperty->getLocation(), diag::note_property_declare); + } + if (Property->getSetterName() != SuperProperty->getSetterName()) { Diag(Property->getLocation(), diag::warn_property_attribute) << Property->getDeclName() << "setter" << inheritedName; - if (Property->getGetterName() != SuperProperty->getGetterName()) + Diag(SuperProperty->getLocation(), diag::note_property_declare); + } + if (Property->getGetterName() != SuperProperty->getGetterName()) { Diag(Property->getLocation(), diag::warn_property_attribute) << Property->getDeclName() << "getter" << inheritedName; + Diag(SuperProperty->getLocation(), diag::note_property_declare); + } QualType LHSType = Context.getCanonicalType(SuperProperty->getType()); @@ -1270,119 +1376,56 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property, return false; } -/// ComparePropertiesInBaseAndSuper - This routine compares property -/// declarations in base and its super class, if any, and issues -/// diagnostics in a variety of inconsistent situations. -/// -void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) { - ObjCInterfaceDecl *SDecl = IDecl->getSuperClass(); - if (!SDecl) - return; - // FIXME: O(N^2) - for (ObjCInterfaceDecl::prop_iterator S = SDecl->prop_begin(), - E = SDecl->prop_end(); S != E; ++S) { - ObjCPropertyDecl *SuperPDecl = *S; - // Does property in super class has declaration in current class? - for (ObjCInterfaceDecl::prop_iterator I = IDecl->prop_begin(), - E = IDecl->prop_end(); I != E; ++I) { - ObjCPropertyDecl *PDecl = *I; - if (SuperPDecl->getIdentifier() == PDecl->getIdentifier()) - DiagnosePropertyMismatch(PDecl, SuperPDecl, - SDecl->getIdentifier()); - } - } -} - /// MatchOneProtocolPropertiesInClass - This routine goes thru the list /// of properties declared in a protocol and compares their attribute against /// the same property declared in the class or category. void -Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl, - ObjCProtocolDecl *PDecl) { - ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl); - if (!IDecl) { - // Category - ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl); +Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl, ObjCProtocolDecl *PDecl) { + if (!CDecl) + return; + + // Category case. + if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) { + // FIXME: We should perform this check when the property in the category + // is declared. assert (CatDecl && "MatchOneProtocolPropertiesInClass"); if (!CatDecl->IsClassExtension()) for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), E = PDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Pr = *P; - ObjCCategoryDecl::prop_iterator CP, CE; - // Is this property already in category's list of properties? - for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP!=CE; ++CP) - if (CP->getIdentifier() == Pr->getIdentifier()) - break; - if (CP != CE) - // Property protocol already exist in class. Diagnose any mismatch. - DiagnosePropertyMismatch(*CP, Pr, PDecl->getIdentifier()); + ObjCPropertyDecl *ProtoProp = *P; + DeclContext::lookup_result R + = CatDecl->lookup(ProtoProp->getDeclName()); + for (unsigned I = 0, N = R.size(); I != N; ++I) { + if (ObjCPropertyDecl *CatProp = dyn_cast<ObjCPropertyDecl>(R[I])) { + if (CatProp != ProtoProp) { + // Property protocol already exist in class. Diagnose any mismatch. + DiagnosePropertyMismatch(CatProp, ProtoProp, + PDecl->getIdentifier()); + } + } + } } return; } - for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), - E = PDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Pr = *P; - ObjCInterfaceDecl::prop_iterator CP, CE; - // Is this property already in class's list of properties? - for (CP = IDecl->prop_begin(), CE = IDecl->prop_end(); CP != CE; ++CP) - if (CP->getIdentifier() == Pr->getIdentifier()) - break; - if (CP != CE) - // Property protocol already exist in class. Diagnose any mismatch. - DiagnosePropertyMismatch(*CP, Pr, PDecl->getIdentifier()); - } -} -/// CompareProperties - This routine compares properties -/// declared in 'ClassOrProtocol' objects (which can be a class or an -/// inherited protocol with the list of properties for class/category 'CDecl' -/// -void Sema::CompareProperties(Decl *CDecl, Decl *ClassOrProtocol) { - Decl *ClassDecl = ClassOrProtocol; - ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl); - - if (!IDecl) { - // Category - ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl); - assert (CatDecl && "CompareProperties"); - if (ObjCCategoryDecl *MDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) { - for (ObjCCategoryDecl::protocol_iterator P = MDecl->protocol_begin(), - E = MDecl->protocol_end(); P != E; ++P) - // Match properties of category with those of protocol (*P) - MatchOneProtocolPropertiesInClass(CatDecl, *P); - - // Go thru the list of protocols for this category and recursively match - // their properties with those in the category. - for (ObjCCategoryDecl::protocol_iterator P = CatDecl->protocol_begin(), - E = CatDecl->protocol_end(); P != E; ++P) - CompareProperties(CatDecl, *P); - } else { - ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl); - for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(), - E = MD->protocol_end(); P != E; ++P) - MatchOneProtocolPropertiesInClass(CatDecl, *P); + // Class + // FIXME: We should perform this check when the property in the class + // is declared. + ObjCInterfaceDecl *IDecl = cast<ObjCInterfaceDecl>(CDecl); + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), + E = PDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *ProtoProp = *P; + DeclContext::lookup_result R + = IDecl->lookup(ProtoProp->getDeclName()); + for (unsigned I = 0, N = R.size(); I != N; ++I) { + if (ObjCPropertyDecl *ClassProp = dyn_cast<ObjCPropertyDecl>(R[I])) { + if (ClassProp != ProtoProp) { + // Property protocol already exist in class. Diagnose any mismatch. + DiagnosePropertyMismatch(ClassProp, ProtoProp, + PDecl->getIdentifier()); + } + } } - return; - } - - if (ObjCInterfaceDecl *MDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) { - for (ObjCInterfaceDecl::all_protocol_iterator - P = MDecl->all_referenced_protocol_begin(), - E = MDecl->all_referenced_protocol_end(); P != E; ++P) - // Match properties of class IDecl with those of protocol (*P). - MatchOneProtocolPropertiesInClass(IDecl, *P); - - // Go thru the list of protocols for this class and recursively match - // their properties with those declared in the class. - for (ObjCInterfaceDecl::all_protocol_iterator - P = IDecl->all_referenced_protocol_begin(), - E = IDecl->all_referenced_protocol_end(); P != E; ++P) - CompareProperties(IDecl, *P); - } else { - ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl); - for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(), - E = MD->protocol_end(); P != E; ++P) - MatchOneProtocolPropertiesInClass(IDecl, *P); } } @@ -1402,14 +1445,14 @@ bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl, // Main class has the property as 'readonly'. Must search // through the category list to see if the property's // attribute has been over-ridden to 'readwrite'. - for (ObjCCategoryDecl *Category = IDecl->getCategoryList(); - Category; Category = Category->getNextClassCategory()) { - // Even if property is ready only, if a category has a user defined setter, - // it is not considered read only. - if (Category->getInstanceMethod(PDecl->getSetterName())) + for (ObjCInterfaceDecl::visible_categories_iterator + Cat = IDecl->visible_categories_begin(), + CatEnd = IDecl->visible_categories_end(); + Cat != CatEnd; ++Cat) { + if (Cat->getInstanceMethod(PDecl->getSetterName())) return false; ObjCPropertyDecl *P = - Category->FindPropertyDeclaration(PDecl->getIdentifier()); + Cat->FindPropertyDeclaration(PDecl->getIdentifier()); if (P && !P->isReadOnly()) return false; } @@ -1438,7 +1481,7 @@ bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl, } /// CollectImmediateProperties - This routine collects all properties in -/// the class and its conforming protocols; but not those it its super class. +/// the class and its conforming protocols; but not those in its super class. void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, ObjCContainerDecl::PropertyMap &PropMap, ObjCContainerDecl::PropertyMap &SuperPropMap) { @@ -1493,36 +1536,84 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, static void CollectSuperClassPropertyImplementations(ObjCInterfaceDecl *CDecl, ObjCInterfaceDecl::PropertyMap &PropMap) { if (ObjCInterfaceDecl *SDecl = CDecl->getSuperClass()) { + ObjCInterfaceDecl::PropertyDeclOrder PO; while (SDecl) { - SDecl->collectPropertiesToImplement(PropMap); + SDecl->collectPropertiesToImplement(PropMap, PO); SDecl = SDecl->getSuperClass(); } } } +/// IvarBacksCurrentMethodAccessor - This routine returns 'true' if 'IV' is +/// an ivar synthesized for 'Method' and 'Method' is a property accessor +/// declared in class 'IFace'. +bool +Sema::IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace, + ObjCMethodDecl *Method, ObjCIvarDecl *IV) { + if (!IV->getSynthesize()) + return false; + ObjCMethodDecl *IMD = IFace->lookupMethod(Method->getSelector(), + Method->isInstanceMethod()); + if (!IMD || !IMD->isPropertyAccessor()) + return false; + + // look up a property declaration whose one of its accessors is implemented + // by this method. + for (ObjCContainerDecl::prop_iterator P = IFace->prop_begin(), + E = IFace->prop_end(); P != E; ++P) { + ObjCPropertyDecl *property = *P; + if ((property->getGetterName() == IMD->getSelector() || + property->getSetterName() == IMD->getSelector()) && + (property->getPropertyIvarDecl() == IV)) + return true; + } + return false; +} + + /// \brief Default synthesizes all properties which must be synthesized /// in class's \@implementation. void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl, ObjCInterfaceDecl *IDecl) { ObjCInterfaceDecl::PropertyMap PropMap; - IDecl->collectPropertiesToImplement(PropMap); + ObjCInterfaceDecl::PropertyDeclOrder PropertyOrder; + IDecl->collectPropertiesToImplement(PropMap, PropertyOrder); if (PropMap.empty()) return; ObjCInterfaceDecl::PropertyMap SuperPropMap; CollectSuperClassPropertyImplementations(IDecl, SuperPropMap); - for (ObjCInterfaceDecl::PropertyMap::iterator - P = PropMap.begin(), E = PropMap.end(); P != E; ++P) { - ObjCPropertyDecl *Prop = P->second; + for (unsigned i = 0, e = PropertyOrder.size(); i != e; i++) { + ObjCPropertyDecl *Prop = PropertyOrder[i]; // If property to be implemented in the super class, ignore. - if (SuperPropMap[Prop->getIdentifier()]) + if (SuperPropMap[Prop->getIdentifier()]) { + ObjCPropertyDecl *PropInSuperClass = SuperPropMap[Prop->getIdentifier()]; + if ((Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite) && + (PropInSuperClass->getPropertyAttributes() & + ObjCPropertyDecl::OBJC_PR_readonly) && + !IMPDecl->getInstanceMethod(Prop->getSetterName()) && + !IDecl->HasUserDeclaredSetterMethod(Prop)) { + Diag(Prop->getLocation(), diag::warn_no_autosynthesis_property) + << Prop->getIdentifier()->getName(); + Diag(PropInSuperClass->getLocation(), diag::note_property_declare); + } continue; + } // Is there a matching property synthesize/dynamic? if (Prop->isInvalidDecl() || - Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional || - IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier())) + Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional) continue; + if (ObjCPropertyImplDecl *PID = + IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier())) { + if (PID->getPropertyDecl() != Prop) { + Diag(Prop->getLocation(), diag::warn_no_autosynthesis_shared_ivar_property) + << Prop->getIdentifier()->getName(); + if (!PID->getLocation().isInvalid()) + Diag(PID->getLocation(), diag::note_property_synthesize); + } + continue; + } // Property may have been synthesized by user. if (IMPDecl->FindPropertyImplDecl(Prop->getIdentifier())) continue; @@ -1571,12 +1662,25 @@ void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) { void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl *CDecl, const SelectorSet &InsMap) { - ObjCContainerDecl::PropertyMap SuperPropMap; - if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) - CollectSuperClassPropertyImplementations(IDecl, SuperPropMap); + ObjCContainerDecl::PropertyMap NoNeedToImplPropMap; + ObjCInterfaceDecl *IDecl; + // Gather properties which need not be implemented in this class + // or category. + if (!(IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl))) + if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) { + // For categories, no need to implement properties declared in + // its primary class (and its super classes) if property is + // declared in one of those containers. + if ((IDecl = C->getClassInterface())) { + ObjCInterfaceDecl::PropertyDeclOrder PO; + IDecl->collectPropertiesToImplement(NoNeedToImplPropMap, PO); + } + } + if (IDecl) + CollectSuperClassPropertyImplementations(IDecl, NoNeedToImplPropMap); ObjCContainerDecl::PropertyMap PropMap; - CollectImmediateProperties(CDecl, PropMap, SuperPropMap); + CollectImmediateProperties(CDecl, PropMap, NoNeedToImplPropMap); if (PropMap.empty()) return; @@ -1592,7 +1696,8 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, // Is there a matching propery synthesize/dynamic? if (Prop->isInvalidDecl() || Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional || - PropImplMap.count(Prop) || Prop->hasAttr<UnavailableAttr>()) + PropImplMap.count(Prop) || + Prop->getAvailability() == AR_Unavailable) continue; if (!InsMap.count(Prop->getGetterName())) { Diag(IMPDecl->getLocation(), @@ -1829,6 +1934,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, if (property->hasAttr<NSReturnsNotRetainedAttr>()) GetterMethod->addAttr( ::new (Context) NSReturnsNotRetainedAttr(Loc, Context)); + + if (getLangOpts().ObjCAutoRefCount) + CheckARCMethodDecl(GetterMethod); } else // A user declared getter will be synthesize when @synthesize of // the property with the same name is seen in the @implementation @@ -1866,7 +1974,6 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, property->getType().getUnqualifiedType(), /*TInfo=*/0, SC_None, - SC_None, 0); SetterMethod->setMethodParams(Context, Argument, ArrayRef<SourceLocation>()); @@ -1878,6 +1985,11 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, // and the real context should be the same. if (lexicalDC) SetterMethod->setLexicalDeclContext(lexicalDC); + + // It's possible for the user to have set a very odd custom + // setter selector that causes it to have a method family. + if (getLangOpts().ObjCAutoRefCount) + CheckARCMethodDecl(SetterMethod); } else // A user declared setter will be synthesize when @synthesize of // the property with the same name is seen in the @implementation |