summaryrefslogtreecommitdiffstats
path: root/lib/Sema/SemaObjCProperty.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaObjCProperty.cpp')
-rw-r--r--lib/Sema/SemaObjCProperty.cpp468
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
OpenPOWER on IntegriCloud