//===--- 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;
//===----------------------------------------------------------------------===//
// Grammar actions.
//===----------------------------------------------------------------------===//
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.