[cfe-commits] r98317 - in /cfe/trunk/lib/Sema: SemaDeclObjC.cpp SemaObjCProperty.cpp
Ted Kremenek
kremenek at apple.com
Thu Mar 11 16:38:38 PST 2010
Author: kremenek
Date: Thu Mar 11 18:38:38 2010
New Revision: 98317
URL: http://llvm.org/viewvc/llvm-project?rev=98317&view=rev
Log:
Split Sema logic for ObjC @property and @synthesize into
a separate file.
Added:
cfe/trunk/lib/Sema/SemaObjCProperty.cpp
Modified:
cfe/trunk/lib/Sema/SemaDeclObjC.cpp
Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=98317&r1=98316&r2=98317&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Thu Mar 11 18:38:38 2010
@@ -20,25 +20,6 @@
#include "clang/Parse/DeclSpec.h"
using namespace clang;
-bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
- ObjCMethodDecl *GetterMethod,
- SourceLocation Loc) {
- if (GetterMethod &&
- GetterMethod->getResultType() != property->getType()) {
- AssignConvertType result = Incompatible;
- if (property->getType()->isObjCObjectPointerType())
- result = CheckAssignmentConstraints(GetterMethod->getResultType(), property->getType());
- if (result != Compatible) {
- Diag(Loc, diag::warn_accessor_property_type_mismatch)
- << property->getDeclName()
- << GetterMethod->getSelector();
- Diag(GetterMethod->getLocation(), diag::note_declared_at);
- return true;
- }
- }
- return false;
-}
-
/// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible
/// and user declared, in the method definition's AST.
void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) {
@@ -361,171 +342,6 @@
}
}
-/// DiagnosePropertyMismatch - Compares two properties for their
-/// attributes and types and warns on a variety of inconsistencies.
-///
-void
-Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
- ObjCPropertyDecl *SuperProperty,
- const IdentifierInfo *inheritedName) {
- ObjCPropertyDecl::PropertyAttributeKind CAttr =
- Property->getPropertyAttributes();
- ObjCPropertyDecl::PropertyAttributeKind SAttr =
- SuperProperty->getPropertyAttributes();
- if ((CAttr & ObjCPropertyDecl::OBJC_PR_readonly)
- && (SAttr & ObjCPropertyDecl::OBJC_PR_readwrite))
- Diag(Property->getLocation(), diag::warn_readonly_property)
- << Property->getDeclName() << inheritedName;
- if ((CAttr & ObjCPropertyDecl::OBJC_PR_copy)
- != (SAttr & ObjCPropertyDecl::OBJC_PR_copy))
- Diag(Property->getLocation(), diag::warn_property_attribute)
- << Property->getDeclName() << "copy" << inheritedName;
- else if ((CAttr & ObjCPropertyDecl::OBJC_PR_retain)
- != (SAttr & ObjCPropertyDecl::OBJC_PR_retain))
- Diag(Property->getLocation(), diag::warn_property_attribute)
- << Property->getDeclName() << "retain" << inheritedName;
-
- if ((CAttr & 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(Property->getLocation(), diag::warn_property_attribute)
- << Property->getDeclName() << "setter" << inheritedName;
- if (Property->getGetterName() != SuperProperty->getGetterName())
- Diag(Property->getLocation(), diag::warn_property_attribute)
- << Property->getDeclName() << "getter" << inheritedName;
-
- QualType LHSType =
- Context.getCanonicalType(SuperProperty->getType());
- QualType RHSType =
- Context.getCanonicalType(Property->getType());
-
- if (!Context.typesAreCompatible(LHSType, RHSType)) {
- // FIXME: Incorporate this test with typesAreCompatible.
- if (LHSType->isObjCQualifiedIdType() && RHSType->isObjCQualifiedIdType())
- if (Context.ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false))
- return;
- Diag(Property->getLocation(), diag::warn_property_types_are_incompatible)
- << Property->getType() << SuperProperty->getType() << inheritedName;
- }
-}
-
-/// ComparePropertiesInBaseAndSuper - This routine compares property
-/// declarations in base and its super class, if any, and issues
-/// diagnostics in a variety of inconsistant 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);
- 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());
- }
- 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,
- DeclPtrTy ClassOrProtocol) {
- Decl *ClassDecl = ClassOrProtocol.getAs<Decl>();
- 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, DeclPtrTy::make(*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);
- }
- return;
- }
-
- if (ObjCInterfaceDecl *MDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
- for (ObjCInterfaceDecl::protocol_iterator P = MDecl->protocol_begin(),
- E = MDecl->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::protocol_iterator P = IDecl->protocol_begin(),
- E = IDecl->protocol_end(); P != E; ++P)
- CompareProperties(IDecl, DeclPtrTy::make(*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);
- }
-}
-
/// DiagnoseClassExtensionDupMethods - Check for duplicate declaration of
/// a class method in its extension.
///
@@ -941,57 +757,6 @@
}
}
-/// isPropertyReadonly - Return true if property is readonly, by searching
-/// for the property in the class and in its categories and implementations
-///
-bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl,
- ObjCInterfaceDecl *IDecl) {
- // by far the most common case.
- if (!PDecl->isReadOnly())
- return false;
- // Even if property is ready only, if interface has a user defined setter,
- // it is not considered read only.
- if (IDecl->getInstanceMethod(PDecl->getSetterName()))
- return false;
-
- // 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()))
- return false;
- ObjCPropertyDecl *P =
- Category->FindPropertyDeclaration(PDecl->getIdentifier());
- if (P && !P->isReadOnly())
- return false;
- }
-
- // Also, check for definition of a setter method in the implementation if
- // all else failed.
- if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(CurContext)) {
- if (ObjCImplementationDecl *IMD =
- dyn_cast<ObjCImplementationDecl>(OMD->getDeclContext())) {
- if (IMD->getInstanceMethod(PDecl->getSetterName()))
- return false;
- } else if (ObjCCategoryImplDecl *CIMD =
- dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) {
- if (CIMD->getInstanceMethod(PDecl->getSetterName()))
- return false;
- }
- }
- // Lastly, look through the implementation (if one is in scope).
- if (ObjCImplementationDecl *ImpDecl = IDecl->getImplementation())
- if (ImpDecl->getInstanceMethod(PDecl->getSetterName()))
- return false;
- // If all fails, look at the super class.
- if (ObjCInterfaceDecl *SIDecl = IDecl->getSuperClass())
- return isPropertyReadonly(PDecl, SIDecl);
- return true;
-}
-
/// FIXME: Type hierarchies in Objective-C can be deep. We could most likely
/// improve the efficiency of selector lookups and type checking by associating
/// with each protocol / interface / category the flattened instance tables. If
@@ -1131,140 +896,6 @@
}
}
-/// CollectImmediateProperties - This routine collects all properties in
-/// the class and its conforming protocols; but not those it its super class.
-void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
- llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) {
- if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
- for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
- E = IDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = (*P);
- PropMap[Prop->getIdentifier()] = Prop;
- }
- // scan through class's protocols.
- for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(),
- E = IDecl->protocol_end(); PI != E; ++PI)
- CollectImmediateProperties((*PI), PropMap);
- }
- if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
- if (!CATDecl->IsClassExtension())
- for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(),
- E = CATDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = (*P);
- PropMap[Prop->getIdentifier()] = Prop;
- }
- // scan through class's protocols.
- for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(),
- E = CATDecl->protocol_end(); PI != E; ++PI)
- CollectImmediateProperties((*PI), PropMap);
- }
- else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) {
- for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
- E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = (*P);
- ObjCPropertyDecl *&PropEntry = PropMap[Prop->getIdentifier()];
- if (!PropEntry)
- PropEntry = Prop;
- }
- // scan through protocol's protocols.
- for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
- E = PDecl->protocol_end(); PI != E; ++PI)
- CollectImmediateProperties((*PI), PropMap);
- }
-}
-
-/// LookupPropertyDecl - Looks up a property in the current class and all
-/// its protocols.
-ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl,
- IdentifierInfo *II) {
- if (const ObjCInterfaceDecl *IDecl =
- dyn_cast<ObjCInterfaceDecl>(CDecl)) {
- for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
- E = IDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = (*P);
- if (Prop->getIdentifier() == II)
- return Prop;
- }
- // scan through class's protocols.
- for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(),
- E = IDecl->protocol_end(); PI != E; ++PI) {
- ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II);
- if (Prop)
- return Prop;
- }
- }
- else if (const ObjCProtocolDecl *PDecl =
- dyn_cast<ObjCProtocolDecl>(CDecl)) {
- for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
- E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = (*P);
- if (Prop->getIdentifier() == II)
- return Prop;
- }
- // scan through protocol's protocols.
- for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
- E = PDecl->protocol_end(); PI != E; ++PI) {
- ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II);
- if (Prop)
- return Prop;
- }
- }
- return 0;
-}
-
-
-void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
- ObjCContainerDecl *CDecl,
- const llvm::DenseSet<Selector>& InsMap) {
- llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap;
- CollectImmediateProperties(CDecl, PropMap);
- if (PropMap.empty())
- return;
-
- llvm::DenseSet<ObjCPropertyDecl *> PropImplMap;
- for (ObjCImplDecl::propimpl_iterator
- I = IMPDecl->propimpl_begin(),
- EI = IMPDecl->propimpl_end(); I != EI; ++I)
- PropImplMap.insert((*I)->getPropertyDecl());
-
- for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator
- P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = P->second;
- // Is there a matching propery synthesize/dynamic?
- if (Prop->isInvalidDecl() ||
- Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
- PropImplMap.count(Prop))
- continue;
- if (LangOpts.ObjCNonFragileABI2) {
- ActOnPropertyImplDecl(IMPDecl->getLocation(),
- SourceLocation(),
- true, DeclPtrTy::make(IMPDecl),
- Prop->getIdentifier(),
- Prop->getIdentifier());
- continue;
- }
- if (!InsMap.count(Prop->getGetterName())) {
- Diag(Prop->getLocation(),
- isa<ObjCCategoryDecl>(CDecl) ?
- diag::warn_setter_getter_impl_required_in_category :
- diag::warn_setter_getter_impl_required)
- << Prop->getDeclName() << Prop->getGetterName();
- Diag(IMPDecl->getLocation(),
- diag::note_property_impl_required);
- }
-
- if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) {
- Diag(Prop->getLocation(),
- isa<ObjCCategoryDecl>(CDecl) ?
- diag::warn_setter_getter_impl_required_in_category :
- diag::warn_setter_getter_impl_required)
- << Prop->getDeclName() << Prop->getSetterName();
- Diag(IMPDecl->getLocation(),
- diag::note_property_impl_required);
- }
- }
-}
-
void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
ObjCContainerDecl* CDecl,
bool IncompleteImpl) {
@@ -1336,41 +967,6 @@
assert(false && "invalid ObjCContainerDecl type.");
}
-void
-Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
- ObjCContainerDecl* IDecl) {
- // Rules apply in non-GC mode only
- if (getLangOptions().getGCMode() != LangOptions::NonGC)
- return;
- for (ObjCContainerDecl::prop_iterator I = IDecl->prop_begin(),
- E = IDecl->prop_end();
- I != E; ++I) {
- ObjCPropertyDecl *Property = (*I);
- unsigned Attributes = Property->getPropertyAttributes();
- // We only care about readwrite atomic property.
- if ((Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) ||
- !(Attributes & ObjCPropertyDecl::OBJC_PR_readwrite))
- continue;
- if (const ObjCPropertyImplDecl *PIDecl
- = IMPDecl->FindPropertyImplDecl(Property->getIdentifier())) {
- if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
- continue;
- ObjCMethodDecl *GetterMethod =
- IMPDecl->getInstanceMethod(Property->getGetterName());
- ObjCMethodDecl *SetterMethod =
- IMPDecl->getInstanceMethod(Property->getSetterName());
- if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) {
- SourceLocation MethodLoc =
- (GetterMethod ? GetterMethod->getLocation()
- : SetterMethod->getLocation());
- Diag(MethodLoc, diag::warn_atomic_property_rule)
- << Property->getIdentifier();
- Diag(Property->getLocation(), diag::note_property_declare);
- }
- }
- }
-}
-
/// ActOnForwardClassDeclaration -
Action::DeclPtrTy
Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
@@ -1638,111 +1234,6 @@
return MethList.Method;
}
-/// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods
-/// have the property type and issue diagnostics if they don't.
-/// Also synthesize a getter/setter method if none exist (and update the
-/// appropriate lookup tables. FIXME: Should reconsider if adding synthesized
-/// methods is the "right" thing to do.
-void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
- ObjCContainerDecl *CD) {
- ObjCMethodDecl *GetterMethod, *SetterMethod;
-
- GetterMethod = CD->getInstanceMethod(property->getGetterName());
- SetterMethod = CD->getInstanceMethod(property->getSetterName());
- DiagnosePropertyAccessorMismatch(property, GetterMethod,
- property->getLocation());
-
- if (SetterMethod) {
- ObjCPropertyDecl::PropertyAttributeKind CAttr =
- property->getPropertyAttributes();
- if ((!(CAttr & ObjCPropertyDecl::OBJC_PR_readonly)) &&
- Context.getCanonicalType(SetterMethod->getResultType()) !=
- Context.VoidTy)
- Diag(SetterMethod->getLocation(), diag::err_setter_type_void);
- if (SetterMethod->param_size() != 1 ||
- ((*SetterMethod->param_begin())->getType() != property->getType())) {
- Diag(property->getLocation(),
- diag::warn_accessor_property_type_mismatch)
- << property->getDeclName()
- << SetterMethod->getSelector();
- Diag(SetterMethod->getLocation(), diag::note_declared_at);
- }
- }
-
- // Synthesize getter/setter methods if none exist.
- // Find the default getter and if one not found, add one.
- // FIXME: The synthesized property we set here is misleading. We almost always
- // synthesize these methods unless the user explicitly provided prototypes
- // (which is odd, but allowed). Sema should be typechecking that the
- // declarations jive in that situation (which it is not currently).
- if (!GetterMethod) {
- // 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.
- GetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(),
- property->getLocation(), property->getGetterName(),
- property->getType(), 0, CD, true, false, true,
- (property->getPropertyImplementation() ==
- ObjCPropertyDecl::Optional) ?
- ObjCMethodDecl::Optional :
- ObjCMethodDecl::Required);
- CD->addDecl(GetterMethod);
- } else
- // A user declared getter will be synthesize when @synthesize of
- // the property with the same name is seen in the @implementation
- GetterMethod->setSynthesized(true);
- property->setGetterMethodDecl(GetterMethod);
-
- // Skip setter if property is read-only.
- if (!property->isReadOnly()) {
- // Find the default setter and if one not found, add one.
- if (!SetterMethod) {
- // 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.
- SetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(),
- property->getLocation(),
- property->getSetterName(),
- Context.VoidTy, 0, CD, true, false, true,
- (property->getPropertyImplementation() ==
- ObjCPropertyDecl::Optional) ?
- ObjCMethodDecl::Optional :
- ObjCMethodDecl::Required);
- // Invent the arguments for the setter. We don't bother making a
- // nice name for the argument.
- ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod,
- property->getLocation(),
- property->getIdentifier(),
- property->getType(),
- /*TInfo=*/0,
- VarDecl::None,
- 0);
- SetterMethod->setMethodParams(Context, &Argument, 1);
- CD->addDecl(SetterMethod);
- } else
- // A user declared setter will be synthesize when @synthesize of
- // the property with the same name is seen in the @implementation
- SetterMethod->setSynthesized(true);
- property->setSetterMethodDecl(SetterMethod);
- }
- // Add any synthesized methods to the global pool. This allows us to
- // handle the following, which is supported by GCC (and part of the design).
- //
- // @interface Foo
- // @property double bar;
- // @end
- //
- // void thisIsUnfortunate() {
- // id foo;
- // double bar = [foo bar];
- // }
- //
- if (GetterMethod)
- AddInstanceMethodToGlobalPool(GetterMethod);
- if (SetterMethod)
- AddInstanceMethodToGlobalPool(SetterMethod);
-}
-
/// CompareMethodParamsInBaseAndSuper - This routine compares methods with
/// identical selector names in current and its super classes and issues
/// a warning if any of their argument types are incompatible.
@@ -2106,503 +1597,6 @@
return DeclPtrTy::make(ObjCMethod);
}
-void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
- SourceLocation Loc,
- unsigned &Attributes) {
- // FIXME: Improve the reported location.
-
- // readonly and readwrite/assign/retain/copy conflict.
- if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
- (Attributes & (ObjCDeclSpec::DQ_PR_readwrite |
- ObjCDeclSpec::DQ_PR_assign |
- ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_retain))) {
- const char * which = (Attributes & ObjCDeclSpec::DQ_PR_readwrite) ?
- "readwrite" :
- (Attributes & ObjCDeclSpec::DQ_PR_assign) ?
- "assign" :
- (Attributes & ObjCDeclSpec::DQ_PR_copy) ?
- "copy" : "retain";
-
- Diag(Loc, (Attributes & (ObjCDeclSpec::DQ_PR_readwrite)) ?
- diag::err_objc_property_attr_mutually_exclusive :
- diag::warn_objc_property_attr_mutually_exclusive)
- << "readonly" << which;
- }
-
- // Check for copy or retain on non-object types.
- if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) &&
- !PropertyTy->isObjCObjectPointerType() &&
- !PropertyTy->isBlockPointerType() &&
- !Context.isObjCNSObjectType(PropertyTy)) {
- Diag(Loc, diag::err_objc_property_requires_object)
- << (Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain");
- Attributes &= ~(ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain);
- }
-
- // Check for more than one of { assign, copy, retain }.
- if (Attributes & ObjCDeclSpec::DQ_PR_assign) {
- if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "assign" << "copy";
- Attributes &= ~ObjCDeclSpec::DQ_PR_copy;
- }
- if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "assign" << "retain";
- Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
- }
- } else if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
- if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "copy" << "retain";
- Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
- }
- }
-
- // Warn if user supplied no assignment attribute, property is
- // readwrite, and this is an object type.
- if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_retain)) &&
- !(Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
- PropertyTy->isObjCObjectPointerType()) {
- // Skip this warning in gc-only mode.
- if (getLangOptions().getGCMode() != LangOptions::GCOnly)
- Diag(Loc, diag::warn_objc_property_no_assignment_attribute);
-
- // If non-gc code warn that this is likely inappropriate.
- if (getLangOptions().getGCMode() == LangOptions::NonGC)
- Diag(Loc, diag::warn_objc_property_default_assign_on_object);
-
- // FIXME: Implement warning dependent on NSCopying being
- // implemented. See also:
- // <rdar://5168496&4855821&5607453&5096644&4947311&5698469&4947014&5168496>
- // (please trim this list while you are at it).
- }
-
- if (!(Attributes & ObjCDeclSpec::DQ_PR_copy)
- && getLangOptions().getGCMode() == LangOptions::GCOnly
- && PropertyTy->isBlockPointerType())
- Diag(Loc, diag::warn_objc_property_copy_missing_on_block);
-}
-
-Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
- FieldDeclarator &FD,
- ObjCDeclSpec &ODS,
- Selector GetterSel,
- Selector SetterSel,
- DeclPtrTy ClassCategory,
- bool *isOverridingProperty,
- tok::ObjCKeywordKind MethodImplKind) {
- unsigned Attributes = ODS.getPropertyAttributes();
- bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) ||
- // default is readwrite!
- !(Attributes & ObjCDeclSpec::DQ_PR_readonly));
- // property is defaulted to 'assign' if it is readwrite and is
- // not retain or copy
- bool isAssign = ((Attributes & ObjCDeclSpec::DQ_PR_assign) ||
- (isReadWrite &&
- !(Attributes & ObjCDeclSpec::DQ_PR_retain) &&
- !(Attributes & ObjCDeclSpec::DQ_PR_copy)));
- QualType T = GetTypeForDeclarator(FD.D, S);
- if (T->isReferenceType()) {
- Diag(AtLoc, diag::error_reference_property);
- return DeclPtrTy();
- }
- Decl *ClassDecl = ClassCategory.getAs<Decl>();
- ObjCInterfaceDecl *CCPrimary = 0; // continuation class's primary class
- // May modify Attributes.
- CheckObjCPropertyAttributes(T, AtLoc, Attributes);
- if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl))
- if (CDecl->IsClassExtension()) {
- // Diagnose if this property is already in continuation class.
- DeclContext *DC = dyn_cast<DeclContext>(ClassDecl);
- assert(DC && "ClassDecl is not a DeclContext");
- DeclContext::lookup_result Found = DC->lookup(FD.D.getIdentifier());
- if (Found.first != Found.second && isa<ObjCPropertyDecl>(*Found.first)) {
- Diag(AtLoc, diag::err_duplicate_property);
- Diag((*Found.first)->getLocation(), diag::note_property_declare);
- return DeclPtrTy();
- }
- ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
- FD.D.getIdentifierLoc(),
- FD.D.getIdentifier(),
- AtLoc, T);
- DC->addDecl(PDecl);
-
- // This is a continuation class. property requires special
- // handling.
- if ((CCPrimary = CDecl->getClassInterface())) {
- // Find the property in continuation class's primary class only.
- IdentifierInfo *PropertyId = FD.D.getIdentifier();
- if (ObjCPropertyDecl *PIDecl =
- CCPrimary->FindPropertyVisibleInPrimaryClass(PropertyId)) {
- // property 'PIDecl's readonly attribute will be over-ridden
- // with continuation class's readwrite property attribute!
- unsigned PIkind = PIDecl->getPropertyAttributes();
- if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) {
- unsigned retainCopyNonatomic =
- (ObjCPropertyDecl::OBJC_PR_retain |
- ObjCPropertyDecl::OBJC_PR_copy |
- ObjCPropertyDecl::OBJC_PR_nonatomic);
- if ((Attributes & retainCopyNonatomic) !=
- (PIkind & retainCopyNonatomic)) {
- Diag(AtLoc, diag::warn_property_attr_mismatch);
- Diag(PIDecl->getLocation(), diag::note_property_declare);
- }
- DeclContext *DC = dyn_cast<DeclContext>(CCPrimary);
- assert(DC && "ClassDecl is not a DeclContext");
- DeclContext::lookup_result Found =
- DC->lookup(PIDecl->getDeclName());
- bool PropertyInPrimaryClass = false;
- for (; Found.first != Found.second; ++Found.first)
- if (isa<ObjCPropertyDecl>(*Found.first)) {
- PropertyInPrimaryClass = true;
- break;
- }
- if (!PropertyInPrimaryClass) {
- // 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);
- DeclPtrTy ProtocolPtrTy =
- ActOnProperty(S, AtLoc, FD, ProtocolPropertyODS,
- PIDecl->getGetterName(),
- PIDecl->getSetterName(),
- DeclPtrTy::make(CCPrimary), isOverridingProperty,
- MethodImplKind);
- PIDecl = ProtocolPtrTy.getAs<ObjCPropertyDecl>();
- }
- PIDecl->makeitReadWriteAttribute();
- if (Attributes & ObjCDeclSpec::DQ_PR_retain)
- PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
- if (Attributes & ObjCDeclSpec::DQ_PR_copy)
- PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
- PIDecl->setSetterName(SetterSel);
- } else {
- Diag(AtLoc, diag::err_use_continuation_class)
- << CCPrimary->getDeclName();
- 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);
- return DeclPtrTy();
- }
-
- // No matching property found in the primary class. Just fall thru
- // and add property to continuation class's primary class.
- ClassDecl = CCPrimary;
- } else {
- Diag(CDecl->getLocation(), diag::err_continuation_class);
- *isOverridingProperty = true;
- return DeclPtrTy();
- }
- }
-
- // Issue a warning if property is 'assign' as default and its object, which is
- // gc'able conforms to NSCopying protocol
- if (getLangOptions().getGCMode() != LangOptions::NonGC &&
- isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign))
- if (T->isObjCObjectPointerType()) {
- QualType InterfaceTy = T->getPointeeType();
- if (const ObjCInterfaceType *OIT =
- InterfaceTy->getAs<ObjCInterfaceType>()) {
- ObjCInterfaceDecl *IDecl = OIT->getDecl();
- if (IDecl)
- if (ObjCProtocolDecl* PNSCopying =
- LookupProtocol(&Context.Idents.get("NSCopying")))
- if (IDecl->ClassImplementsProtocol(PNSCopying, true))
- Diag(AtLoc, diag::warn_implements_nscopying)
- << FD.D.getIdentifier();
- }
- }
- if (T->isObjCInterfaceType())
- Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object);
-
- DeclContext *DC = dyn_cast<DeclContext>(ClassDecl);
- assert(DC && "ClassDecl is not a DeclContext");
- ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
- FD.D.getIdentifierLoc(),
- FD.D.getIdentifier(),
- AtLoc, T);
- DeclContext::lookup_result Found = DC->lookup(PDecl->getDeclName());
- if (Found.first != Found.second && isa<ObjCPropertyDecl>(*Found.first)) {
- Diag(PDecl->getLocation(), diag::err_duplicate_property);
- Diag((*Found.first)->getLocation(), diag::note_property_declare);
- PDecl->setInvalidDecl();
- }
- else
- DC->addDecl(PDecl);
-
- if (T->isArrayType() || T->isFunctionType()) {
- Diag(AtLoc, diag::err_property_type) << T;
- PDecl->setInvalidDecl();
- }
-
- ProcessDeclAttributes(S, PDecl, FD.D);
-
- // Regardless of setter/getter attribute, we save the default getter/setter
- // selector names in anticipation of declaration of setter/getter methods.
- PDecl->setGetterName(GetterSel);
- PDecl->setSetterName(SetterSel);
-
- if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
-
- if (Attributes & ObjCDeclSpec::DQ_PR_getter)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_getter);
-
- if (Attributes & ObjCDeclSpec::DQ_PR_setter)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter);
-
- if (isReadWrite)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite);
-
- if (Attributes & ObjCDeclSpec::DQ_PR_retain)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
-
- if (Attributes & ObjCDeclSpec::DQ_PR_copy)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
-
- if (isAssign)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
-
- if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic);
-
- if (MethodImplKind == tok::objc_required)
- PDecl->setPropertyImplementation(ObjCPropertyDecl::Required);
- else if (MethodImplKind == tok::objc_optional)
- PDecl->setPropertyImplementation(ObjCPropertyDecl::Optional);
- // 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.
- if (CCPrimary)
- ProcessPropertyDecl(PDecl, CCPrimary);
-
- return DeclPtrTy::make(PDecl);
-}
-
-ObjCIvarDecl*
-Sema::SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl,
- IdentifierInfo *NameII) {
- ObjCIvarDecl *Ivar = 0;
- ObjCPropertyDecl *Prop = LookupPropertyDecl(IDecl, NameII);
- if (Prop && !Prop->isInvalidDecl()) {
- DeclContext *EnclosingContext = cast_or_null<DeclContext>(IDecl);
- QualType PropType = Context.getCanonicalType(Prop->getType());
- assert(EnclosingContext &&
- "null DeclContext for synthesized ivar - SynthesizeNewPropertyIvar");
- Ivar = ObjCIvarDecl::Create(Context, EnclosingContext,
- Prop->getLocation(),
- NameII, PropType, /*Dinfo=*/0,
- ObjCIvarDecl::Public,
- (Expr *)0);
- Ivar->setLexicalDeclContext(IDecl);
- IDecl->addDecl(Ivar);
- Prop->setPropertyIvarDecl(Ivar);
- }
- return Ivar;
-}
-
-/// ActOnPropertyImplDecl - This routine performs semantic checks and
-/// builds the AST node for a property implementation declaration; declared
-/// as @synthesize or @dynamic.
-///
-Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
- SourceLocation PropertyLoc,
- bool Synthesize,
- DeclPtrTy ClassCatImpDecl,
- IdentifierInfo *PropertyId,
- IdentifierInfo *PropertyIvar) {
- Decl *ClassImpDecl = ClassCatImpDecl.getAs<Decl>();
- // Make sure we have a context for the property implementation declaration.
- if (!ClassImpDecl) {
- Diag(AtLoc, diag::error_missing_property_context);
- return DeclPtrTy();
- }
- ObjCPropertyDecl *property = 0;
- ObjCInterfaceDecl* IDecl = 0;
- // Find the class or category class where this property must have
- // a declaration.
- ObjCImplementationDecl *IC = 0;
- ObjCCategoryImplDecl* CatImplClass = 0;
- if ((IC = dyn_cast<ObjCImplementationDecl>(ClassImpDecl))) {
- IDecl = IC->getClassInterface();
- // We always synthesize an interface for an implementation
- // without an interface decl. So, IDecl is always non-zero.
- assert(IDecl &&
- "ActOnPropertyImplDecl - @implementation without @interface");
-
- // Look for this property declaration in the @implementation's @interface
- property = IDecl->FindPropertyDeclaration(PropertyId);
- if (!property) {
- Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName();
- return DeclPtrTy();
- }
- if (const ObjCCategoryDecl *CD =
- dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) {
- if (!CD->IsClassExtension()) {
- Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName();
- Diag(property->getLocation(), diag::note_property_declare);
- return DeclPtrTy();
- }
- }
- } else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) {
- if (Synthesize) {
- Diag(AtLoc, diag::error_synthesize_category_decl);
- return DeclPtrTy();
- }
- IDecl = CatImplClass->getClassInterface();
- if (!IDecl) {
- Diag(AtLoc, diag::error_missing_property_interface);
- return DeclPtrTy();
- }
- ObjCCategoryDecl *Category =
- IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier());
-
- // If category for this implementation not found, it is an error which
- // has already been reported eralier.
- if (!Category)
- return DeclPtrTy();
- // Look for this property declaration in @implementation's category
- property = Category->FindPropertyDeclaration(PropertyId);
- if (!property) {
- Diag(PropertyLoc, diag::error_bad_category_property_decl)
- << Category->getDeclName();
- return DeclPtrTy();
- }
- } else {
- Diag(AtLoc, diag::error_bad_property_context);
- return DeclPtrTy();
- }
- ObjCIvarDecl *Ivar = 0;
- // Check that we have a valid, previously declared ivar for @synthesize
- if (Synthesize) {
- // @synthesize
- if (!PropertyIvar)
- PropertyIvar = PropertyId;
- QualType PropType = Context.getCanonicalType(property->getType());
- // Check that this is a previously declared 'ivar' in 'IDecl' interface
- ObjCInterfaceDecl *ClassDeclared;
- Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared);
- if (!Ivar) {
- DeclContext *EnclosingContext = cast_or_null<DeclContext>(ClassImpDecl);
- assert(EnclosingContext &&
- "null DeclContext for synthesized ivar - ActOnPropertyImplDecl");
- Ivar = ObjCIvarDecl::Create(Context, EnclosingContext, PropertyLoc,
- PropertyIvar, PropType, /*Dinfo=*/0,
- ObjCIvarDecl::Public,
- (Expr *)0);
- EnclosingContext->addDecl(Ivar);
- IDecl->makeDeclVisibleInContext(Ivar, false);
- property->setPropertyIvarDecl(Ivar);
-
- if (!getLangOptions().ObjCNonFragileABI)
- Diag(PropertyLoc, diag::error_missing_property_ivar_decl) << PropertyId;
- // Note! I deliberately want it to fall thru so, we have a
- // a property implementation and to avoid future warnings.
- } else if (getLangOptions().ObjCNonFragileABI &&
- ClassDeclared != IDecl) {
- Diag(PropertyLoc, diag::error_ivar_in_superclass_use)
- << property->getDeclName() << Ivar->getDeclName()
- << ClassDeclared->getDeclName();
- Diag(Ivar->getLocation(), diag::note_previous_access_declaration)
- << Ivar << Ivar->getNameAsCString();
- // Note! I deliberately want it to fall thru so more errors are caught.
- }
- QualType IvarType = Context.getCanonicalType(Ivar->getType());
-
- // Check that type of property and its ivar are type compatible.
- if (PropType != IvarType) {
- if (CheckAssignmentConstraints(PropType, IvarType) != Compatible) {
- Diag(PropertyLoc, diag::error_property_ivar_type)
- << property->getDeclName() << Ivar->getDeclName();
- // Note! I deliberately want it to fall thru so, we have a
- // a property implementation and to avoid future warnings.
- }
-
- // FIXME! Rules for properties are somewhat different that those
- // for assignments. Use a new routine to consolidate all cases;
- // specifically for property redeclarations as well as for ivars.
- QualType lhsType =Context.getCanonicalType(PropType).getUnqualifiedType();
- QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType();
- if (lhsType != rhsType &&
- lhsType->isArithmeticType()) {
- Diag(PropertyLoc, diag::error_property_ivar_type)
- << property->getDeclName() << Ivar->getDeclName();
- // Fall thru - see previous comment
- }
- // __weak is explicit. So it works on Canonical type.
- if (PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() &&
- getLangOptions().getGCMode() != LangOptions::NonGC) {
- Diag(PropertyLoc, diag::error_weak_property)
- << property->getDeclName() << Ivar->getDeclName();
- // Fall thru - see previous comment
- }
- if ((property->getType()->isObjCObjectPointerType() ||
- PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&
- getLangOptions().getGCMode() != LangOptions::NonGC) {
- Diag(PropertyLoc, diag::error_strong_property)
- << property->getDeclName() << Ivar->getDeclName();
- // Fall thru - see previous comment
- }
- }
- } else if (PropertyIvar)
- // @dynamic
- Diag(PropertyLoc, diag::error_dynamic_property_ivar_decl);
- assert (property && "ActOnPropertyImplDecl - property declaration missing");
- ObjCPropertyImplDecl *PIDecl =
- ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc,
- property,
- (Synthesize ?
- ObjCPropertyImplDecl::Synthesize
- : ObjCPropertyImplDecl::Dynamic),
- Ivar);
- if (IC) {
- if (Synthesize)
- if (ObjCPropertyImplDecl *PPIDecl =
- IC->FindPropertyImplIvarDecl(PropertyIvar)) {
- Diag(PropertyLoc, diag::error_duplicate_ivar_use)
- << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
- << PropertyIvar;
- Diag(PPIDecl->getLocation(), diag::note_previous_use);
- }
-
- if (ObjCPropertyImplDecl *PPIDecl
- = IC->FindPropertyImplDecl(PropertyId)) {
- Diag(PropertyLoc, diag::error_property_implemented) << PropertyId;
- Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
- return DeclPtrTy();
- }
- IC->addPropertyImplementation(PIDecl);
- } else {
- if (Synthesize)
- if (ObjCPropertyImplDecl *PPIDecl =
- CatImplClass->FindPropertyImplIvarDecl(PropertyIvar)) {
- Diag(PropertyLoc, diag::error_duplicate_ivar_use)
- << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
- << PropertyIvar;
- Diag(PPIDecl->getLocation(), diag::note_previous_use);
- }
-
- if (ObjCPropertyImplDecl *PPIDecl =
- CatImplClass->FindPropertyImplDecl(PropertyId)) {
- Diag(PropertyLoc, diag::error_property_implemented) << PropertyId;
- Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
- return DeclPtrTy();
- }
- CatImplClass->addPropertyImplementation(PIDecl);
- }
-
- return DeclPtrTy::make(PIDecl);
-}
-
bool Sema::CheckObjCDeclScope(Decl *D) {
if (isa<TranslationUnitDecl>(CurContext->getLookupContext()))
return false;
Added: cfe/trunk/lib/Sema/SemaObjCProperty.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaObjCProperty.cpp?rev=98317&view=auto
==============================================================================
--- cfe/trunk/lib/Sema/SemaObjCProperty.cpp (added)
+++ cfe/trunk/lib/Sema/SemaObjCProperty.cpp Thu Mar 11 18:38:38 2010
@@ -0,0 +1,1025 @@
+//===--- SemaObjCProperty.cpp - Semantic Analysis for ObjC @property ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for Objective C @property and
+// @synthesize declarations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+
+using namespace clang;
+
+/// DiagnosePropertyMismatch - Compares two properties for their
+/// attributes and types and warns on a variety of inconsistencies.
+///
+void
+Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
+ ObjCPropertyDecl *SuperProperty,
+ const IdentifierInfo *inheritedName) {
+ ObjCPropertyDecl::PropertyAttributeKind CAttr =
+ Property->getPropertyAttributes();
+ ObjCPropertyDecl::PropertyAttributeKind SAttr =
+ SuperProperty->getPropertyAttributes();
+ if ((CAttr & ObjCPropertyDecl::OBJC_PR_readonly)
+ && (SAttr & ObjCPropertyDecl::OBJC_PR_readwrite))
+ Diag(Property->getLocation(), diag::warn_readonly_property)
+ << Property->getDeclName() << inheritedName;
+ if ((CAttr & ObjCPropertyDecl::OBJC_PR_copy)
+ != (SAttr & ObjCPropertyDecl::OBJC_PR_copy))
+ Diag(Property->getLocation(), diag::warn_property_attribute)
+ << Property->getDeclName() << "copy" << inheritedName;
+ else if ((CAttr & ObjCPropertyDecl::OBJC_PR_retain)
+ != (SAttr & ObjCPropertyDecl::OBJC_PR_retain))
+ Diag(Property->getLocation(), diag::warn_property_attribute)
+ << Property->getDeclName() << "retain" << inheritedName;
+
+ if ((CAttr & 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(Property->getLocation(), diag::warn_property_attribute)
+ << Property->getDeclName() << "setter" << inheritedName;
+ if (Property->getGetterName() != SuperProperty->getGetterName())
+ Diag(Property->getLocation(), diag::warn_property_attribute)
+ << Property->getDeclName() << "getter" << inheritedName;
+
+ QualType LHSType =
+ Context.getCanonicalType(SuperProperty->getType());
+ QualType RHSType =
+ Context.getCanonicalType(Property->getType());
+
+ if (!Context.typesAreCompatible(LHSType, RHSType)) {
+ // FIXME: Incorporate this test with typesAreCompatible.
+ if (LHSType->isObjCQualifiedIdType() && RHSType->isObjCQualifiedIdType())
+ if (Context.ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false))
+ return;
+ Diag(Property->getLocation(), diag::warn_property_types_are_incompatible)
+ << Property->getType() << SuperProperty->getType() << inheritedName;
+ }
+}
+
+bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
+ ObjCMethodDecl *GetterMethod,
+ SourceLocation Loc) {
+ if (GetterMethod &&
+ GetterMethod->getResultType() != property->getType()) {
+ AssignConvertType result = Incompatible;
+ if (property->getType()->isObjCObjectPointerType())
+ result = CheckAssignmentConstraints(GetterMethod->getResultType(),
+ property->getType());
+ if (result != Compatible) {
+ Diag(Loc, diag::warn_accessor_property_type_mismatch)
+ << property->getDeclName()
+ << GetterMethod->getSelector();
+ Diag(GetterMethod->getLocation(), diag::note_declared_at);
+ return true;
+ }
+ }
+ return false;
+}
+
+/// ComparePropertiesInBaseAndSuper - This routine compares property
+/// declarations in base and its super class, if any, and issues
+/// diagnostics in a variety of inconsistant 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);
+ 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());
+ }
+ 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,
+ DeclPtrTy ClassOrProtocol) {
+ Decl *ClassDecl = ClassOrProtocol.getAs<Decl>();
+ 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, DeclPtrTy::make(*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);
+ }
+ return;
+ }
+
+ if (ObjCInterfaceDecl *MDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
+ for (ObjCInterfaceDecl::protocol_iterator P = MDecl->protocol_begin(),
+ E = MDecl->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::protocol_iterator P = IDecl->protocol_begin(),
+ E = IDecl->protocol_end(); P != E; ++P)
+ CompareProperties(IDecl, DeclPtrTy::make(*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);
+ }
+}
+
+/// isPropertyReadonly - Return true if property is readonly, by searching
+/// for the property in the class and in its categories and implementations
+///
+bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl,
+ ObjCInterfaceDecl *IDecl) {
+ // by far the most common case.
+ if (!PDecl->isReadOnly())
+ return false;
+ // Even if property is ready only, if interface has a user defined setter,
+ // it is not considered read only.
+ if (IDecl->getInstanceMethod(PDecl->getSetterName()))
+ return false;
+
+ // 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()))
+ return false;
+ ObjCPropertyDecl *P =
+ Category->FindPropertyDeclaration(PDecl->getIdentifier());
+ if (P && !P->isReadOnly())
+ return false;
+ }
+
+ // Also, check for definition of a setter method in the implementation if
+ // all else failed.
+ if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(CurContext)) {
+ if (ObjCImplementationDecl *IMD =
+ dyn_cast<ObjCImplementationDecl>(OMD->getDeclContext())) {
+ if (IMD->getInstanceMethod(PDecl->getSetterName()))
+ return false;
+ } else if (ObjCCategoryImplDecl *CIMD =
+ dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) {
+ if (CIMD->getInstanceMethod(PDecl->getSetterName()))
+ return false;
+ }
+ }
+ // Lastly, look through the implementation (if one is in scope).
+ if (ObjCImplementationDecl *ImpDecl = IDecl->getImplementation())
+ if (ImpDecl->getInstanceMethod(PDecl->getSetterName()))
+ return false;
+ // If all fails, look at the super class.
+ if (ObjCInterfaceDecl *SIDecl = IDecl->getSuperClass())
+ return isPropertyReadonly(PDecl, SIDecl);
+ return true;
+}
+
+/// CollectImmediateProperties - This routine collects all properties in
+/// the class and its conforming protocols; but not those it its super class.
+void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
+ llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) {
+ if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
+ for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
+ E = IDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ PropMap[Prop->getIdentifier()] = Prop;
+ }
+ // scan through class's protocols.
+ for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(),
+ E = IDecl->protocol_end(); PI != E; ++PI)
+ CollectImmediateProperties((*PI), PropMap);
+ }
+ if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
+ if (!CATDecl->IsClassExtension())
+ for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(),
+ E = CATDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ PropMap[Prop->getIdentifier()] = Prop;
+ }
+ // scan through class's protocols.
+ for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(),
+ E = CATDecl->protocol_end(); PI != E; ++PI)
+ CollectImmediateProperties((*PI), PropMap);
+ }
+ else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) {
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ ObjCPropertyDecl *&PropEntry = PropMap[Prop->getIdentifier()];
+ if (!PropEntry)
+ PropEntry = Prop;
+ }
+ // scan through protocol's protocols.
+ for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); PI != E; ++PI)
+ CollectImmediateProperties((*PI), PropMap);
+ }
+}
+
+/// LookupPropertyDecl - Looks up a property in the current class and all
+/// its protocols.
+ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl,
+ IdentifierInfo *II) {
+ if (const ObjCInterfaceDecl *IDecl =
+ dyn_cast<ObjCInterfaceDecl>(CDecl)) {
+ for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
+ E = IDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ if (Prop->getIdentifier() == II)
+ return Prop;
+ }
+ // scan through class's protocols.
+ for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(),
+ E = IDecl->protocol_end(); PI != E; ++PI) {
+ ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II);
+ if (Prop)
+ return Prop;
+ }
+ }
+ else if (const ObjCProtocolDecl *PDecl =
+ dyn_cast<ObjCProtocolDecl>(CDecl)) {
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ if (Prop->getIdentifier() == II)
+ return Prop;
+ }
+ // scan through protocol's protocols.
+ for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); PI != E; ++PI) {
+ ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II);
+ if (Prop)
+ return Prop;
+ }
+ }
+ return 0;
+}
+
+
+void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
+ ObjCContainerDecl *CDecl,
+ const llvm::DenseSet<Selector>& InsMap) {
+ llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap;
+ CollectImmediateProperties(CDecl, PropMap);
+ if (PropMap.empty())
+ return;
+
+ llvm::DenseSet<ObjCPropertyDecl *> PropImplMap;
+ for (ObjCImplDecl::propimpl_iterator
+ I = IMPDecl->propimpl_begin(),
+ EI = IMPDecl->propimpl_end(); I != EI; ++I)
+ PropImplMap.insert((*I)->getPropertyDecl());
+
+ for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator
+ P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = P->second;
+ // Is there a matching propery synthesize/dynamic?
+ if (Prop->isInvalidDecl() ||
+ Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
+ PropImplMap.count(Prop))
+ continue;
+ if (LangOpts.ObjCNonFragileABI2) {
+ ActOnPropertyImplDecl(IMPDecl->getLocation(),
+ SourceLocation(),
+ true, DeclPtrTy::make(IMPDecl),
+ Prop->getIdentifier(),
+ Prop->getIdentifier());
+ continue;
+ }
+ if (!InsMap.count(Prop->getGetterName())) {
+ Diag(Prop->getLocation(),
+ isa<ObjCCategoryDecl>(CDecl) ?
+ diag::warn_setter_getter_impl_required_in_category :
+ diag::warn_setter_getter_impl_required)
+ << Prop->getDeclName() << Prop->getGetterName();
+ Diag(IMPDecl->getLocation(),
+ diag::note_property_impl_required);
+ }
+
+ if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) {
+ Diag(Prop->getLocation(),
+ isa<ObjCCategoryDecl>(CDecl) ?
+ diag::warn_setter_getter_impl_required_in_category :
+ diag::warn_setter_getter_impl_required)
+ << Prop->getDeclName() << Prop->getSetterName();
+ Diag(IMPDecl->getLocation(),
+ diag::note_property_impl_required);
+ }
+ }
+}
+
+void
+Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
+ ObjCContainerDecl* IDecl) {
+ // Rules apply in non-GC mode only
+ if (getLangOptions().getGCMode() != LangOptions::NonGC)
+ return;
+ for (ObjCContainerDecl::prop_iterator I = IDecl->prop_begin(),
+ E = IDecl->prop_end();
+ I != E; ++I) {
+ ObjCPropertyDecl *Property = (*I);
+ unsigned Attributes = Property->getPropertyAttributes();
+ // We only care about readwrite atomic property.
+ if ((Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) ||
+ !(Attributes & ObjCPropertyDecl::OBJC_PR_readwrite))
+ continue;
+ if (const ObjCPropertyImplDecl *PIDecl
+ = IMPDecl->FindPropertyImplDecl(Property->getIdentifier())) {
+ if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
+ continue;
+ ObjCMethodDecl *GetterMethod =
+ IMPDecl->getInstanceMethod(Property->getGetterName());
+ ObjCMethodDecl *SetterMethod =
+ IMPDecl->getInstanceMethod(Property->getSetterName());
+ if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) {
+ SourceLocation MethodLoc =
+ (GetterMethod ? GetterMethod->getLocation()
+ : SetterMethod->getLocation());
+ Diag(MethodLoc, diag::warn_atomic_property_rule)
+ << Property->getIdentifier();
+ Diag(Property->getLocation(), diag::note_property_declare);
+ }
+ }
+ }
+}
+
+/// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods
+/// have the property type and issue diagnostics if they don't.
+/// Also synthesize a getter/setter method if none exist (and update the
+/// appropriate lookup tables. FIXME: Should reconsider if adding synthesized
+/// methods is the "right" thing to do.
+void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
+ ObjCContainerDecl *CD) {
+ ObjCMethodDecl *GetterMethod, *SetterMethod;
+
+ GetterMethod = CD->getInstanceMethod(property->getGetterName());
+ SetterMethod = CD->getInstanceMethod(property->getSetterName());
+ DiagnosePropertyAccessorMismatch(property, GetterMethod,
+ property->getLocation());
+
+ if (SetterMethod) {
+ ObjCPropertyDecl::PropertyAttributeKind CAttr =
+ property->getPropertyAttributes();
+ if ((!(CAttr & ObjCPropertyDecl::OBJC_PR_readonly)) &&
+ Context.getCanonicalType(SetterMethod->getResultType()) !=
+ Context.VoidTy)
+ Diag(SetterMethod->getLocation(), diag::err_setter_type_void);
+ if (SetterMethod->param_size() != 1 ||
+ ((*SetterMethod->param_begin())->getType() != property->getType())) {
+ Diag(property->getLocation(),
+ diag::warn_accessor_property_type_mismatch)
+ << property->getDeclName()
+ << SetterMethod->getSelector();
+ Diag(SetterMethod->getLocation(), diag::note_declared_at);
+ }
+ }
+
+ // Synthesize getter/setter methods if none exist.
+ // Find the default getter and if one not found, add one.
+ // FIXME: The synthesized property we set here is misleading. We almost always
+ // synthesize these methods unless the user explicitly provided prototypes
+ // (which is odd, but allowed). Sema should be typechecking that the
+ // declarations jive in that situation (which it is not currently).
+ if (!GetterMethod) {
+ // 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.
+ GetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(),
+ property->getLocation(), property->getGetterName(),
+ property->getType(), 0, CD, true, false, true,
+ (property->getPropertyImplementation() ==
+ ObjCPropertyDecl::Optional) ?
+ ObjCMethodDecl::Optional :
+ ObjCMethodDecl::Required);
+ CD->addDecl(GetterMethod);
+ } else
+ // A user declared getter will be synthesize when @synthesize of
+ // the property with the same name is seen in the @implementation
+ GetterMethod->setSynthesized(true);
+ property->setGetterMethodDecl(GetterMethod);
+
+ // Skip setter if property is read-only.
+ if (!property->isReadOnly()) {
+ // Find the default setter and if one not found, add one.
+ if (!SetterMethod) {
+ // 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.
+ SetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(),
+ property->getLocation(),
+ property->getSetterName(),
+ Context.VoidTy, 0, CD, true, false, true,
+ (property->getPropertyImplementation() ==
+ ObjCPropertyDecl::Optional) ?
+ ObjCMethodDecl::Optional :
+ ObjCMethodDecl::Required);
+ // Invent the arguments for the setter. We don't bother making a
+ // nice name for the argument.
+ ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod,
+ property->getLocation(),
+ property->getIdentifier(),
+ property->getType(),
+ /*TInfo=*/0,
+ VarDecl::None,
+ 0);
+ SetterMethod->setMethodParams(Context, &Argument, 1);
+ CD->addDecl(SetterMethod);
+ } else
+ // A user declared setter will be synthesize when @synthesize of
+ // the property with the same name is seen in the @implementation
+ SetterMethod->setSynthesized(true);
+ property->setSetterMethodDecl(SetterMethod);
+ }
+ // Add any synthesized methods to the global pool. This allows us to
+ // handle the following, which is supported by GCC (and part of the design).
+ //
+ // @interface Foo
+ // @property double bar;
+ // @end
+ //
+ // void thisIsUnfortunate() {
+ // id foo;
+ // double bar = [foo bar];
+ // }
+ //
+ if (GetterMethod)
+ AddInstanceMethodToGlobalPool(GetterMethod);
+ if (SetterMethod)
+ AddInstanceMethodToGlobalPool(SetterMethod);
+}
+
+void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
+ SourceLocation Loc,
+ unsigned &Attributes) {
+ // FIXME: Improve the reported location.
+
+ // readonly and readwrite/assign/retain/copy conflict.
+ if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
+ (Attributes & (ObjCDeclSpec::DQ_PR_readwrite |
+ ObjCDeclSpec::DQ_PR_assign |
+ ObjCDeclSpec::DQ_PR_copy |
+ ObjCDeclSpec::DQ_PR_retain))) {
+ const char * which = (Attributes & ObjCDeclSpec::DQ_PR_readwrite) ?
+ "readwrite" :
+ (Attributes & ObjCDeclSpec::DQ_PR_assign) ?
+ "assign" :
+ (Attributes & ObjCDeclSpec::DQ_PR_copy) ?
+ "copy" : "retain";
+
+ Diag(Loc, (Attributes & (ObjCDeclSpec::DQ_PR_readwrite)) ?
+ diag::err_objc_property_attr_mutually_exclusive :
+ diag::warn_objc_property_attr_mutually_exclusive)
+ << "readonly" << which;
+ }
+
+ // Check for copy or retain on non-object types.
+ if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) &&
+ !PropertyTy->isObjCObjectPointerType() &&
+ !PropertyTy->isBlockPointerType() &&
+ !Context.isObjCNSObjectType(PropertyTy)) {
+ Diag(Loc, diag::err_objc_property_requires_object)
+ << (Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain");
+ Attributes &= ~(ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain);
+ }
+
+ // Check for more than one of { assign, copy, retain }.
+ if (Attributes & ObjCDeclSpec::DQ_PR_assign) {
+ if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "assign" << "copy";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_copy;
+ }
+ if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "assign" << "retain";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
+ }
+ } else if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
+ if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "copy" << "retain";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
+ }
+ }
+
+ // Warn if user supplied no assignment attribute, property is
+ // readwrite, and this is an object type.
+ if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy |
+ ObjCDeclSpec::DQ_PR_retain)) &&
+ !(Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
+ PropertyTy->isObjCObjectPointerType()) {
+ // Skip this warning in gc-only mode.
+ if (getLangOptions().getGCMode() != LangOptions::GCOnly)
+ Diag(Loc, diag::warn_objc_property_no_assignment_attribute);
+
+ // If non-gc code warn that this is likely inappropriate.
+ if (getLangOptions().getGCMode() == LangOptions::NonGC)
+ Diag(Loc, diag::warn_objc_property_default_assign_on_object);
+
+ // FIXME: Implement warning dependent on NSCopying being
+ // implemented. See also:
+ // <rdar://5168496&4855821&5607453&5096644&4947311&5698469&4947014&5168496>
+ // (please trim this list while you are at it).
+ }
+
+ if (!(Attributes & ObjCDeclSpec::DQ_PR_copy)
+ && getLangOptions().getGCMode() == LangOptions::GCOnly
+ && PropertyTy->isBlockPointerType())
+ Diag(Loc, diag::warn_objc_property_copy_missing_on_block);
+}
+
+Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
+ FieldDeclarator &FD,
+ ObjCDeclSpec &ODS,
+ Selector GetterSel,
+ Selector SetterSel,
+ DeclPtrTy ClassCategory,
+ bool *isOverridingProperty,
+ tok::ObjCKeywordKind MethodImplKind) {
+ unsigned Attributes = ODS.getPropertyAttributes();
+ bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) ||
+ // default is readwrite!
+ !(Attributes & ObjCDeclSpec::DQ_PR_readonly));
+ // property is defaulted to 'assign' if it is readwrite and is
+ // not retain or copy
+ bool isAssign = ((Attributes & ObjCDeclSpec::DQ_PR_assign) ||
+ (isReadWrite &&
+ !(Attributes & ObjCDeclSpec::DQ_PR_retain) &&
+ !(Attributes & ObjCDeclSpec::DQ_PR_copy)));
+ QualType T = GetTypeForDeclarator(FD.D, S);
+ if (T->isReferenceType()) {
+ Diag(AtLoc, diag::error_reference_property);
+ return DeclPtrTy();
+ }
+ Decl *ClassDecl = ClassCategory.getAs<Decl>();
+ ObjCInterfaceDecl *CCPrimary = 0; // continuation class's primary class
+ // May modify Attributes.
+ CheckObjCPropertyAttributes(T, AtLoc, Attributes);
+ if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl))
+ if (CDecl->IsClassExtension()) {
+ // Diagnose if this property is already in continuation class.
+ DeclContext *DC = dyn_cast<DeclContext>(ClassDecl);
+ assert(DC && "ClassDecl is not a DeclContext");
+ DeclContext::lookup_result Found = DC->lookup(FD.D.getIdentifier());
+ if (Found.first != Found.second && isa<ObjCPropertyDecl>(*Found.first)) {
+ Diag(AtLoc, diag::err_duplicate_property);
+ Diag((*Found.first)->getLocation(), diag::note_property_declare);
+ return DeclPtrTy();
+ }
+ ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
+ FD.D.getIdentifierLoc(),
+ FD.D.getIdentifier(),
+ AtLoc, T);
+ DC->addDecl(PDecl);
+
+ // This is a continuation class. property requires special
+ // handling.
+ if ((CCPrimary = CDecl->getClassInterface())) {
+ // Find the property in continuation class's primary class only.
+ IdentifierInfo *PropertyId = FD.D.getIdentifier();
+ if (ObjCPropertyDecl *PIDecl =
+ CCPrimary->FindPropertyVisibleInPrimaryClass(PropertyId)) {
+ // property 'PIDecl's readonly attribute will be over-ridden
+ // with continuation class's readwrite property attribute!
+ unsigned PIkind = PIDecl->getPropertyAttributes();
+ if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) {
+ unsigned retainCopyNonatomic =
+ (ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_copy |
+ ObjCPropertyDecl::OBJC_PR_nonatomic);
+ if ((Attributes & retainCopyNonatomic) !=
+ (PIkind & retainCopyNonatomic)) {
+ Diag(AtLoc, diag::warn_property_attr_mismatch);
+ Diag(PIDecl->getLocation(), diag::note_property_declare);
+ }
+ DeclContext *DC = dyn_cast<DeclContext>(CCPrimary);
+ assert(DC && "ClassDecl is not a DeclContext");
+ DeclContext::lookup_result Found =
+ DC->lookup(PIDecl->getDeclName());
+ bool PropertyInPrimaryClass = false;
+ for (; Found.first != Found.second; ++Found.first)
+ if (isa<ObjCPropertyDecl>(*Found.first)) {
+ PropertyInPrimaryClass = true;
+ break;
+ }
+ if (!PropertyInPrimaryClass) {
+ // 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);
+ DeclPtrTy ProtocolPtrTy =
+ ActOnProperty(S, AtLoc, FD, ProtocolPropertyODS,
+ PIDecl->getGetterName(),
+ PIDecl->getSetterName(),
+ DeclPtrTy::make(CCPrimary), isOverridingProperty,
+ MethodImplKind);
+ PIDecl = ProtocolPtrTy.getAs<ObjCPropertyDecl>();
+ }
+ PIDecl->makeitReadWriteAttribute();
+ if (Attributes & ObjCDeclSpec::DQ_PR_retain)
+ PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
+ if (Attributes & ObjCDeclSpec::DQ_PR_copy)
+ PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
+ PIDecl->setSetterName(SetterSel);
+ } else {
+ Diag(AtLoc, diag::err_use_continuation_class)
+ << CCPrimary->getDeclName();
+ 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);
+ return DeclPtrTy();
+ }
+
+ // No matching property found in the primary class. Just fall thru
+ // and add property to continuation class's primary class.
+ ClassDecl = CCPrimary;
+ } else {
+ Diag(CDecl->getLocation(), diag::err_continuation_class);
+ *isOverridingProperty = true;
+ return DeclPtrTy();
+ }
+ }
+
+ // Issue a warning if property is 'assign' as default and its object, which is
+ // gc'able conforms to NSCopying protocol
+ if (getLangOptions().getGCMode() != LangOptions::NonGC &&
+ isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign))
+ if (T->isObjCObjectPointerType()) {
+ QualType InterfaceTy = T->getPointeeType();
+ if (const ObjCInterfaceType *OIT =
+ InterfaceTy->getAs<ObjCInterfaceType>()) {
+ ObjCInterfaceDecl *IDecl = OIT->getDecl();
+ if (IDecl)
+ if (ObjCProtocolDecl* PNSCopying =
+ LookupProtocol(&Context.Idents.get("NSCopying")))
+ if (IDecl->ClassImplementsProtocol(PNSCopying, true))
+ Diag(AtLoc, diag::warn_implements_nscopying)
+ << FD.D.getIdentifier();
+ }
+ }
+ if (T->isObjCInterfaceType())
+ Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object);
+
+ DeclContext *DC = dyn_cast<DeclContext>(ClassDecl);
+ assert(DC && "ClassDecl is not a DeclContext");
+ ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
+ FD.D.getIdentifierLoc(),
+ FD.D.getIdentifier(),
+ AtLoc, T);
+ DeclContext::lookup_result Found = DC->lookup(PDecl->getDeclName());
+ if (Found.first != Found.second && isa<ObjCPropertyDecl>(*Found.first)) {
+ Diag(PDecl->getLocation(), diag::err_duplicate_property);
+ Diag((*Found.first)->getLocation(), diag::note_property_declare);
+ PDecl->setInvalidDecl();
+ }
+ else
+ DC->addDecl(PDecl);
+
+ if (T->isArrayType() || T->isFunctionType()) {
+ Diag(AtLoc, diag::err_property_type) << T;
+ PDecl->setInvalidDecl();
+ }
+
+ ProcessDeclAttributes(S, PDecl, FD.D);
+
+ // Regardless of setter/getter attribute, we save the default getter/setter
+ // selector names in anticipation of declaration of setter/getter methods.
+ PDecl->setGetterName(GetterSel);
+ PDecl->setSetterName(SetterSel);
+
+ if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
+
+ if (Attributes & ObjCDeclSpec::DQ_PR_getter)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_getter);
+
+ if (Attributes & ObjCDeclSpec::DQ_PR_setter)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter);
+
+ if (isReadWrite)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite);
+
+ if (Attributes & ObjCDeclSpec::DQ_PR_retain)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
+
+ if (Attributes & ObjCDeclSpec::DQ_PR_copy)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
+
+ if (isAssign)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
+
+ if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic);
+
+ if (MethodImplKind == tok::objc_required)
+ PDecl->setPropertyImplementation(ObjCPropertyDecl::Required);
+ else if (MethodImplKind == tok::objc_optional)
+ PDecl->setPropertyImplementation(ObjCPropertyDecl::Optional);
+ // 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.
+ if (CCPrimary)
+ ProcessPropertyDecl(PDecl, CCPrimary);
+
+ return DeclPtrTy::make(PDecl);
+}
+
+ObjCIvarDecl*
+Sema::SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl,
+ IdentifierInfo *NameII) {
+ ObjCIvarDecl *Ivar = 0;
+ ObjCPropertyDecl *Prop = LookupPropertyDecl(IDecl, NameII);
+ if (Prop && !Prop->isInvalidDecl()) {
+ DeclContext *EnclosingContext = cast_or_null<DeclContext>(IDecl);
+ QualType PropType = Context.getCanonicalType(Prop->getType());
+ assert(EnclosingContext &&
+ "null DeclContext for synthesized ivar - SynthesizeNewPropertyIvar");
+ Ivar = ObjCIvarDecl::Create(Context, EnclosingContext,
+ Prop->getLocation(),
+ NameII, PropType, /*Dinfo=*/0,
+ ObjCIvarDecl::Public,
+ (Expr *)0);
+ Ivar->setLexicalDeclContext(IDecl);
+ IDecl->addDecl(Ivar);
+ Prop->setPropertyIvarDecl(Ivar);
+ }
+ return Ivar;
+}
+
+/// ActOnPropertyImplDecl - This routine performs semantic checks and
+/// builds the AST node for a property implementation declaration; declared
+/// as @synthesize or @dynamic.
+///
+Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
+ SourceLocation PropertyLoc,
+ bool Synthesize,
+ DeclPtrTy ClassCatImpDecl,
+ IdentifierInfo *PropertyId,
+ IdentifierInfo *PropertyIvar) {
+ Decl *ClassImpDecl = ClassCatImpDecl.getAs<Decl>();
+ // Make sure we have a context for the property implementation declaration.
+ if (!ClassImpDecl) {
+ Diag(AtLoc, diag::error_missing_property_context);
+ return DeclPtrTy();
+ }
+ ObjCPropertyDecl *property = 0;
+ ObjCInterfaceDecl* IDecl = 0;
+ // Find the class or category class where this property must have
+ // a declaration.
+ ObjCImplementationDecl *IC = 0;
+ ObjCCategoryImplDecl* CatImplClass = 0;
+ if ((IC = dyn_cast<ObjCImplementationDecl>(ClassImpDecl))) {
+ IDecl = IC->getClassInterface();
+ // We always synthesize an interface for an implementation
+ // without an interface decl. So, IDecl is always non-zero.
+ assert(IDecl &&
+ "ActOnPropertyImplDecl - @implementation without @interface");
+
+ // Look for this property declaration in the @implementation's @interface
+ property = IDecl->FindPropertyDeclaration(PropertyId);
+ if (!property) {
+ Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName();
+ return DeclPtrTy();
+ }
+ if (const ObjCCategoryDecl *CD =
+ dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) {
+ if (!CD->IsClassExtension()) {
+ Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName();
+ Diag(property->getLocation(), diag::note_property_declare);
+ return DeclPtrTy();
+ }
+ }
+ } else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) {
+ if (Synthesize) {
+ Diag(AtLoc, diag::error_synthesize_category_decl);
+ return DeclPtrTy();
+ }
+ IDecl = CatImplClass->getClassInterface();
+ if (!IDecl) {
+ Diag(AtLoc, diag::error_missing_property_interface);
+ return DeclPtrTy();
+ }
+ ObjCCategoryDecl *Category =
+ IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier());
+
+ // If category for this implementation not found, it is an error which
+ // has already been reported eralier.
+ if (!Category)
+ return DeclPtrTy();
+ // Look for this property declaration in @implementation's category
+ property = Category->FindPropertyDeclaration(PropertyId);
+ if (!property) {
+ Diag(PropertyLoc, diag::error_bad_category_property_decl)
+ << Category->getDeclName();
+ return DeclPtrTy();
+ }
+ } else {
+ Diag(AtLoc, diag::error_bad_property_context);
+ return DeclPtrTy();
+ }
+ ObjCIvarDecl *Ivar = 0;
+ // Check that we have a valid, previously declared ivar for @synthesize
+ if (Synthesize) {
+ // @synthesize
+ if (!PropertyIvar)
+ PropertyIvar = PropertyId;
+ QualType PropType = Context.getCanonicalType(property->getType());
+ // Check that this is a previously declared 'ivar' in 'IDecl' interface
+ ObjCInterfaceDecl *ClassDeclared;
+ Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared);
+ if (!Ivar) {
+ DeclContext *EnclosingContext = cast_or_null<DeclContext>(ClassImpDecl);
+ assert(EnclosingContext &&
+ "null DeclContext for synthesized ivar - ActOnPropertyImplDecl");
+ Ivar = ObjCIvarDecl::Create(Context, EnclosingContext, PropertyLoc,
+ PropertyIvar, PropType, /*Dinfo=*/0,
+ ObjCIvarDecl::Public,
+ (Expr *)0);
+ EnclosingContext->addDecl(Ivar);
+ IDecl->makeDeclVisibleInContext(Ivar, false);
+ property->setPropertyIvarDecl(Ivar);
+
+ if (!getLangOptions().ObjCNonFragileABI)
+ Diag(PropertyLoc, diag::error_missing_property_ivar_decl) << PropertyId;
+ // Note! I deliberately want it to fall thru so, we have a
+ // a property implementation and to avoid future warnings.
+ } else if (getLangOptions().ObjCNonFragileABI &&
+ ClassDeclared != IDecl) {
+ Diag(PropertyLoc, diag::error_ivar_in_superclass_use)
+ << property->getDeclName() << Ivar->getDeclName()
+ << ClassDeclared->getDeclName();
+ Diag(Ivar->getLocation(), diag::note_previous_access_declaration)
+ << Ivar << Ivar->getNameAsCString();
+ // Note! I deliberately want it to fall thru so more errors are caught.
+ }
+ QualType IvarType = Context.getCanonicalType(Ivar->getType());
+
+ // Check that type of property and its ivar are type compatible.
+ if (PropType != IvarType) {
+ if (CheckAssignmentConstraints(PropType, IvarType) != Compatible) {
+ Diag(PropertyLoc, diag::error_property_ivar_type)
+ << property->getDeclName() << Ivar->getDeclName();
+ // Note! I deliberately want it to fall thru so, we have a
+ // a property implementation and to avoid future warnings.
+ }
+
+ // FIXME! Rules for properties are somewhat different that those
+ // for assignments. Use a new routine to consolidate all cases;
+ // specifically for property redeclarations as well as for ivars.
+ QualType lhsType =Context.getCanonicalType(PropType).getUnqualifiedType();
+ QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType();
+ if (lhsType != rhsType &&
+ lhsType->isArithmeticType()) {
+ Diag(PropertyLoc, diag::error_property_ivar_type)
+ << property->getDeclName() << Ivar->getDeclName();
+ // Fall thru - see previous comment
+ }
+ // __weak is explicit. So it works on Canonical type.
+ if (PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() &&
+ getLangOptions().getGCMode() != LangOptions::NonGC) {
+ Diag(PropertyLoc, diag::error_weak_property)
+ << property->getDeclName() << Ivar->getDeclName();
+ // Fall thru - see previous comment
+ }
+ if ((property->getType()->isObjCObjectPointerType() ||
+ PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&
+ getLangOptions().getGCMode() != LangOptions::NonGC) {
+ Diag(PropertyLoc, diag::error_strong_property)
+ << property->getDeclName() << Ivar->getDeclName();
+ // Fall thru - see previous comment
+ }
+ }
+ } else if (PropertyIvar)
+ // @dynamic
+ Diag(PropertyLoc, diag::error_dynamic_property_ivar_decl);
+ assert (property && "ActOnPropertyImplDecl - property declaration missing");
+ ObjCPropertyImplDecl *PIDecl =
+ ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc,
+ property,
+ (Synthesize ?
+ ObjCPropertyImplDecl::Synthesize
+ : ObjCPropertyImplDecl::Dynamic),
+ Ivar);
+ if (IC) {
+ if (Synthesize)
+ if (ObjCPropertyImplDecl *PPIDecl =
+ IC->FindPropertyImplIvarDecl(PropertyIvar)) {
+ Diag(PropertyLoc, diag::error_duplicate_ivar_use)
+ << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
+ << PropertyIvar;
+ Diag(PPIDecl->getLocation(), diag::note_previous_use);
+ }
+
+ if (ObjCPropertyImplDecl *PPIDecl
+ = IC->FindPropertyImplDecl(PropertyId)) {
+ Diag(PropertyLoc, diag::error_property_implemented) << PropertyId;
+ Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
+ return DeclPtrTy();
+ }
+ IC->addPropertyImplementation(PIDecl);
+ } else {
+ if (Synthesize)
+ if (ObjCPropertyImplDecl *PPIDecl =
+ CatImplClass->FindPropertyImplIvarDecl(PropertyIvar)) {
+ Diag(PropertyLoc, diag::error_duplicate_ivar_use)
+ << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
+ << PropertyIvar;
+ Diag(PPIDecl->getLocation(), diag::note_previous_use);
+ }
+
+ if (ObjCPropertyImplDecl *PPIDecl =
+ CatImplClass->FindPropertyImplDecl(PropertyId)) {
+ Diag(PropertyLoc, diag::error_property_implemented) << PropertyId;
+ Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
+ return DeclPtrTy();
+ }
+ CatImplClass->addPropertyImplementation(PIDecl);
+ }
+
+ return DeclPtrTy::make(PIDecl);
+}
+
More information about the cfe-commits
mailing list