2810 lines · cpp
1//===--- SemaObjCProperty.cpp - Semantic Analysis for ObjC @property ------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements semantic analysis for Objective C @property and10// @synthesize declarations.11//12//===----------------------------------------------------------------------===//13 14#include "clang/AST/ASTMutationListener.h"15#include "clang/AST/DeclObjC.h"16#include "clang/AST/ExprCXX.h"17#include "clang/AST/ExprObjC.h"18#include "clang/Basic/SourceManager.h"19#include "clang/Lex/Lexer.h"20#include "clang/Lex/Preprocessor.h"21#include "clang/Sema/Initialization.h"22#include "clang/Sema/SemaObjC.h"23#include "llvm/ADT/DenseSet.h"24 25using namespace clang;26 27//===----------------------------------------------------------------------===//28// Grammar actions.29//===----------------------------------------------------------------------===//30 31/// getImpliedARCOwnership - Given a set of property attributes and a32/// type, infer an expected lifetime. The type's ownership qualification33/// is not considered.34///35/// Returns OCL_None if the attributes as stated do not imply an ownership.36/// Never returns OCL_Autoreleasing.37static Qualifiers::ObjCLifetime38getImpliedARCOwnership(ObjCPropertyAttribute::Kind attrs, QualType type) {39 // retain, strong, copy, weak, and unsafe_unretained are only legal40 // on properties of retainable pointer type.41 if (attrs &42 (ObjCPropertyAttribute::kind_retain | ObjCPropertyAttribute::kind_strong |43 ObjCPropertyAttribute::kind_copy)) {44 return Qualifiers::OCL_Strong;45 } else if (attrs & ObjCPropertyAttribute::kind_weak) {46 return Qualifiers::OCL_Weak;47 } else if (attrs & ObjCPropertyAttribute::kind_unsafe_unretained) {48 return Qualifiers::OCL_ExplicitNone;49 }50 51 // assign can appear on other types, so we have to check the52 // property type.53 if (attrs & ObjCPropertyAttribute::kind_assign &&54 type->isObjCRetainableType()) {55 return Qualifiers::OCL_ExplicitNone;56 }57 58 return Qualifiers::OCL_None;59}60 61/// Check the internal consistency of a property declaration with62/// an explicit ownership qualifier.63static void checkPropertyDeclWithOwnership(Sema &S,64 ObjCPropertyDecl *property) {65 if (property->isInvalidDecl()) return;66 67 ObjCPropertyAttribute::Kind propertyKind = property->getPropertyAttributes();68 Qualifiers::ObjCLifetime propertyLifetime69 = property->getType().getObjCLifetime();70 71 assert(propertyLifetime != Qualifiers::OCL_None);72 73 Qualifiers::ObjCLifetime expectedLifetime74 = getImpliedARCOwnership(propertyKind, property->getType());75 if (!expectedLifetime) {76 // We have a lifetime qualifier but no dominating property77 // attribute. That's okay, but restore reasonable invariants by78 // setting the property attribute according to the lifetime79 // qualifier.80 ObjCPropertyAttribute::Kind attr;81 if (propertyLifetime == Qualifiers::OCL_Strong) {82 attr = ObjCPropertyAttribute::kind_strong;83 } else if (propertyLifetime == Qualifiers::OCL_Weak) {84 attr = ObjCPropertyAttribute::kind_weak;85 } else {86 assert(propertyLifetime == Qualifiers::OCL_ExplicitNone);87 attr = ObjCPropertyAttribute::kind_unsafe_unretained;88 }89 property->setPropertyAttributes(attr);90 return;91 }92 93 if (propertyLifetime == expectedLifetime) return;94 95 property->setInvalidDecl();96 S.Diag(property->getLocation(),97 diag::err_arc_inconsistent_property_ownership)98 << property->getDeclName()99 << expectedLifetime100 << propertyLifetime;101}102 103/// Check this Objective-C property against a property declared in the104/// given protocol.105static void106CheckPropertyAgainstProtocol(Sema &S, ObjCPropertyDecl *Prop,107 ObjCProtocolDecl *Proto,108 llvm::SmallPtrSetImpl<ObjCProtocolDecl *> &Known) {109 // Have we seen this protocol before?110 if (!Known.insert(Proto).second)111 return;112 113 // Look for a property with the same name.114 if (ObjCPropertyDecl *ProtoProp = Proto->getProperty(115 Prop->getIdentifier(), Prop->isInstanceProperty())) {116 S.ObjC().DiagnosePropertyMismatch(Prop, ProtoProp, Proto->getIdentifier(),117 true);118 return;119 }120 121 // Check this property against any protocols we inherit.122 for (auto *P : Proto->protocols())123 CheckPropertyAgainstProtocol(S, Prop, P, Known);124}125 126static unsigned deducePropertyOwnershipFromType(Sema &S, QualType T) {127 // In GC mode, just look for the __weak qualifier.128 if (S.getLangOpts().getGC() != LangOptions::NonGC) {129 if (T.isObjCGCWeak())130 return ObjCPropertyAttribute::kind_weak;131 132 // In ARC/MRC, look for an explicit ownership qualifier.133 // For some reason, this only applies to __weak.134 } else if (auto ownership = T.getObjCLifetime()) {135 switch (ownership) {136 case Qualifiers::OCL_Weak:137 return ObjCPropertyAttribute::kind_weak;138 case Qualifiers::OCL_Strong:139 return ObjCPropertyAttribute::kind_strong;140 case Qualifiers::OCL_ExplicitNone:141 return ObjCPropertyAttribute::kind_unsafe_unretained;142 case Qualifiers::OCL_Autoreleasing:143 case Qualifiers::OCL_None:144 return 0;145 }146 llvm_unreachable("bad qualifier");147 }148 149 return 0;150}151 152static const unsigned OwnershipMask =153 (ObjCPropertyAttribute::kind_assign | ObjCPropertyAttribute::kind_retain |154 ObjCPropertyAttribute::kind_copy | ObjCPropertyAttribute::kind_weak |155 ObjCPropertyAttribute::kind_strong |156 ObjCPropertyAttribute::kind_unsafe_unretained);157 158static unsigned getOwnershipRule(unsigned attr) {159 unsigned result = attr & OwnershipMask;160 161 // From an ownership perspective, assign and unsafe_unretained are162 // identical; make sure one also implies the other.163 if (result & (ObjCPropertyAttribute::kind_assign |164 ObjCPropertyAttribute::kind_unsafe_unretained)) {165 result |= ObjCPropertyAttribute::kind_assign |166 ObjCPropertyAttribute::kind_unsafe_unretained;167 }168 169 return result;170}171 172Decl *SemaObjC::ActOnProperty(Scope *S, SourceLocation AtLoc,173 SourceLocation LParenLoc, FieldDeclarator &FD,174 ObjCDeclSpec &ODS, Selector GetterSel,175 Selector SetterSel,176 tok::ObjCKeywordKind MethodImplKind,177 DeclContext *lexicalDC) {178 unsigned Attributes = ODS.getPropertyAttributes();179 FD.D.setObjCWeakProperty((Attributes & ObjCPropertyAttribute::kind_weak) !=180 0);181 TypeSourceInfo *TSI = SemaRef.GetTypeForDeclarator(FD.D);182 QualType T = TSI->getType();183 if (T.getPointerAuth().isPresent()) {184 Diag(AtLoc, diag::err_ptrauth_qualifier_invalid) << T << 2;185 }186 if (!getOwnershipRule(Attributes)) {187 Attributes |= deducePropertyOwnershipFromType(SemaRef, T);188 }189 bool isReadWrite = ((Attributes & ObjCPropertyAttribute::kind_readwrite) ||190 // default is readwrite!191 !(Attributes & ObjCPropertyAttribute::kind_readonly));192 193 // Proceed with constructing the ObjCPropertyDecls.194 ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(SemaRef.CurContext);195 ObjCPropertyDecl *Res = nullptr;196 if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {197 if (CDecl->IsClassExtension()) {198 Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc,199 FD,200 GetterSel, ODS.getGetterNameLoc(),201 SetterSel, ODS.getSetterNameLoc(),202 isReadWrite, Attributes,203 ODS.getPropertyAttributes(),204 T, TSI, MethodImplKind);205 if (!Res)206 return nullptr;207 }208 }209 210 if (!Res) {211 Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD,212 GetterSel, ODS.getGetterNameLoc(), SetterSel,213 ODS.getSetterNameLoc(), isReadWrite, Attributes,214 ODS.getPropertyAttributes(), T, TSI,215 MethodImplKind);216 if (lexicalDC)217 Res->setLexicalDeclContext(lexicalDC);218 }219 220 // Validate the attributes on the @property.221 CheckObjCPropertyAttributes(Res, AtLoc, Attributes,222 (isa<ObjCInterfaceDecl>(ClassDecl) ||223 isa<ObjCProtocolDecl>(ClassDecl)));224 225 // Check consistency if the type has explicit ownership qualification.226 if (Res->getType().getObjCLifetime())227 checkPropertyDeclWithOwnership(SemaRef, Res);228 229 llvm::SmallPtrSet<ObjCProtocolDecl *, 16> KnownProtos;230 if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {231 // For a class, compare the property against a property in our superclass.232 bool FoundInSuper = false;233 ObjCInterfaceDecl *CurrentInterfaceDecl = IFace;234 while (ObjCInterfaceDecl *Super = CurrentInterfaceDecl->getSuperClass()) {235 if (ObjCPropertyDecl *SuperProp = Super->getProperty(236 Res->getIdentifier(), Res->isInstanceProperty())) {237 DiagnosePropertyMismatch(Res, SuperProp, Super->getIdentifier(), false);238 FoundInSuper = true;239 break;240 }241 CurrentInterfaceDecl = Super;242 }243 244 if (FoundInSuper) {245 // Also compare the property against a property in our protocols.246 for (auto *P : CurrentInterfaceDecl->protocols()) {247 CheckPropertyAgainstProtocol(SemaRef, Res, P, KnownProtos);248 }249 } else {250 // Slower path: look in all protocols we referenced.251 for (auto *P : IFace->all_referenced_protocols()) {252 CheckPropertyAgainstProtocol(SemaRef, Res, P, KnownProtos);253 }254 }255 } else if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {256 // We don't check if class extension. Because properties in class extension257 // are meant to override some of the attributes and checking has already done258 // when property in class extension is constructed.259 if (!Cat->IsClassExtension())260 for (auto *P : Cat->protocols())261 CheckPropertyAgainstProtocol(SemaRef, Res, P, KnownProtos);262 } else {263 ObjCProtocolDecl *Proto = cast<ObjCProtocolDecl>(ClassDecl);264 for (auto *P : Proto->protocols())265 CheckPropertyAgainstProtocol(SemaRef, Res, P, KnownProtos);266 }267 268 SemaRef.ActOnDocumentableDecl(Res);269 return Res;270}271 272static ObjCPropertyAttribute::Kind273makePropertyAttributesAsWritten(unsigned Attributes) {274 unsigned attributesAsWritten = 0;275 if (Attributes & ObjCPropertyAttribute::kind_readonly)276 attributesAsWritten |= ObjCPropertyAttribute::kind_readonly;277 if (Attributes & ObjCPropertyAttribute::kind_readwrite)278 attributesAsWritten |= ObjCPropertyAttribute::kind_readwrite;279 if (Attributes & ObjCPropertyAttribute::kind_getter)280 attributesAsWritten |= ObjCPropertyAttribute::kind_getter;281 if (Attributes & ObjCPropertyAttribute::kind_setter)282 attributesAsWritten |= ObjCPropertyAttribute::kind_setter;283 if (Attributes & ObjCPropertyAttribute::kind_assign)284 attributesAsWritten |= ObjCPropertyAttribute::kind_assign;285 if (Attributes & ObjCPropertyAttribute::kind_retain)286 attributesAsWritten |= ObjCPropertyAttribute::kind_retain;287 if (Attributes & ObjCPropertyAttribute::kind_strong)288 attributesAsWritten |= ObjCPropertyAttribute::kind_strong;289 if (Attributes & ObjCPropertyAttribute::kind_weak)290 attributesAsWritten |= ObjCPropertyAttribute::kind_weak;291 if (Attributes & ObjCPropertyAttribute::kind_copy)292 attributesAsWritten |= ObjCPropertyAttribute::kind_copy;293 if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained)294 attributesAsWritten |= ObjCPropertyAttribute::kind_unsafe_unretained;295 if (Attributes & ObjCPropertyAttribute::kind_nonatomic)296 attributesAsWritten |= ObjCPropertyAttribute::kind_nonatomic;297 if (Attributes & ObjCPropertyAttribute::kind_atomic)298 attributesAsWritten |= ObjCPropertyAttribute::kind_atomic;299 if (Attributes & ObjCPropertyAttribute::kind_class)300 attributesAsWritten |= ObjCPropertyAttribute::kind_class;301 if (Attributes & ObjCPropertyAttribute::kind_direct)302 attributesAsWritten |= ObjCPropertyAttribute::kind_direct;303 304 return (ObjCPropertyAttribute::Kind)attributesAsWritten;305}306 307static bool LocPropertyAttribute( ASTContext &Context, const char *attrName,308 SourceLocation LParenLoc, SourceLocation &Loc) {309 if (LParenLoc.isMacroID())310 return false;311 312 SourceManager &SM = Context.getSourceManager();313 FileIDAndOffset locInfo = SM.getDecomposedLoc(LParenLoc);314 // Try to load the file buffer.315 bool invalidTemp = false;316 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);317 if (invalidTemp)318 return false;319 const char *tokenBegin = file.data() + locInfo.second;320 321 // Lex from the start of the given location.322 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),323 Context.getLangOpts(),324 file.begin(), tokenBegin, file.end());325 Token Tok;326 do {327 lexer.LexFromRawLexer(Tok);328 if (Tok.is(tok::raw_identifier) && Tok.getRawIdentifier() == attrName) {329 Loc = Tok.getLocation();330 return true;331 }332 } while (Tok.isNot(tok::r_paren));333 return false;334}335 336/// Check for a mismatch in the atomicity of the given properties.337static void checkAtomicPropertyMismatch(Sema &S,338 ObjCPropertyDecl *OldProperty,339 ObjCPropertyDecl *NewProperty,340 bool PropagateAtomicity) {341 // If the atomicity of both matches, we're done.342 bool OldIsAtomic = (OldProperty->getPropertyAttributes() &343 ObjCPropertyAttribute::kind_nonatomic) == 0;344 bool NewIsAtomic = (NewProperty->getPropertyAttributes() &345 ObjCPropertyAttribute::kind_nonatomic) == 0;346 if (OldIsAtomic == NewIsAtomic) return;347 348 // Determine whether the given property is readonly and implicitly349 // atomic.350 auto isImplicitlyReadonlyAtomic = [](ObjCPropertyDecl *Property) -> bool {351 // Is it readonly?352 auto Attrs = Property->getPropertyAttributes();353 if ((Attrs & ObjCPropertyAttribute::kind_readonly) == 0)354 return false;355 356 // Is it nonatomic?357 if (Attrs & ObjCPropertyAttribute::kind_nonatomic)358 return false;359 360 // Was 'atomic' specified directly?361 if (Property->getPropertyAttributesAsWritten() &362 ObjCPropertyAttribute::kind_atomic)363 return false;364 365 return true;366 };367 368 // If we're allowed to propagate atomicity, and the new property did369 // not specify atomicity at all, propagate.370 const unsigned AtomicityMask = (ObjCPropertyAttribute::kind_atomic |371 ObjCPropertyAttribute::kind_nonatomic);372 if (PropagateAtomicity &&373 ((NewProperty->getPropertyAttributesAsWritten() & AtomicityMask) == 0)) {374 unsigned Attrs = NewProperty->getPropertyAttributes();375 Attrs = Attrs & ~AtomicityMask;376 if (OldIsAtomic)377 Attrs |= ObjCPropertyAttribute::kind_atomic;378 else379 Attrs |= ObjCPropertyAttribute::kind_nonatomic;380 381 NewProperty->overwritePropertyAttributes(Attrs);382 return;383 }384 385 // One of the properties is atomic; if it's a readonly property, and386 // 'atomic' wasn't explicitly specified, we're okay.387 if ((OldIsAtomic && isImplicitlyReadonlyAtomic(OldProperty)) ||388 (NewIsAtomic && isImplicitlyReadonlyAtomic(NewProperty)))389 return;390 391 // Diagnose the conflict.392 const IdentifierInfo *OldContextName;393 auto *OldDC = OldProperty->getDeclContext();394 if (auto Category = dyn_cast<ObjCCategoryDecl>(OldDC))395 OldContextName = Category->getClassInterface()->getIdentifier();396 else397 OldContextName = cast<ObjCContainerDecl>(OldDC)->getIdentifier();398 399 S.Diag(NewProperty->getLocation(), diag::warn_property_attribute)400 << NewProperty->getDeclName() << "atomic"401 << OldContextName;402 S.Diag(OldProperty->getLocation(), diag::note_property_declare);403}404 405ObjCPropertyDecl *SemaObjC::HandlePropertyInClassExtension(406 Scope *S, SourceLocation AtLoc, SourceLocation LParenLoc,407 FieldDeclarator &FD, Selector GetterSel, SourceLocation GetterNameLoc,408 Selector SetterSel, SourceLocation SetterNameLoc, const bool isReadWrite,409 unsigned &Attributes, const unsigned AttributesAsWritten, QualType T,410 TypeSourceInfo *TSI, tok::ObjCKeywordKind MethodImplKind) {411 ObjCCategoryDecl *CDecl = cast<ObjCCategoryDecl>(SemaRef.CurContext);412 // Diagnose if this property is already in continuation class.413 DeclContext *DC = SemaRef.CurContext;414 const IdentifierInfo *PropertyId = FD.D.getIdentifier();415 ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface();416 417 // We need to look in the @interface to see if the @property was418 // already declared.419 if (!CCPrimary) {420 Diag(CDecl->getLocation(), diag::err_continuation_class);421 return nullptr;422 }423 424 bool isClassProperty =425 (AttributesAsWritten & ObjCPropertyAttribute::kind_class) ||426 (Attributes & ObjCPropertyAttribute::kind_class);427 428 // Find the property in the extended class's primary class or429 // extensions.430 ObjCPropertyDecl *PIDecl = CCPrimary->FindPropertyVisibleInPrimaryClass(431 PropertyId, ObjCPropertyDecl::getQueryKind(isClassProperty));432 433 // If we found a property in an extension, complain.434 if (PIDecl && isa<ObjCCategoryDecl>(PIDecl->getDeclContext())) {435 Diag(AtLoc, diag::err_duplicate_property);436 Diag(PIDecl->getLocation(), diag::note_property_declare);437 return nullptr;438 }439 440 // Check for consistency with the previous declaration, if there is one.441 if (PIDecl) {442 // A readonly property declared in the primary class can be refined443 // by adding a readwrite property within an extension.444 // Anything else is an error.445 if (!(PIDecl->isReadOnly() && isReadWrite)) {446 // Tailor the diagnostics for the common case where a readwrite447 // property is declared both in the @interface and the continuation.448 // This is a common error where the user often intended the original449 // declaration to be readonly.450 unsigned diag =451 (Attributes & ObjCPropertyAttribute::kind_readwrite) &&452 (PIDecl->getPropertyAttributesAsWritten() &453 ObjCPropertyAttribute::kind_readwrite)454 ? diag::err_use_continuation_class_redeclaration_readwrite455 : diag::err_use_continuation_class;456 Diag(AtLoc, diag)457 << CCPrimary->getDeclName();458 Diag(PIDecl->getLocation(), diag::note_property_declare);459 return nullptr;460 }461 462 // Check for consistency of getters.463 if (PIDecl->getGetterName() != GetterSel) {464 // If the getter was written explicitly, complain.465 if (AttributesAsWritten & ObjCPropertyAttribute::kind_getter) {466 Diag(AtLoc, diag::warn_property_redecl_getter_mismatch)467 << PIDecl->getGetterName() << GetterSel;468 Diag(PIDecl->getLocation(), diag::note_property_declare);469 }470 471 // Always adopt the getter from the original declaration.472 GetterSel = PIDecl->getGetterName();473 Attributes |= ObjCPropertyAttribute::kind_getter;474 }475 476 // Check consistency of ownership.477 unsigned ExistingOwnership478 = getOwnershipRule(PIDecl->getPropertyAttributes());479 unsigned NewOwnership = getOwnershipRule(Attributes);480 if (ExistingOwnership && NewOwnership != ExistingOwnership) {481 // If the ownership was written explicitly, complain.482 if (getOwnershipRule(AttributesAsWritten)) {483 Diag(AtLoc, diag::warn_property_attr_mismatch);484 Diag(PIDecl->getLocation(), diag::note_property_declare);485 }486 487 // Take the ownership from the original property.488 Attributes = (Attributes & ~OwnershipMask) | ExistingOwnership;489 }490 491 // If the redeclaration is 'weak' but the original property is not,492 if ((Attributes & ObjCPropertyAttribute::kind_weak) &&493 !(PIDecl->getPropertyAttributesAsWritten() &494 ObjCPropertyAttribute::kind_weak) &&495 PIDecl->getType()->getAs<ObjCObjectPointerType>() &&496 PIDecl->getType().getObjCLifetime() == Qualifiers::OCL_None) {497 Diag(AtLoc, diag::warn_property_implicitly_mismatched);498 Diag(PIDecl->getLocation(), diag::note_property_declare);499 }500 }501 502 // Create a new ObjCPropertyDecl with the DeclContext being503 // the class extension.504 ObjCPropertyDecl *PDecl = CreatePropertyDecl(S, CDecl, AtLoc, LParenLoc,505 FD, GetterSel, GetterNameLoc,506 SetterSel, SetterNameLoc,507 isReadWrite,508 Attributes, AttributesAsWritten,509 T, TSI, MethodImplKind, DC);510 ASTContext &Context = getASTContext();511 // If there was no declaration of a property with the same name in512 // the primary class, we're done.513 if (!PIDecl) {514 ProcessPropertyDecl(PDecl);515 return PDecl;516 }517 518 if (!Context.hasSameType(PIDecl->getType(), PDecl->getType())) {519 bool IncompatibleObjC = false;520 QualType ConvertedType;521 // Relax the strict type matching for property type in continuation class.522 // Allow property object type of continuation class to be different as long523 // as it narrows the object type in its primary class property. Note that524 // this conversion is safe only because the wider type is for a 'readonly'525 // property in primary class and 'narrowed' type for a 'readwrite' property526 // in continuation class.527 QualType PrimaryClassPropertyT = Context.getCanonicalType(PIDecl->getType());528 QualType ClassExtPropertyT = Context.getCanonicalType(PDecl->getType());529 if (!isa<ObjCObjectPointerType>(PrimaryClassPropertyT) ||530 !isa<ObjCObjectPointerType>(ClassExtPropertyT) ||531 (!SemaRef.isObjCPointerConversion(ClassExtPropertyT,532 PrimaryClassPropertyT, ConvertedType,533 IncompatibleObjC)) ||534 IncompatibleObjC) {535 Diag(AtLoc,536 diag::err_type_mismatch_continuation_class) << PDecl->getType();537 Diag(PIDecl->getLocation(), diag::note_property_declare);538 return nullptr;539 }540 }541 542 // Check that atomicity of property in class extension matches the previous543 // declaration.544 checkAtomicPropertyMismatch(SemaRef, PIDecl, PDecl, true);545 546 // Make sure getter/setter are appropriately synthesized.547 ProcessPropertyDecl(PDecl);548 return PDecl;549}550 551ObjCPropertyDecl *SemaObjC::CreatePropertyDecl(552 Scope *S, ObjCContainerDecl *CDecl, SourceLocation AtLoc,553 SourceLocation LParenLoc, FieldDeclarator &FD, Selector GetterSel,554 SourceLocation GetterNameLoc, Selector SetterSel,555 SourceLocation SetterNameLoc, const bool isReadWrite,556 const unsigned Attributes, const unsigned AttributesAsWritten, QualType T,557 TypeSourceInfo *TInfo, tok::ObjCKeywordKind MethodImplKind,558 DeclContext *lexicalDC) {559 ASTContext &Context = getASTContext();560 const IdentifierInfo *PropertyId = FD.D.getIdentifier();561 562 // Property defaults to 'assign' if it is readwrite, unless this is ARC563 // and the type is retainable.564 bool isAssign;565 if (Attributes & (ObjCPropertyAttribute::kind_assign |566 ObjCPropertyAttribute::kind_unsafe_unretained)) {567 isAssign = true;568 } else if (getOwnershipRule(Attributes) || !isReadWrite) {569 isAssign = false;570 } else {571 isAssign = (!getLangOpts().ObjCAutoRefCount ||572 !T->isObjCRetainableType());573 }574 575 // Issue a warning if property is 'assign' as default and its576 // object, which is gc'able conforms to NSCopying protocol577 if (getLangOpts().getGC() != LangOptions::NonGC && isAssign &&578 !(Attributes & ObjCPropertyAttribute::kind_assign)) {579 if (const ObjCObjectPointerType *ObjPtrTy =580 T->getAs<ObjCObjectPointerType>()) {581 ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();582 if (IDecl)583 if (ObjCProtocolDecl* PNSCopying =584 LookupProtocol(&Context.Idents.get("NSCopying"), AtLoc))585 if (IDecl->ClassImplementsProtocol(PNSCopying, true))586 Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId;587 }588 }589 590 if (T->isObjCObjectType()) {591 SourceLocation StarLoc = TInfo->getTypeLoc().getEndLoc();592 StarLoc = SemaRef.getLocForEndOfToken(StarLoc);593 Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object)594 << FixItHint::CreateInsertion(StarLoc, "*");595 T = Context.getObjCObjectPointerType(T);596 SourceLocation TLoc = TInfo->getTypeLoc().getBeginLoc();597 TInfo = Context.getTrivialTypeSourceInfo(T, TLoc);598 }599 600 DeclContext *DC = CDecl;601 ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,602 FD.D.getIdentifierLoc(),603 PropertyId, AtLoc,604 LParenLoc, T, TInfo);605 606 bool isClassProperty =607 (AttributesAsWritten & ObjCPropertyAttribute::kind_class) ||608 (Attributes & ObjCPropertyAttribute::kind_class);609 // Class property and instance property can have the same name.610 if (ObjCPropertyDecl *prevDecl = ObjCPropertyDecl::findPropertyDecl(611 DC, PropertyId, ObjCPropertyDecl::getQueryKind(isClassProperty))) {612 Diag(PDecl->getLocation(), diag::err_duplicate_property);613 Diag(prevDecl->getLocation(), diag::note_property_declare);614 PDecl->setInvalidDecl();615 }616 else {617 DC->addDecl(PDecl);618 if (lexicalDC)619 PDecl->setLexicalDeclContext(lexicalDC);620 }621 622 if (T->isArrayType() || T->isFunctionType()) {623 Diag(AtLoc, diag::err_property_type) << T;624 PDecl->setInvalidDecl();625 }626 627 // Regardless of setter/getter attribute, we save the default getter/setter628 // selector names in anticipation of declaration of setter/getter methods.629 PDecl->setGetterName(GetterSel, GetterNameLoc);630 PDecl->setSetterName(SetterSel, SetterNameLoc);631 PDecl->setPropertyAttributesAsWritten(632 makePropertyAttributesAsWritten(AttributesAsWritten));633 634 SemaRef.ProcessDeclAttributes(S, PDecl, FD.D);635 636 if (Attributes & ObjCPropertyAttribute::kind_readonly)637 PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_readonly);638 639 if (Attributes & ObjCPropertyAttribute::kind_getter)640 PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_getter);641 642 if (Attributes & ObjCPropertyAttribute::kind_setter)643 PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_setter);644 645 if (isReadWrite)646 PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_readwrite);647 648 if (Attributes & ObjCPropertyAttribute::kind_retain)649 PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_retain);650 651 if (Attributes & ObjCPropertyAttribute::kind_strong)652 PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_strong);653 654 if (Attributes & ObjCPropertyAttribute::kind_weak)655 PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_weak);656 657 if (Attributes & ObjCPropertyAttribute::kind_copy)658 PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_copy);659 660 if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained)661 PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_unsafe_unretained);662 663 if (isAssign)664 PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_assign);665 666 // In the semantic attributes, one of nonatomic or atomic is always set.667 if (Attributes & ObjCPropertyAttribute::kind_nonatomic)668 PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_nonatomic);669 else670 PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_atomic);671 672 // 'unsafe_unretained' is alias for 'assign'.673 if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained)674 PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_assign);675 if (isAssign)676 PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_unsafe_unretained);677 678 if (MethodImplKind == tok::objc_required)679 PDecl->setPropertyImplementation(ObjCPropertyDecl::Required);680 else if (MethodImplKind == tok::objc_optional)681 PDecl->setPropertyImplementation(ObjCPropertyDecl::Optional);682 683 if (Attributes & ObjCPropertyAttribute::kind_nullability)684 PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_nullability);685 686 if (Attributes & ObjCPropertyAttribute::kind_null_resettable)687 PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_null_resettable);688 689 if (Attributes & ObjCPropertyAttribute::kind_class)690 PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_class);691 692 if ((Attributes & ObjCPropertyAttribute::kind_direct) ||693 CDecl->hasAttr<ObjCDirectMembersAttr>()) {694 if (isa<ObjCProtocolDecl>(CDecl)) {695 Diag(PDecl->getLocation(), diag::err_objc_direct_on_protocol) << true;696 } else if (getLangOpts().ObjCRuntime.allowsDirectDispatch()) {697 PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_direct);698 } else {699 Diag(PDecl->getLocation(), diag::warn_objc_direct_property_ignored)700 << PDecl->getDeclName();701 }702 }703 704 return PDecl;705}706 707static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc,708 ObjCPropertyDecl *property,709 ObjCIvarDecl *ivar) {710 if (property->isInvalidDecl() || ivar->isInvalidDecl()) return;711 712 QualType ivarType = ivar->getType();713 Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime();714 715 // The lifetime implied by the property's attributes.716 Qualifiers::ObjCLifetime propertyLifetime =717 getImpliedARCOwnership(property->getPropertyAttributes(),718 property->getType());719 720 // We're fine if they match.721 if (propertyLifetime == ivarLifetime) return;722 723 // None isn't a valid lifetime for an object ivar in ARC, and724 // __autoreleasing is never valid; don't diagnose twice.725 if ((ivarLifetime == Qualifiers::OCL_None &&726 S.getLangOpts().ObjCAutoRefCount) ||727 ivarLifetime == Qualifiers::OCL_Autoreleasing)728 return;729 730 // If the ivar is private, and it's implicitly __unsafe_unretained731 // because of its type, then pretend it was actually implicitly732 // __strong. This is only sound because we're processing the733 // property implementation before parsing any method bodies.734 if (ivarLifetime == Qualifiers::OCL_ExplicitNone &&735 propertyLifetime == Qualifiers::OCL_Strong &&736 ivar->getAccessControl() == ObjCIvarDecl::Private) {737 SplitQualType split = ivarType.split();738 if (split.Quals.hasObjCLifetime()) {739 assert(ivarType->isObjCARCImplicitlyUnretainedType());740 split.Quals.setObjCLifetime(Qualifiers::OCL_Strong);741 ivarType = S.Context.getQualifiedType(split);742 ivar->setType(ivarType);743 return;744 }745 }746 747 switch (propertyLifetime) {748 case Qualifiers::OCL_Strong:749 S.Diag(ivar->getLocation(), diag::err_arc_strong_property_ownership)750 << property->getDeclName()751 << ivar->getDeclName()752 << ivarLifetime;753 break;754 755 case Qualifiers::OCL_Weak:756 S.Diag(ivar->getLocation(), diag::err_weak_property)757 << property->getDeclName()758 << ivar->getDeclName();759 break;760 761 case Qualifiers::OCL_ExplicitNone:762 S.Diag(ivar->getLocation(), diag::err_arc_assign_property_ownership)763 << property->getDeclName() << ivar->getDeclName()764 << ((property->getPropertyAttributesAsWritten() &765 ObjCPropertyAttribute::kind_assign) != 0);766 break;767 768 case Qualifiers::OCL_Autoreleasing:769 llvm_unreachable("properties cannot be autoreleasing");770 771 case Qualifiers::OCL_None:772 // Any other property should be ignored.773 return;774 }775 776 S.Diag(property->getLocation(), diag::note_property_declare);777 if (propertyImplLoc.isValid())778 S.Diag(propertyImplLoc, diag::note_property_synthesize);779}780 781/// setImpliedPropertyAttributeForReadOnlyProperty -782/// This routine evaludates life-time attributes for a 'readonly'783/// property with no known lifetime of its own, using backing784/// 'ivar's attribute, if any. If no backing 'ivar', property's785/// life-time is assumed 'strong'.786static void setImpliedPropertyAttributeForReadOnlyProperty(787 ObjCPropertyDecl *property, ObjCIvarDecl *ivar) {788 Qualifiers::ObjCLifetime propertyLifetime =789 getImpliedARCOwnership(property->getPropertyAttributes(),790 property->getType());791 if (propertyLifetime != Qualifiers::OCL_None)792 return;793 794 if (!ivar) {795 // if no backing ivar, make property 'strong'.796 property->setPropertyAttributes(ObjCPropertyAttribute::kind_strong);797 return;798 }799 // property assumes owenership of backing ivar.800 QualType ivarType = ivar->getType();801 Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime();802 if (ivarLifetime == Qualifiers::OCL_Strong)803 property->setPropertyAttributes(ObjCPropertyAttribute::kind_strong);804 else if (ivarLifetime == Qualifiers::OCL_Weak)805 property->setPropertyAttributes(ObjCPropertyAttribute::kind_weak);806}807 808static bool isIncompatiblePropertyAttribute(unsigned Attr1, unsigned Attr2,809 ObjCPropertyAttribute::Kind Kind) {810 return (Attr1 & Kind) != (Attr2 & Kind);811}812 813static bool areIncompatiblePropertyAttributes(unsigned Attr1, unsigned Attr2,814 unsigned Kinds) {815 return ((Attr1 & Kinds) != 0) != ((Attr2 & Kinds) != 0);816}817 818/// SelectPropertyForSynthesisFromProtocols - Finds the most appropriate819/// property declaration that should be synthesised in all of the inherited820/// protocols. It also diagnoses properties declared in inherited protocols with821/// mismatched types or attributes, since any of them can be candidate for822/// synthesis.823static ObjCPropertyDecl *824SelectPropertyForSynthesisFromProtocols(Sema &S, SourceLocation AtLoc,825 ObjCInterfaceDecl *ClassDecl,826 ObjCPropertyDecl *Property) {827 assert(isa<ObjCProtocolDecl>(Property->getDeclContext()) &&828 "Expected a property from a protocol");829 ObjCInterfaceDecl::ProtocolPropertySet ProtocolSet;830 ObjCInterfaceDecl::PropertyDeclOrder Properties;831 for (const auto *PI : ClassDecl->all_referenced_protocols()) {832 if (const ObjCProtocolDecl *PDecl = PI->getDefinition())833 PDecl->collectInheritedProtocolProperties(Property, ProtocolSet,834 Properties);835 }836 if (ObjCInterfaceDecl *SDecl = ClassDecl->getSuperClass()) {837 while (SDecl) {838 for (const auto *PI : SDecl->all_referenced_protocols()) {839 if (const ObjCProtocolDecl *PDecl = PI->getDefinition())840 PDecl->collectInheritedProtocolProperties(Property, ProtocolSet,841 Properties);842 }843 SDecl = SDecl->getSuperClass();844 }845 }846 847 if (Properties.empty())848 return Property;849 850 ObjCPropertyDecl *OriginalProperty = Property;851 size_t SelectedIndex = 0;852 for (const auto &Prop : llvm::enumerate(Properties)) {853 // Select the 'readwrite' property if such property exists.854 if (Property->isReadOnly() && !Prop.value()->isReadOnly()) {855 Property = Prop.value();856 SelectedIndex = Prop.index();857 }858 }859 if (Property != OriginalProperty) {860 // Check that the old property is compatible with the new one.861 Properties[SelectedIndex] = OriginalProperty;862 }863 864 QualType RHSType = S.Context.getCanonicalType(Property->getType());865 unsigned OriginalAttributes = Property->getPropertyAttributesAsWritten();866 enum MismatchKind {867 IncompatibleType = 0,868 HasNoExpectedAttribute,869 HasUnexpectedAttribute,870 DifferentGetter,871 DifferentSetter872 };873 // Represents a property from another protocol that conflicts with the874 // selected declaration.875 struct MismatchingProperty {876 const ObjCPropertyDecl *Prop;877 MismatchKind Kind;878 StringRef AttributeName;879 };880 SmallVector<MismatchingProperty, 4> Mismatches;881 for (ObjCPropertyDecl *Prop : Properties) {882 // Verify the property attributes.883 unsigned Attr = Prop->getPropertyAttributesAsWritten();884 if (Attr != OriginalAttributes) {885 auto Diag = [&](bool OriginalHasAttribute, StringRef AttributeName) {886 MismatchKind Kind = OriginalHasAttribute ? HasNoExpectedAttribute887 : HasUnexpectedAttribute;888 Mismatches.push_back({Prop, Kind, AttributeName});889 };890 // The ownership might be incompatible unless the property has no explicit891 // ownership.892 bool HasOwnership =893 (Attr & (ObjCPropertyAttribute::kind_retain |894 ObjCPropertyAttribute::kind_strong |895 ObjCPropertyAttribute::kind_copy |896 ObjCPropertyAttribute::kind_assign |897 ObjCPropertyAttribute::kind_unsafe_unretained |898 ObjCPropertyAttribute::kind_weak)) != 0;899 if (HasOwnership &&900 isIncompatiblePropertyAttribute(OriginalAttributes, Attr,901 ObjCPropertyAttribute::kind_copy)) {902 Diag(OriginalAttributes & ObjCPropertyAttribute::kind_copy, "copy");903 continue;904 }905 if (HasOwnership && areIncompatiblePropertyAttributes(906 OriginalAttributes, Attr,907 ObjCPropertyAttribute::kind_retain |908 ObjCPropertyAttribute::kind_strong)) {909 Diag(OriginalAttributes & (ObjCPropertyAttribute::kind_retain |910 ObjCPropertyAttribute::kind_strong),911 "retain (or strong)");912 continue;913 }914 if (isIncompatiblePropertyAttribute(OriginalAttributes, Attr,915 ObjCPropertyAttribute::kind_atomic)) {916 Diag(OriginalAttributes & ObjCPropertyAttribute::kind_atomic, "atomic");917 continue;918 }919 }920 if (Property->getGetterName() != Prop->getGetterName()) {921 Mismatches.push_back({Prop, DifferentGetter, ""});922 continue;923 }924 if (!Property->isReadOnly() && !Prop->isReadOnly() &&925 Property->getSetterName() != Prop->getSetterName()) {926 Mismatches.push_back({Prop, DifferentSetter, ""});927 continue;928 }929 QualType LHSType = S.Context.getCanonicalType(Prop->getType());930 if (!S.Context.propertyTypesAreCompatible(LHSType, RHSType)) {931 bool IncompatibleObjC = false;932 QualType ConvertedType;933 if (!S.isObjCPointerConversion(RHSType, LHSType, ConvertedType, IncompatibleObjC)934 || IncompatibleObjC) {935 Mismatches.push_back({Prop, IncompatibleType, ""});936 continue;937 }938 }939 }940 941 if (Mismatches.empty())942 return Property;943 944 // Diagnose incompability.945 {946 bool HasIncompatibleAttributes = false;947 for (const auto &Note : Mismatches)948 HasIncompatibleAttributes =949 Note.Kind != IncompatibleType ? true : HasIncompatibleAttributes;950 // Promote the warning to an error if there are incompatible attributes or951 // incompatible types together with readwrite/readonly incompatibility.952 auto Diag = S.Diag(Property->getLocation(),953 Property != OriginalProperty || HasIncompatibleAttributes954 ? diag::err_protocol_property_mismatch955 : diag::warn_protocol_property_mismatch);956 Diag << Mismatches[0].Kind;957 switch (Mismatches[0].Kind) {958 case IncompatibleType:959 Diag << Property->getType();960 break;961 case HasNoExpectedAttribute:962 case HasUnexpectedAttribute:963 Diag << Mismatches[0].AttributeName;964 break;965 case DifferentGetter:966 Diag << Property->getGetterName();967 break;968 case DifferentSetter:969 Diag << Property->getSetterName();970 break;971 }972 }973 for (const auto &Note : Mismatches) {974 auto Diag =975 S.Diag(Note.Prop->getLocation(), diag::note_protocol_property_declare)976 << Note.Kind;977 switch (Note.Kind) {978 case IncompatibleType:979 Diag << Note.Prop->getType();980 break;981 case HasNoExpectedAttribute:982 case HasUnexpectedAttribute:983 Diag << Note.AttributeName;984 break;985 case DifferentGetter:986 Diag << Note.Prop->getGetterName();987 break;988 case DifferentSetter:989 Diag << Note.Prop->getSetterName();990 break;991 }992 }993 if (AtLoc.isValid())994 S.Diag(AtLoc, diag::note_property_synthesize);995 996 return Property;997}998 999/// Determine whether any storage attributes were written on the property.1000static bool hasWrittenStorageAttribute(ObjCPropertyDecl *Prop,1001 ObjCPropertyQueryKind QueryKind) {1002 if (Prop->getPropertyAttributesAsWritten() & OwnershipMask) return true;1003 1004 // If this is a readwrite property in a class extension that refines1005 // a readonly property in the original class definition, check it as1006 // well.1007 1008 // If it's a readonly property, we're not interested.1009 if (Prop->isReadOnly()) return false;1010 1011 // Is it declared in an extension?1012 auto Category = dyn_cast<ObjCCategoryDecl>(Prop->getDeclContext());1013 if (!Category || !Category->IsClassExtension()) return false;1014 1015 // Find the corresponding property in the primary class definition.1016 auto OrigClass = Category->getClassInterface();1017 for (auto *Found : OrigClass->lookup(Prop->getDeclName())) {1018 if (ObjCPropertyDecl *OrigProp = dyn_cast<ObjCPropertyDecl>(Found))1019 return OrigProp->getPropertyAttributesAsWritten() & OwnershipMask;1020 }1021 1022 // Look through all of the protocols.1023 for (const auto *Proto : OrigClass->all_referenced_protocols()) {1024 if (ObjCPropertyDecl *OrigProp = Proto->FindPropertyDeclaration(1025 Prop->getIdentifier(), QueryKind))1026 return OrigProp->getPropertyAttributesAsWritten() & OwnershipMask;1027 }1028 1029 return false;1030}1031 1032/// Create a synthesized property accessor stub inside the \@implementation.1033static ObjCMethodDecl *1034RedeclarePropertyAccessor(ASTContext &Context, ObjCImplementationDecl *Impl,1035 ObjCMethodDecl *AccessorDecl, SourceLocation AtLoc,1036 SourceLocation PropertyLoc) {1037 ObjCMethodDecl *Decl = AccessorDecl;1038 ObjCMethodDecl *ImplDecl = ObjCMethodDecl::Create(1039 Context, AtLoc.isValid() ? AtLoc : Decl->getBeginLoc(),1040 PropertyLoc.isValid() ? PropertyLoc : Decl->getEndLoc(),1041 Decl->getSelector(), Decl->getReturnType(),1042 Decl->getReturnTypeSourceInfo(), Impl, Decl->isInstanceMethod(),1043 Decl->isVariadic(), Decl->isPropertyAccessor(),1044 /*isSynthesizedAccessorStub=*/true, Decl->isImplicit(), Decl->isDefined(),1045 Decl->getImplementationControl(), Decl->hasRelatedResultType());1046 ImplDecl->getMethodFamily();1047 if (Decl->hasAttrs())1048 ImplDecl->setAttrs(Decl->getAttrs());1049 ImplDecl->setSelfDecl(Decl->getSelfDecl());1050 ImplDecl->setCmdDecl(Decl->getCmdDecl());1051 SmallVector<SourceLocation, 1> SelLocs;1052 Decl->getSelectorLocs(SelLocs);1053 ImplDecl->setMethodParams(Context, Decl->parameters(), SelLocs);1054 ImplDecl->setLexicalDeclContext(Impl);1055 ImplDecl->setDefined(false);1056 return ImplDecl;1057}1058 1059/// ActOnPropertyImplDecl - This routine performs semantic checks and1060/// builds the AST node for a property implementation declaration; declared1061/// as \@synthesize or \@dynamic.1062///1063Decl *SemaObjC::ActOnPropertyImplDecl(1064 Scope *S, SourceLocation AtLoc, SourceLocation PropertyLoc, bool Synthesize,1065 IdentifierInfo *PropertyId, IdentifierInfo *PropertyIvar,1066 SourceLocation PropertyIvarLoc, ObjCPropertyQueryKind QueryKind) {1067 ASTContext &Context = getASTContext();1068 ObjCContainerDecl *ClassImpDecl =1069 dyn_cast<ObjCContainerDecl>(SemaRef.CurContext);1070 // Make sure we have a context for the property implementation declaration.1071 if (!ClassImpDecl) {1072 Diag(AtLoc, diag::err_missing_property_context);1073 return nullptr;1074 }1075 if (PropertyIvarLoc.isInvalid())1076 PropertyIvarLoc = PropertyLoc;1077 SourceLocation PropertyDiagLoc = PropertyLoc;1078 if (PropertyDiagLoc.isInvalid())1079 PropertyDiagLoc = ClassImpDecl->getBeginLoc();1080 ObjCPropertyDecl *property = nullptr;1081 ObjCInterfaceDecl *IDecl = nullptr;1082 // Find the class or category class where this property must have1083 // a declaration.1084 ObjCImplementationDecl *IC = nullptr;1085 ObjCCategoryImplDecl *CatImplClass = nullptr;1086 if ((IC = dyn_cast<ObjCImplementationDecl>(ClassImpDecl))) {1087 IDecl = IC->getClassInterface();1088 // We always synthesize an interface for an implementation1089 // without an interface decl. So, IDecl is always non-zero.1090 assert(IDecl &&1091 "ActOnPropertyImplDecl - @implementation without @interface");1092 1093 // Look for this property declaration in the @implementation's @interface1094 property = IDecl->FindPropertyDeclaration(PropertyId, QueryKind);1095 if (!property) {1096 Diag(PropertyLoc, diag::err_bad_property_decl) << IDecl->getDeclName();1097 return nullptr;1098 }1099 if (property->isClassProperty() && Synthesize) {1100 Diag(PropertyLoc, diag::err_synthesize_on_class_property) << PropertyId;1101 return nullptr;1102 }1103 unsigned PIkind = property->getPropertyAttributesAsWritten();1104 if ((PIkind & (ObjCPropertyAttribute::kind_atomic |1105 ObjCPropertyAttribute::kind_nonatomic)) == 0) {1106 if (AtLoc.isValid())1107 Diag(AtLoc, diag::warn_implicit_atomic_property);1108 else1109 Diag(IC->getLocation(), diag::warn_auto_implicit_atomic_property);1110 Diag(property->getLocation(), diag::note_property_declare);1111 }1112 1113 if (const ObjCCategoryDecl *CD =1114 dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) {1115 if (!CD->IsClassExtension()) {1116 Diag(PropertyLoc, diag::err_category_property) << CD->getDeclName();1117 Diag(property->getLocation(), diag::note_property_declare);1118 return nullptr;1119 }1120 }1121 if (Synthesize && (PIkind & ObjCPropertyAttribute::kind_readonly) &&1122 property->hasAttr<IBOutletAttr>() && !AtLoc.isValid()) {1123 bool ReadWriteProperty = false;1124 // Search into the class extensions and see if 'readonly property is1125 // redeclared 'readwrite', then no warning is to be issued.1126 for (auto *Ext : IDecl->known_extensions()) {1127 DeclContext::lookup_result R = Ext->lookup(property->getDeclName());1128 if (auto *ExtProp = R.find_first<ObjCPropertyDecl>()) {1129 PIkind = ExtProp->getPropertyAttributesAsWritten();1130 if (PIkind & ObjCPropertyAttribute::kind_readwrite) {1131 ReadWriteProperty = true;1132 break;1133 }1134 }1135 }1136 1137 if (!ReadWriteProperty) {1138 Diag(property->getLocation(), diag::warn_auto_readonly_iboutlet_property)1139 << property;1140 SourceLocation readonlyLoc;1141 if (LocPropertyAttribute(Context, "readonly",1142 property->getLParenLoc(), readonlyLoc)) {1143 SourceLocation endLoc =1144 readonlyLoc.getLocWithOffset(strlen("readonly")-1);1145 SourceRange ReadonlySourceRange(readonlyLoc, endLoc);1146 Diag(property->getLocation(),1147 diag::note_auto_readonly_iboutlet_fixup_suggest) <<1148 FixItHint::CreateReplacement(ReadonlySourceRange, "readwrite");1149 }1150 }1151 }1152 if (Synthesize && isa<ObjCProtocolDecl>(property->getDeclContext()))1153 property = SelectPropertyForSynthesisFromProtocols(SemaRef, AtLoc, IDecl,1154 property);1155 1156 } else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) {1157 if (Synthesize) {1158 Diag(AtLoc, diag::err_synthesize_category_decl);1159 return nullptr;1160 }1161 IDecl = CatImplClass->getClassInterface();1162 if (!IDecl) {1163 Diag(AtLoc, diag::err_missing_property_interface);1164 return nullptr;1165 }1166 ObjCCategoryDecl *Category =1167 IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier());1168 1169 // If category for this implementation not found, it is an error which1170 // has already been reported eralier.1171 if (!Category)1172 return nullptr;1173 // Look for this property declaration in @implementation's category1174 property = Category->FindPropertyDeclaration(PropertyId, QueryKind);1175 if (!property) {1176 Diag(PropertyLoc, diag::err_bad_category_property_decl)1177 << Category->getDeclName();1178 return nullptr;1179 }1180 } else {1181 Diag(AtLoc, diag::err_bad_property_context);1182 return nullptr;1183 }1184 ObjCIvarDecl *Ivar = nullptr;1185 bool CompleteTypeErr = false;1186 bool compat = true;1187 // Check that we have a valid, previously declared ivar for @synthesize1188 if (Synthesize) {1189 // @synthesize1190 if (!PropertyIvar)1191 PropertyIvar = PropertyId;1192 // Check that this is a previously declared 'ivar' in 'IDecl' interface1193 ObjCInterfaceDecl *ClassDeclared;1194 Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared);1195 QualType PropType = property->getType();1196 QualType PropertyIvarType = PropType.getNonReferenceType();1197 1198 if (SemaRef.RequireCompleteType(PropertyDiagLoc, PropertyIvarType,1199 diag::err_incomplete_synthesized_property,1200 property->getDeclName())) {1201 Diag(property->getLocation(), diag::note_property_declare);1202 CompleteTypeErr = true;1203 }1204 1205 if (getLangOpts().ObjCAutoRefCount &&1206 (property->getPropertyAttributesAsWritten() &1207 ObjCPropertyAttribute::kind_readonly) &&1208 PropertyIvarType->isObjCRetainableType()) {1209 setImpliedPropertyAttributeForReadOnlyProperty(property, Ivar);1210 }1211 1212 ObjCPropertyAttribute::Kind kind = property->getPropertyAttributes();1213 1214 bool isARCWeak = false;1215 if (kind & ObjCPropertyAttribute::kind_weak) {1216 // Add GC __weak to the ivar type if the property is weak.1217 if (getLangOpts().getGC() != LangOptions::NonGC) {1218 assert(!getLangOpts().ObjCAutoRefCount);1219 if (PropertyIvarType.isObjCGCStrong()) {1220 Diag(PropertyDiagLoc, diag::err_gc_weak_property_strong_type);1221 Diag(property->getLocation(), diag::note_property_declare);1222 } else {1223 PropertyIvarType =1224 Context.getObjCGCQualType(PropertyIvarType, Qualifiers::Weak);1225 }1226 1227 // Otherwise, check whether ARC __weak is enabled and works with1228 // the property type.1229 } else {1230 if (!getLangOpts().ObjCWeak) {1231 // Only complain here when synthesizing an ivar.1232 if (!Ivar) {1233 Diag(PropertyDiagLoc,1234 getLangOpts().ObjCWeakRuntime1235 ? diag::err_synthesizing_arc_weak_property_disabled1236 : diag::err_synthesizing_arc_weak_property_no_runtime);1237 Diag(property->getLocation(), diag::note_property_declare);1238 }1239 CompleteTypeErr = true; // suppress later diagnostics about the ivar1240 } else {1241 isARCWeak = true;1242 if (const ObjCObjectPointerType *ObjT =1243 PropertyIvarType->getAs<ObjCObjectPointerType>()) {1244 const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl();1245 if (ObjI && ObjI->isArcWeakrefUnavailable()) {1246 Diag(property->getLocation(),1247 diag::err_arc_weak_unavailable_property)1248 << PropertyIvarType;1249 Diag(ClassImpDecl->getLocation(), diag::note_implemented_by_class)1250 << ClassImpDecl->getName();1251 }1252 }1253 }1254 }1255 }1256 1257 if (AtLoc.isInvalid()) {1258 // Check when default synthesizing a property that there is1259 // an ivar matching property name and issue warning; since this1260 // is the most common case of not using an ivar used for backing1261 // property in non-default synthesis case.1262 ObjCInterfaceDecl *ClassDeclared=nullptr;1263 ObjCIvarDecl *originalIvar =1264 IDecl->lookupInstanceVariable(property->getIdentifier(),1265 ClassDeclared);1266 if (originalIvar) {1267 Diag(PropertyDiagLoc,1268 diag::warn_autosynthesis_property_ivar_match)1269 << PropertyId << (Ivar == nullptr) << PropertyIvar1270 << originalIvar->getIdentifier();1271 Diag(property->getLocation(), diag::note_property_declare);1272 Diag(originalIvar->getLocation(), diag::note_ivar_decl);1273 }1274 }1275 1276 if (!Ivar) {1277 // In ARC, give the ivar a lifetime qualifier based on the1278 // property attributes.1279 if ((getLangOpts().ObjCAutoRefCount || isARCWeak) &&1280 !PropertyIvarType.getObjCLifetime() &&1281 PropertyIvarType->isObjCRetainableType()) {1282 1283 // It's an error if we have to do this and the user didn't1284 // explicitly write an ownership attribute on the property.1285 if (!hasWrittenStorageAttribute(property, QueryKind) &&1286 !(kind & ObjCPropertyAttribute::kind_strong)) {1287 Diag(PropertyDiagLoc,1288 diag::err_arc_objc_property_default_assign_on_object);1289 Diag(property->getLocation(), diag::note_property_declare);1290 } else {1291 Qualifiers::ObjCLifetime lifetime =1292 getImpliedARCOwnership(kind, PropertyIvarType);1293 assert(lifetime && "no lifetime for property?");1294 1295 Qualifiers qs;1296 qs.addObjCLifetime(lifetime);1297 PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs);1298 }1299 }1300 1301 if (Context.getLangOpts().PointerAuthObjcInterfaceSel &&1302 !PropertyIvarType.getPointerAuth()) {1303 if (Context.isObjCSelType(QualType(PropertyIvarType.getTypePtr(), 0))) {1304 if (auto PAQ = Context.getObjCMemberSelTypePtrAuth())1305 PropertyIvarType =1306 Context.getPointerAuthType(PropertyIvarType, PAQ);1307 }1308 }1309 1310 Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl,1311 PropertyIvarLoc,PropertyIvarLoc, PropertyIvar,1312 PropertyIvarType, /*TInfo=*/nullptr,1313 ObjCIvarDecl::Private,1314 (Expr *)nullptr, true);1315 if (SemaRef.RequireNonAbstractType(PropertyIvarLoc, PropertyIvarType,1316 diag::err_abstract_type_in_decl,1317 Sema::AbstractSynthesizedIvarType)) {1318 Diag(property->getLocation(), diag::note_property_declare);1319 // An abstract type is as bad as an incomplete type.1320 CompleteTypeErr = true;1321 }1322 if (!CompleteTypeErr) {1323 if (const auto *RD = PropertyIvarType->getAsRecordDecl();1324 RD && RD->hasFlexibleArrayMember()) {1325 Diag(PropertyIvarLoc, diag::err_synthesize_variable_sized_ivar)1326 << PropertyIvarType;1327 CompleteTypeErr = true; // suppress later diagnostics about the ivar1328 }1329 }1330 if (CompleteTypeErr)1331 Ivar->setInvalidDecl();1332 ClassImpDecl->addDecl(Ivar);1333 IDecl->makeDeclVisibleInContext(Ivar);1334 1335 if (getLangOpts().ObjCRuntime.isFragile())1336 Diag(PropertyDiagLoc, diag::err_missing_property_ivar_decl)1337 << PropertyId;1338 // Note! I deliberately want it to fall thru so, we have a1339 // a property implementation and to avoid future warnings.1340 } else if (getLangOpts().ObjCRuntime.isNonFragile() &&1341 !declaresSameEntity(ClassDeclared, IDecl)) {1342 Diag(PropertyDiagLoc, diag::err_ivar_in_superclass_use)1343 << property->getDeclName() << Ivar->getDeclName()1344 << ClassDeclared->getDeclName();1345 Diag(Ivar->getLocation(), diag::note_previous_access_declaration)1346 << Ivar << Ivar->getName();1347 // Note! I deliberately want it to fall thru so more errors are caught.1348 }1349 property->setPropertyIvarDecl(Ivar);1350 1351 QualType IvarType = Context.getCanonicalType(Ivar->getType());1352 1353 // Check that type of property and its ivar are type compatible.1354 if (!Context.hasSameType(PropertyIvarType, IvarType)) {1355 if (isa<ObjCObjectPointerType>(PropertyIvarType)1356 && isa<ObjCObjectPointerType>(IvarType))1357 compat = Context.canAssignObjCInterfaces(1358 PropertyIvarType->castAs<ObjCObjectPointerType>(),1359 IvarType->castAs<ObjCObjectPointerType>());1360 else {1361 compat = SemaRef.IsAssignConvertCompatible(1362 SemaRef.CheckAssignmentConstraints(PropertyIvarLoc,1363 PropertyIvarType, IvarType));1364 }1365 if (!compat) {1366 Diag(PropertyDiagLoc, diag::err_property_ivar_type)1367 << property->getDeclName() << PropType1368 << Ivar->getDeclName() << IvarType;1369 Diag(Ivar->getLocation(), diag::note_ivar_decl);1370 // Note! I deliberately want it to fall thru so, we have a1371 // a property implementation and to avoid future warnings.1372 }1373 else {1374 // FIXME! Rules for properties are somewhat different that those1375 // for assignments. Use a new routine to consolidate all cases;1376 // specifically for property redeclarations as well as for ivars.1377 QualType lhsType =Context.getCanonicalType(PropertyIvarType).getUnqualifiedType();1378 QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType();1379 if (lhsType != rhsType &&1380 lhsType->isArithmeticType()) {1381 Diag(PropertyDiagLoc, diag::err_property_ivar_type)1382 << property->getDeclName() << PropType1383 << Ivar->getDeclName() << IvarType;1384 Diag(Ivar->getLocation(), diag::note_ivar_decl);1385 // Fall thru - see previous comment1386 }1387 }1388 // __weak is explicit. So it works on Canonical type.1389 if ((PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() &&1390 getLangOpts().getGC() != LangOptions::NonGC)) {1391 Diag(PropertyDiagLoc, diag::err_weak_property)1392 << property->getDeclName() << Ivar->getDeclName();1393 Diag(Ivar->getLocation(), diag::note_ivar_decl);1394 // Fall thru - see previous comment1395 }1396 // Fall thru - see previous comment1397 if ((property->getType()->isObjCObjectPointerType() ||1398 PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&1399 getLangOpts().getGC() != LangOptions::NonGC) {1400 Diag(PropertyDiagLoc, diag::err_strong_property)1401 << property->getDeclName() << Ivar->getDeclName();1402 // Fall thru - see previous comment1403 }1404 }1405 if (getLangOpts().ObjCAutoRefCount || isARCWeak ||1406 Ivar->getType().getObjCLifetime())1407 checkARCPropertyImpl(SemaRef, PropertyLoc, property, Ivar);1408 } else if (PropertyIvar)1409 // @dynamic1410 Diag(PropertyDiagLoc, diag::err_dynamic_property_ivar_decl);1411 1412 assert (property && "ActOnPropertyImplDecl - property declaration missing");1413 ObjCPropertyImplDecl *PIDecl = ObjCPropertyImplDecl::Create(1414 Context, SemaRef.CurContext, AtLoc, PropertyLoc, property,1415 (Synthesize ? ObjCPropertyImplDecl::Synthesize1416 : ObjCPropertyImplDecl::Dynamic),1417 Ivar, PropertyIvarLoc);1418 1419 if (CompleteTypeErr || !compat)1420 PIDecl->setInvalidDecl();1421 1422 if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) {1423 getterMethod->createImplicitParams(Context, IDecl);1424 1425 // Redeclare the getter within the implementation as DeclContext.1426 if (Synthesize) {1427 // If the method hasn't been overridden, create a synthesized implementation.1428 ObjCMethodDecl *OMD = ClassImpDecl->getMethod(1429 getterMethod->getSelector(), getterMethod->isInstanceMethod());1430 if (!OMD)1431 OMD = RedeclarePropertyAccessor(Context, IC, getterMethod, AtLoc,1432 PropertyLoc);1433 PIDecl->setGetterMethodDecl(OMD);1434 }1435 1436 if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr &&1437 Ivar->getType()->isRecordType()) {1438 // For Objective-C++, need to synthesize the AST for the IVAR object to be1439 // returned by the getter as it must conform to C++'s copy-return rules.1440 // FIXME. Eventually we want to do this for Objective-C as well.1441 Sema::SynthesizedFunctionScope Scope(SemaRef, getterMethod);1442 ImplicitParamDecl *SelfDecl = getterMethod->getSelfDecl();1443 DeclRefExpr *SelfExpr = new (Context)1444 DeclRefExpr(Context, SelfDecl, false, SelfDecl->getType(), VK_LValue,1445 PropertyDiagLoc);1446 SemaRef.MarkDeclRefReferenced(SelfExpr);1447 Expr *LoadSelfExpr = ImplicitCastExpr::Create(1448 Context, SelfDecl->getType(), CK_LValueToRValue, SelfExpr, nullptr,1449 VK_PRValue, FPOptionsOverride());1450 Expr *IvarRefExpr =1451 new (Context) ObjCIvarRefExpr(Ivar,1452 Ivar->getUsageType(SelfDecl->getType()),1453 PropertyDiagLoc,1454 Ivar->getLocation(),1455 LoadSelfExpr, true, true);1456 ExprResult Res = SemaRef.PerformCopyInitialization(1457 InitializedEntity::InitializeResult(PropertyDiagLoc,1458 getterMethod->getReturnType()),1459 PropertyDiagLoc, IvarRefExpr);1460 if (!Res.isInvalid()) {1461 Expr *ResExpr = Res.getAs<Expr>();1462 if (ResExpr)1463 ResExpr = SemaRef.MaybeCreateExprWithCleanups(ResExpr);1464 PIDecl->setGetterCXXConstructor(ResExpr);1465 }1466 }1467 if (property->hasAttr<NSReturnsNotRetainedAttr>() &&1468 !getterMethod->hasAttr<NSReturnsNotRetainedAttr>()) {1469 Diag(getterMethod->getLocation(),1470 diag::warn_property_getter_owning_mismatch);1471 Diag(property->getLocation(), diag::note_property_declare);1472 }1473 if (getLangOpts().ObjCAutoRefCount && Synthesize)1474 switch (getterMethod->getMethodFamily()) {1475 case OMF_retain:1476 case OMF_retainCount:1477 case OMF_release:1478 case OMF_autorelease:1479 Diag(getterMethod->getLocation(), diag::err_arc_illegal_method_def)1480 << 1 << getterMethod->getSelector();1481 break;1482 default:1483 break;1484 }1485 }1486 1487 if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) {1488 setterMethod->createImplicitParams(Context, IDecl);1489 1490 // Redeclare the setter within the implementation as DeclContext.1491 if (Synthesize) {1492 ObjCMethodDecl *OMD = ClassImpDecl->getMethod(1493 setterMethod->getSelector(), setterMethod->isInstanceMethod());1494 if (!OMD)1495 OMD = RedeclarePropertyAccessor(Context, IC, setterMethod,1496 AtLoc, PropertyLoc);1497 PIDecl->setSetterMethodDecl(OMD);1498 }1499 1500 if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr &&1501 Ivar->getType()->isRecordType()) {1502 // FIXME. Eventually we want to do this for Objective-C as well.1503 Sema::SynthesizedFunctionScope Scope(SemaRef, setterMethod);1504 ImplicitParamDecl *SelfDecl = setterMethod->getSelfDecl();1505 DeclRefExpr *SelfExpr = new (Context)1506 DeclRefExpr(Context, SelfDecl, false, SelfDecl->getType(), VK_LValue,1507 PropertyDiagLoc);1508 SemaRef.MarkDeclRefReferenced(SelfExpr);1509 Expr *LoadSelfExpr = ImplicitCastExpr::Create(1510 Context, SelfDecl->getType(), CK_LValueToRValue, SelfExpr, nullptr,1511 VK_PRValue, FPOptionsOverride());1512 Expr *lhs =1513 new (Context) ObjCIvarRefExpr(Ivar,1514 Ivar->getUsageType(SelfDecl->getType()),1515 PropertyDiagLoc,1516 Ivar->getLocation(),1517 LoadSelfExpr, true, true);1518 ObjCMethodDecl::param_iterator P = setterMethod->param_begin();1519 ParmVarDecl *Param = (*P);1520 QualType T = Param->getType().getNonReferenceType();1521 DeclRefExpr *rhs = new (Context)1522 DeclRefExpr(Context, Param, false, T, VK_LValue, PropertyDiagLoc);1523 SemaRef.MarkDeclRefReferenced(rhs);1524 ExprResult Res =1525 SemaRef.BuildBinOp(S, PropertyDiagLoc, BO_Assign, lhs, rhs);1526 if (property->getPropertyAttributes() &1527 ObjCPropertyAttribute::kind_atomic) {1528 Expr *callExpr = Res.getAs<Expr>();1529 if (const CXXOperatorCallExpr *CXXCE =1530 dyn_cast_or_null<CXXOperatorCallExpr>(callExpr))1531 if (const FunctionDecl *FuncDecl = CXXCE->getDirectCallee())1532 if (!FuncDecl->isTrivial())1533 if (property->getType()->isReferenceType()) {1534 Diag(PropertyDiagLoc,1535 diag::err_atomic_property_nontrivial_assign_op)1536 << property->getType();1537 Diag(FuncDecl->getBeginLoc(), diag::note_callee_decl)1538 << FuncDecl;1539 }1540 }1541 PIDecl->setSetterCXXAssignment(Res.getAs<Expr>());1542 }1543 }1544 1545 if (IC) {1546 if (Synthesize)1547 if (ObjCPropertyImplDecl *PPIDecl =1548 IC->FindPropertyImplIvarDecl(PropertyIvar)) {1549 Diag(PropertyLoc, diag::err_duplicate_ivar_use)1550 << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()1551 << PropertyIvar;1552 Diag(PPIDecl->getLocation(), diag::note_previous_use);1553 }1554 1555 if (ObjCPropertyImplDecl *PPIDecl1556 = IC->FindPropertyImplDecl(PropertyId, QueryKind)) {1557 Diag(PropertyLoc, diag::err_property_implemented) << PropertyId;1558 Diag(PPIDecl->getLocation(), diag::note_previous_declaration);1559 return nullptr;1560 }1561 IC->addPropertyImplementation(PIDecl);1562 if (getLangOpts().ObjCDefaultSynthProperties &&1563 getLangOpts().ObjCRuntime.isNonFragile() &&1564 !IDecl->isObjCRequiresPropertyDefs()) {1565 // Diagnose if an ivar was lazily synthesdized due to a previous1566 // use and if 1) property is @dynamic or 2) property is synthesized1567 // but it requires an ivar of different name.1568 ObjCInterfaceDecl *ClassDeclared=nullptr;1569 ObjCIvarDecl *Ivar = nullptr;1570 if (!Synthesize)1571 Ivar = IDecl->lookupInstanceVariable(PropertyId, ClassDeclared);1572 else {1573 if (PropertyIvar && PropertyIvar != PropertyId)1574 Ivar = IDecl->lookupInstanceVariable(PropertyId, ClassDeclared);1575 }1576 // Issue diagnostics only if Ivar belongs to current class.1577 if (Ivar && Ivar->getSynthesize() &&1578 declaresSameEntity(IC->getClassInterface(), ClassDeclared)) {1579 Diag(Ivar->getLocation(), diag::err_undeclared_var_use)1580 << PropertyId;1581 Ivar->setInvalidDecl();1582 }1583 }1584 } else {1585 if (Synthesize)1586 if (ObjCPropertyImplDecl *PPIDecl =1587 CatImplClass->FindPropertyImplIvarDecl(PropertyIvar)) {1588 Diag(PropertyDiagLoc, diag::err_duplicate_ivar_use)1589 << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()1590 << PropertyIvar;1591 Diag(PPIDecl->getLocation(), diag::note_previous_use);1592 }1593 1594 if (ObjCPropertyImplDecl *PPIDecl =1595 CatImplClass->FindPropertyImplDecl(PropertyId, QueryKind)) {1596 Diag(PropertyDiagLoc, diag::err_property_implemented) << PropertyId;1597 Diag(PPIDecl->getLocation(), diag::note_previous_declaration);1598 return nullptr;1599 }1600 CatImplClass->addPropertyImplementation(PIDecl);1601 }1602 1603 if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic &&1604 PIDecl->getPropertyDecl() &&1605 PIDecl->getPropertyDecl()->isDirectProperty()) {1606 Diag(PropertyLoc, diag::err_objc_direct_dynamic_property);1607 Diag(PIDecl->getPropertyDecl()->getLocation(),1608 diag::note_previous_declaration);1609 return nullptr;1610 }1611 1612 return PIDecl;1613}1614 1615//===----------------------------------------------------------------------===//1616// Helper methods.1617//===----------------------------------------------------------------------===//1618 1619/// DiagnosePropertyMismatch - Compares two properties for their1620/// attributes and types and warns on a variety of inconsistencies.1621///1622void SemaObjC::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,1623 ObjCPropertyDecl *SuperProperty,1624 const IdentifierInfo *inheritedName,1625 bool OverridingProtocolProperty) {1626 ASTContext &Context = getASTContext();1627 ObjCPropertyAttribute::Kind CAttr = Property->getPropertyAttributes();1628 ObjCPropertyAttribute::Kind SAttr = SuperProperty->getPropertyAttributes();1629 1630 // We allow readonly properties without an explicit ownership1631 // (assign/unsafe_unretained/weak/retain/strong/copy) in super class1632 // to be overridden by a property with any explicit ownership in the subclass.1633 if (!OverridingProtocolProperty &&1634 !getOwnershipRule(SAttr) && getOwnershipRule(CAttr))1635 ;1636 else {1637 if ((CAttr & ObjCPropertyAttribute::kind_readonly) &&1638 (SAttr & ObjCPropertyAttribute::kind_readwrite))1639 Diag(Property->getLocation(), diag::warn_readonly_property)1640 << Property->getDeclName() << inheritedName;1641 if ((CAttr & ObjCPropertyAttribute::kind_copy) !=1642 (SAttr & ObjCPropertyAttribute::kind_copy))1643 Diag(Property->getLocation(), diag::warn_property_attribute)1644 << Property->getDeclName() << "copy" << inheritedName;1645 else if (!(SAttr & ObjCPropertyAttribute::kind_readonly)) {1646 unsigned CAttrRetain = (CAttr & (ObjCPropertyAttribute::kind_retain |1647 ObjCPropertyAttribute::kind_strong));1648 unsigned SAttrRetain = (SAttr & (ObjCPropertyAttribute::kind_retain |1649 ObjCPropertyAttribute::kind_strong));1650 bool CStrong = (CAttrRetain != 0);1651 bool SStrong = (SAttrRetain != 0);1652 if (CStrong != SStrong)1653 Diag(Property->getLocation(), diag::warn_property_attribute)1654 << Property->getDeclName() << "retain (or strong)" << inheritedName;1655 }1656 }1657 1658 // Check for nonatomic; note that nonatomic is effectively1659 // meaningless for readonly properties, so don't diagnose if the1660 // atomic property is 'readonly'.1661 checkAtomicPropertyMismatch(SemaRef, SuperProperty, Property, false);1662 // Readonly properties from protocols can be implemented as "readwrite"1663 // with a custom setter name.1664 if (Property->getSetterName() != SuperProperty->getSetterName() &&1665 !(SuperProperty->isReadOnly() &&1666 isa<ObjCProtocolDecl>(SuperProperty->getDeclContext()))) {1667 Diag(Property->getLocation(), diag::warn_property_attribute)1668 << Property->getDeclName() << "setter" << inheritedName;1669 Diag(SuperProperty->getLocation(), diag::note_property_declare);1670 }1671 if (Property->getGetterName() != SuperProperty->getGetterName()) {1672 Diag(Property->getLocation(), diag::warn_property_attribute)1673 << Property->getDeclName() << "getter" << inheritedName;1674 Diag(SuperProperty->getLocation(), diag::note_property_declare);1675 }1676 1677 QualType LHSType =1678 Context.getCanonicalType(SuperProperty->getType());1679 QualType RHSType =1680 Context.getCanonicalType(Property->getType());1681 1682 if (!Context.propertyTypesAreCompatible(LHSType, RHSType)) {1683 // Do cases not handled in above.1684 // FIXME. For future support of covariant property types, revisit this.1685 bool IncompatibleObjC = false;1686 QualType ConvertedType;1687 if (!SemaRef.isObjCPointerConversion(RHSType, LHSType, ConvertedType,1688 IncompatibleObjC) ||1689 IncompatibleObjC) {1690 Diag(Property->getLocation(), diag::warn_property_types_are_incompatible)1691 << Property->getType() << SuperProperty->getType() << inheritedName;1692 Diag(SuperProperty->getLocation(), diag::note_property_declare);1693 }1694 }1695}1696 1697bool SemaObjC::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,1698 ObjCMethodDecl *GetterMethod,1699 SourceLocation Loc) {1700 ASTContext &Context = getASTContext();1701 if (!GetterMethod)1702 return false;1703 QualType GetterType = GetterMethod->getReturnType().getNonReferenceType();1704 QualType PropertyRValueType =1705 property->getType().getNonReferenceType().getAtomicUnqualifiedType();1706 bool compat = Context.hasSameType(PropertyRValueType, GetterType);1707 if (!compat) {1708 const ObjCObjectPointerType *propertyObjCPtr = nullptr;1709 const ObjCObjectPointerType *getterObjCPtr = nullptr;1710 if ((propertyObjCPtr =1711 PropertyRValueType->getAs<ObjCObjectPointerType>()) &&1712 (getterObjCPtr = GetterType->getAs<ObjCObjectPointerType>()))1713 compat = Context.canAssignObjCInterfaces(getterObjCPtr, propertyObjCPtr);1714 else if (!SemaRef.IsAssignConvertCompatible(1715 SemaRef.CheckAssignmentConstraints(Loc, GetterType,1716 PropertyRValueType))) {1717 Diag(Loc, diag::err_property_accessor_type)1718 << property->getDeclName() << PropertyRValueType1719 << GetterMethod->getSelector() << GetterType;1720 Diag(GetterMethod->getLocation(), diag::note_declared_at);1721 return true;1722 } else {1723 compat = true;1724 QualType lhsType = Context.getCanonicalType(PropertyRValueType);1725 QualType rhsType =Context.getCanonicalType(GetterType).getUnqualifiedType();1726 if (lhsType != rhsType && lhsType->isArithmeticType())1727 compat = false;1728 }1729 }1730 1731 if (!compat) {1732 Diag(Loc, diag::warn_accessor_property_type_mismatch)1733 << property->getDeclName()1734 << GetterMethod->getSelector();1735 Diag(GetterMethod->getLocation(), diag::note_declared_at);1736 return true;1737 }1738 1739 return false;1740}1741 1742/// CollectImmediateProperties - This routine collects all properties in1743/// the class and its conforming protocols; but not those in its super class.1744static void1745CollectImmediateProperties(ObjCContainerDecl *CDecl,1746 ObjCContainerDecl::PropertyMap &PropMap,1747 ObjCContainerDecl::PropertyMap &SuperPropMap,1748 bool CollectClassPropsOnly = false,1749 bool IncludeProtocols = true) {1750 if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {1751 for (auto *Prop : IDecl->properties()) {1752 if (CollectClassPropsOnly && !Prop->isClassProperty())1753 continue;1754 PropMap[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] =1755 Prop;1756 }1757 1758 // Collect the properties from visible extensions.1759 for (auto *Ext : IDecl->visible_extensions())1760 CollectImmediateProperties(Ext, PropMap, SuperPropMap,1761 CollectClassPropsOnly, IncludeProtocols);1762 1763 if (IncludeProtocols) {1764 // Scan through class's protocols.1765 for (auto *PI : IDecl->all_referenced_protocols())1766 CollectImmediateProperties(PI, PropMap, SuperPropMap,1767 CollectClassPropsOnly);1768 }1769 }1770 if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {1771 for (auto *Prop : CATDecl->properties()) {1772 if (CollectClassPropsOnly && !Prop->isClassProperty())1773 continue;1774 PropMap[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] =1775 Prop;1776 }1777 if (IncludeProtocols) {1778 // Scan through class's protocols.1779 for (auto *PI : CATDecl->protocols())1780 CollectImmediateProperties(PI, PropMap, SuperPropMap,1781 CollectClassPropsOnly);1782 }1783 }1784 else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) {1785 for (auto *Prop : PDecl->properties()) {1786 if (CollectClassPropsOnly && !Prop->isClassProperty())1787 continue;1788 ObjCPropertyDecl *PropertyFromSuper =1789 SuperPropMap[std::make_pair(Prop->getIdentifier(),1790 Prop->isClassProperty())];1791 // Exclude property for protocols which conform to class's super-class,1792 // as super-class has to implement the property.1793 if (!PropertyFromSuper ||1794 PropertyFromSuper->getIdentifier() != Prop->getIdentifier()) {1795 ObjCPropertyDecl *&PropEntry =1796 PropMap[std::make_pair(Prop->getIdentifier(),1797 Prop->isClassProperty())];1798 if (!PropEntry)1799 PropEntry = Prop;1800 }1801 }1802 // Scan through protocol's protocols.1803 for (auto *PI : PDecl->protocols())1804 CollectImmediateProperties(PI, PropMap, SuperPropMap,1805 CollectClassPropsOnly);1806 }1807}1808 1809/// CollectSuperClassPropertyImplementations - This routine collects list of1810/// properties to be implemented in super class(s) and also coming from their1811/// conforming protocols.1812static void CollectSuperClassPropertyImplementations(ObjCInterfaceDecl *CDecl,1813 ObjCInterfaceDecl::PropertyMap &PropMap) {1814 if (ObjCInterfaceDecl *SDecl = CDecl->getSuperClass()) {1815 while (SDecl) {1816 SDecl->collectPropertiesToImplement(PropMap);1817 SDecl = SDecl->getSuperClass();1818 }1819 }1820}1821 1822/// IvarBacksCurrentMethodAccessor - This routine returns 'true' if 'IV' is1823/// an ivar synthesized for 'Method' and 'Method' is a property accessor1824/// declared in class 'IFace'.1825bool SemaObjC::IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace,1826 ObjCMethodDecl *Method,1827 ObjCIvarDecl *IV) {1828 if (!IV->getSynthesize())1829 return false;1830 ObjCMethodDecl *IMD = IFace->lookupMethod(Method->getSelector(),1831 Method->isInstanceMethod());1832 if (!IMD || !IMD->isPropertyAccessor())1833 return false;1834 1835 // look up a property declaration whose one of its accessors is implemented1836 // by this method.1837 for (const auto *Property : IFace->instance_properties()) {1838 if ((Property->getGetterName() == IMD->getSelector() ||1839 Property->getSetterName() == IMD->getSelector()) &&1840 (Property->getPropertyIvarDecl() == IV))1841 return true;1842 }1843 // Also look up property declaration in class extension whose one of its1844 // accessors is implemented by this method.1845 for (const auto *Ext : IFace->known_extensions())1846 for (const auto *Property : Ext->instance_properties())1847 if ((Property->getGetterName() == IMD->getSelector() ||1848 Property->getSetterName() == IMD->getSelector()) &&1849 (Property->getPropertyIvarDecl() == IV))1850 return true;1851 return false;1852}1853 1854static bool SuperClassImplementsProperty(ObjCInterfaceDecl *IDecl,1855 ObjCPropertyDecl *Prop) {1856 bool SuperClassImplementsGetter = false;1857 bool SuperClassImplementsSetter = false;1858 if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_readonly)1859 SuperClassImplementsSetter = true;1860 1861 while (IDecl->getSuperClass()) {1862 ObjCInterfaceDecl *SDecl = IDecl->getSuperClass();1863 if (!SuperClassImplementsGetter && SDecl->getInstanceMethod(Prop->getGetterName()))1864 SuperClassImplementsGetter = true;1865 1866 if (!SuperClassImplementsSetter && SDecl->getInstanceMethod(Prop->getSetterName()))1867 SuperClassImplementsSetter = true;1868 if (SuperClassImplementsGetter && SuperClassImplementsSetter)1869 return true;1870 IDecl = IDecl->getSuperClass();1871 }1872 return false;1873}1874 1875/// Default synthesizes all properties which must be synthesized1876/// in class's \@implementation.1877void SemaObjC::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl,1878 ObjCInterfaceDecl *IDecl,1879 SourceLocation AtEnd) {1880 ASTContext &Context = getASTContext();1881 ObjCInterfaceDecl::PropertyMap PropMap;1882 IDecl->collectPropertiesToImplement(PropMap);1883 if (PropMap.empty())1884 return;1885 ObjCInterfaceDecl::PropertyMap SuperPropMap;1886 CollectSuperClassPropertyImplementations(IDecl, SuperPropMap);1887 1888 for (const auto &PropEntry : PropMap) {1889 ObjCPropertyDecl *Prop = PropEntry.second;1890 // Is there a matching property synthesize/dynamic?1891 if (Prop->isInvalidDecl() ||1892 Prop->isClassProperty() ||1893 Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional)1894 continue;1895 // Property may have been synthesized by user.1896 if (IMPDecl->FindPropertyImplDecl(1897 Prop->getIdentifier(), Prop->getQueryKind()))1898 continue;1899 ObjCMethodDecl *ImpMethod = IMPDecl->getInstanceMethod(Prop->getGetterName());1900 if (ImpMethod && !ImpMethod->getBody()) {1901 if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_readonly)1902 continue;1903 ImpMethod = IMPDecl->getInstanceMethod(Prop->getSetterName());1904 if (ImpMethod && !ImpMethod->getBody())1905 continue;1906 }1907 if (ObjCPropertyImplDecl *PID =1908 IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier())) {1909 Diag(Prop->getLocation(), diag::warn_no_autosynthesis_shared_ivar_property)1910 << Prop->getIdentifier();1911 if (PID->getLocation().isValid())1912 Diag(PID->getLocation(), diag::note_property_synthesize);1913 continue;1914 }1915 ObjCPropertyDecl *PropInSuperClass =1916 SuperPropMap[std::make_pair(Prop->getIdentifier(),1917 Prop->isClassProperty())];1918 if (ObjCProtocolDecl *Proto =1919 dyn_cast<ObjCProtocolDecl>(Prop->getDeclContext())) {1920 // We won't auto-synthesize properties declared in protocols.1921 // Suppress the warning if class's superclass implements property's1922 // getter and implements property's setter (if readwrite property).1923 // Or, if property is going to be implemented in its super class.1924 if (!SuperClassImplementsProperty(IDecl, Prop) && !PropInSuperClass) {1925 Diag(IMPDecl->getLocation(),1926 diag::warn_auto_synthesizing_protocol_property)1927 << Prop << Proto;1928 Diag(Prop->getLocation(), diag::note_property_declare);1929 std::string FixIt =1930 (Twine("@synthesize ") + Prop->getName() + ";\n\n").str();1931 Diag(AtEnd, diag::note_add_synthesize_directive)1932 << FixItHint::CreateInsertion(AtEnd, FixIt);1933 }1934 continue;1935 }1936 // If property to be implemented in the super class, ignore.1937 if (PropInSuperClass) {1938 if ((Prop->getPropertyAttributes() &1939 ObjCPropertyAttribute::kind_readwrite) &&1940 (PropInSuperClass->getPropertyAttributes() &1941 ObjCPropertyAttribute::kind_readonly) &&1942 !IMPDecl->getInstanceMethod(Prop->getSetterName()) &&1943 !IDecl->HasUserDeclaredSetterMethod(Prop)) {1944 Diag(Prop->getLocation(), diag::warn_no_autosynthesis_property)1945 << Prop->getIdentifier();1946 Diag(PropInSuperClass->getLocation(), diag::note_property_declare);1947 } else {1948 Diag(Prop->getLocation(), diag::warn_autosynthesis_property_in_superclass)1949 << Prop->getIdentifier();1950 Diag(PropInSuperClass->getLocation(), diag::note_property_declare);1951 Diag(IMPDecl->getLocation(), diag::note_while_in_implementation);1952 }1953 continue;1954 }1955 // We use invalid SourceLocations for the synthesized ivars since they1956 // aren't really synthesized at a particular location; they just exist.1957 // Saying that they are located at the @implementation isn't really going1958 // to help users.1959 ObjCPropertyImplDecl *PIDecl = dyn_cast_or_null<ObjCPropertyImplDecl>(1960 ActOnPropertyImplDecl(S, SourceLocation(), SourceLocation(),1961 true,1962 /* property = */ Prop->getIdentifier(),1963 /* ivar = */ Prop->getDefaultSynthIvarName(Context),1964 Prop->getLocation(), Prop->getQueryKind()));1965 if (PIDecl && !Prop->isUnavailable()) {1966 Diag(Prop->getLocation(), diag::warn_missing_explicit_synthesis);1967 Diag(IMPDecl->getLocation(), diag::note_while_in_implementation);1968 }1969 }1970}1971 1972void SemaObjC::DefaultSynthesizeProperties(Scope *S, Decl *D,1973 SourceLocation AtEnd) {1974 if (!getLangOpts().ObjCDefaultSynthProperties ||1975 getLangOpts().ObjCRuntime.isFragile())1976 return;1977 ObjCImplementationDecl *IC=dyn_cast_or_null<ObjCImplementationDecl>(D);1978 if (!IC)1979 return;1980 if (ObjCInterfaceDecl* IDecl = IC->getClassInterface())1981 if (!IDecl->isObjCRequiresPropertyDefs())1982 DefaultSynthesizeProperties(S, IC, IDecl, AtEnd);1983}1984 1985static void DiagnoseUnimplementedAccessor(1986 Sema &S, ObjCInterfaceDecl *PrimaryClass, Selector Method,1987 ObjCImplDecl *IMPDecl, ObjCContainerDecl *CDecl, ObjCCategoryDecl *C,1988 ObjCPropertyDecl *Prop,1989 llvm::SmallPtrSet<const ObjCMethodDecl *, 8> &SMap) {1990 // Check to see if we have a corresponding selector in SMap and with the1991 // right method type.1992 auto I = llvm::find_if(SMap, [&](const ObjCMethodDecl *x) {1993 return x->getSelector() == Method &&1994 x->isClassMethod() == Prop->isClassProperty();1995 });1996 // When reporting on missing property setter/getter implementation in1997 // categories, do not report when they are declared in primary class,1998 // class's protocol, or one of it super classes. This is because,1999 // the class is going to implement them.2000 if (I == SMap.end() &&2001 (PrimaryClass == nullptr ||2002 !PrimaryClass->lookupPropertyAccessor(Method, C,2003 Prop->isClassProperty()))) {2004 unsigned diag =2005 isa<ObjCCategoryDecl>(CDecl)2006 ? (Prop->isClassProperty()2007 ? diag::warn_impl_required_in_category_for_class_property2008 : diag::warn_setter_getter_impl_required_in_category)2009 : (Prop->isClassProperty()2010 ? diag::warn_impl_required_for_class_property2011 : diag::warn_setter_getter_impl_required);2012 S.Diag(IMPDecl->getLocation(), diag) << Prop->getDeclName() << Method;2013 S.Diag(Prop->getLocation(), diag::note_property_declare);2014 if (S.LangOpts.ObjCDefaultSynthProperties &&2015 S.LangOpts.ObjCRuntime.isNonFragile())2016 if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl))2017 if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs())2018 S.Diag(RID->getLocation(), diag::note_suppressed_class_declare);2019 }2020}2021 2022void SemaObjC::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl *IMPDecl,2023 ObjCContainerDecl *CDecl,2024 bool SynthesizeProperties) {2025 ObjCContainerDecl::PropertyMap PropMap;2026 ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);2027 2028 // Since we don't synthesize class properties, we should emit diagnose even2029 // if SynthesizeProperties is true.2030 ObjCContainerDecl::PropertyMap NoNeedToImplPropMap;2031 // Gather properties which need not be implemented in this class2032 // or category.2033 if (!IDecl)2034 if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {2035 // For categories, no need to implement properties declared in2036 // its primary class (and its super classes) if property is2037 // declared in one of those containers.2038 if ((IDecl = C->getClassInterface())) {2039 IDecl->collectPropertiesToImplement(NoNeedToImplPropMap);2040 }2041 }2042 if (IDecl)2043 CollectSuperClassPropertyImplementations(IDecl, NoNeedToImplPropMap);2044 2045 // When SynthesizeProperties is true, we only check class properties.2046 CollectImmediateProperties(CDecl, PropMap, NoNeedToImplPropMap,2047 SynthesizeProperties/*CollectClassPropsOnly*/);2048 2049 // Scan the @interface to see if any of the protocols it adopts2050 // require an explicit implementation, via attribute2051 // 'objc_protocol_requires_explicit_implementation'.2052 if (IDecl) {2053 std::unique_ptr<ObjCContainerDecl::PropertyMap> LazyMap;2054 2055 for (auto *PDecl : IDecl->all_referenced_protocols()) {2056 if (!PDecl->hasAttr<ObjCExplicitProtocolImplAttr>())2057 continue;2058 // Lazily construct a set of all the properties in the @interface2059 // of the class, without looking at the superclass. We cannot2060 // use the call to CollectImmediateProperties() above as that2061 // utilizes information from the super class's properties as well2062 // as scans the adopted protocols. This work only triggers for protocols2063 // with the attribute, which is very rare, and only occurs when2064 // analyzing the @implementation.2065 if (!LazyMap) {2066 ObjCContainerDecl::PropertyMap NoNeedToImplPropMap;2067 LazyMap.reset(new ObjCContainerDecl::PropertyMap());2068 CollectImmediateProperties(CDecl, *LazyMap, NoNeedToImplPropMap,2069 /* CollectClassPropsOnly */ false,2070 /* IncludeProtocols */ false);2071 }2072 // Add the properties of 'PDecl' to the list of properties that2073 // need to be implemented.2074 for (auto *PropDecl : PDecl->properties()) {2075 if ((*LazyMap)[std::make_pair(PropDecl->getIdentifier(),2076 PropDecl->isClassProperty())])2077 continue;2078 PropMap[std::make_pair(PropDecl->getIdentifier(),2079 PropDecl->isClassProperty())] = PropDecl;2080 }2081 }2082 }2083 2084 if (PropMap.empty())2085 return;2086 2087 llvm::DenseSet<ObjCPropertyDecl *> PropImplMap;2088 for (const auto *I : IMPDecl->property_impls())2089 PropImplMap.insert(I->getPropertyDecl());2090 2091 // Collect property accessors implemented in current implementation.2092 llvm::SmallPtrSet<const ObjCMethodDecl *, 8> InsMap(llvm::from_range,2093 IMPDecl->methods());2094 2095 ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl);2096 ObjCInterfaceDecl *PrimaryClass = nullptr;2097 if (C && !C->IsClassExtension())2098 if ((PrimaryClass = C->getClassInterface()))2099 // Report unimplemented properties in the category as well.2100 if (ObjCImplDecl *IMP = PrimaryClass->getImplementation()) {2101 // When reporting on missing setter/getters, do not report when2102 // setter/getter is implemented in category's primary class2103 // implementation.2104 InsMap.insert_range(IMP->methods());2105 }2106 2107 for (ObjCContainerDecl::PropertyMap::iterator2108 P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {2109 ObjCPropertyDecl *Prop = P->second;2110 // Is there a matching property synthesize/dynamic?2111 if (Prop->isInvalidDecl() ||2112 Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||2113 PropImplMap.count(Prop) ||2114 Prop->getAvailability() == AR_Unavailable)2115 continue;2116 2117 // Diagnose unimplemented getters and setters.2118 DiagnoseUnimplementedAccessor(SemaRef, PrimaryClass, Prop->getGetterName(),2119 IMPDecl, CDecl, C, Prop, InsMap);2120 if (!Prop->isReadOnly())2121 DiagnoseUnimplementedAccessor(SemaRef, PrimaryClass,2122 Prop->getSetterName(), IMPDecl, CDecl, C,2123 Prop, InsMap);2124 }2125}2126 2127void SemaObjC::diagnoseNullResettableSynthesizedSetters(2128 const ObjCImplDecl *impDecl) {2129 for (const auto *propertyImpl : impDecl->property_impls()) {2130 const auto *property = propertyImpl->getPropertyDecl();2131 // Warn about null_resettable properties with synthesized setters,2132 // because the setter won't properly handle nil.2133 if (propertyImpl->getPropertyImplementation() ==2134 ObjCPropertyImplDecl::Synthesize &&2135 (property->getPropertyAttributes() &2136 ObjCPropertyAttribute::kind_null_resettable) &&2137 property->getGetterMethodDecl() && property->getSetterMethodDecl()) {2138 auto *getterImpl = propertyImpl->getGetterMethodDecl();2139 auto *setterImpl = propertyImpl->getSetterMethodDecl();2140 if ((!getterImpl || getterImpl->isSynthesizedAccessorStub()) &&2141 (!setterImpl || setterImpl->isSynthesizedAccessorStub())) {2142 SourceLocation loc = propertyImpl->getLocation();2143 if (loc.isInvalid())2144 loc = impDecl->getBeginLoc();2145 2146 Diag(loc, diag::warn_null_resettable_setter)2147 << setterImpl->getSelector() << property->getDeclName();2148 }2149 }2150 }2151}2152 2153void SemaObjC::AtomicPropertySetterGetterRules(ObjCImplDecl *IMPDecl,2154 ObjCInterfaceDecl *IDecl) {2155 // Rules apply in non-GC mode only2156 if (getLangOpts().getGC() != LangOptions::NonGC)2157 return;2158 ObjCContainerDecl::PropertyMap PM;2159 for (auto *Prop : IDecl->properties())2160 PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop;2161 for (const auto *Ext : IDecl->known_extensions())2162 for (auto *Prop : Ext->properties())2163 PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop;2164 2165 for (ObjCContainerDecl::PropertyMap::iterator I = PM.begin(), E = PM.end();2166 I != E; ++I) {2167 const ObjCPropertyDecl *Property = I->second;2168 ObjCMethodDecl *GetterMethod = nullptr;2169 ObjCMethodDecl *SetterMethod = nullptr;2170 2171 unsigned Attributes = Property->getPropertyAttributes();2172 unsigned AttributesAsWritten = Property->getPropertyAttributesAsWritten();2173 2174 if (!(AttributesAsWritten & ObjCPropertyAttribute::kind_atomic) &&2175 !(AttributesAsWritten & ObjCPropertyAttribute::kind_nonatomic)) {2176 GetterMethod = Property->isClassProperty() ?2177 IMPDecl->getClassMethod(Property->getGetterName()) :2178 IMPDecl->getInstanceMethod(Property->getGetterName());2179 SetterMethod = Property->isClassProperty() ?2180 IMPDecl->getClassMethod(Property->getSetterName()) :2181 IMPDecl->getInstanceMethod(Property->getSetterName());2182 if (GetterMethod && GetterMethod->isSynthesizedAccessorStub())2183 GetterMethod = nullptr;2184 if (SetterMethod && SetterMethod->isSynthesizedAccessorStub())2185 SetterMethod = nullptr;2186 if (GetterMethod) {2187 Diag(GetterMethod->getLocation(),2188 diag::warn_default_atomic_custom_getter_setter)2189 << Property->getIdentifier() << 0;2190 Diag(Property->getLocation(), diag::note_property_declare);2191 }2192 if (SetterMethod) {2193 Diag(SetterMethod->getLocation(),2194 diag::warn_default_atomic_custom_getter_setter)2195 << Property->getIdentifier() << 1;2196 Diag(Property->getLocation(), diag::note_property_declare);2197 }2198 }2199 2200 // We only care about readwrite atomic property.2201 if ((Attributes & ObjCPropertyAttribute::kind_nonatomic) ||2202 !(Attributes & ObjCPropertyAttribute::kind_readwrite))2203 continue;2204 if (const ObjCPropertyImplDecl *PIDecl = IMPDecl->FindPropertyImplDecl(2205 Property->getIdentifier(), Property->getQueryKind())) {2206 if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)2207 continue;2208 GetterMethod = PIDecl->getGetterMethodDecl();2209 SetterMethod = PIDecl->getSetterMethodDecl();2210 if (GetterMethod && GetterMethod->isSynthesizedAccessorStub())2211 GetterMethod = nullptr;2212 if (SetterMethod && SetterMethod->isSynthesizedAccessorStub())2213 SetterMethod = nullptr;2214 if ((bool)GetterMethod ^ (bool)SetterMethod) {2215 SourceLocation MethodLoc =2216 (GetterMethod ? GetterMethod->getLocation()2217 : SetterMethod->getLocation());2218 Diag(MethodLoc, diag::warn_atomic_property_rule)2219 << Property->getIdentifier() << (GetterMethod != nullptr)2220 << (SetterMethod != nullptr);2221 // fixit stuff.2222 if (Property->getLParenLoc().isValid() &&2223 !(AttributesAsWritten & ObjCPropertyAttribute::kind_atomic)) {2224 // @property () ... case.2225 SourceLocation AfterLParen =2226 SemaRef.getLocForEndOfToken(Property->getLParenLoc());2227 StringRef NonatomicStr = AttributesAsWritten? "nonatomic, "2228 : "nonatomic";2229 Diag(Property->getLocation(),2230 diag::note_atomic_property_fixup_suggest)2231 << FixItHint::CreateInsertion(AfterLParen, NonatomicStr);2232 } else if (Property->getLParenLoc().isInvalid()) {2233 //@property id etc.2234 SourceLocation startLoc =2235 Property->getTypeSourceInfo()->getTypeLoc().getBeginLoc();2236 Diag(Property->getLocation(),2237 diag::note_atomic_property_fixup_suggest)2238 << FixItHint::CreateInsertion(startLoc, "(nonatomic) ");2239 } else2240 Diag(MethodLoc, diag::note_atomic_property_fixup_suggest);2241 Diag(Property->getLocation(), diag::note_property_declare);2242 }2243 }2244 }2245}2246 2247void SemaObjC::DiagnoseOwningPropertyGetterSynthesis(2248 const ObjCImplementationDecl *D) {2249 if (getLangOpts().getGC() == LangOptions::GCOnly)2250 return;2251 2252 for (const auto *PID : D->property_impls()) {2253 const ObjCPropertyDecl *PD = PID->getPropertyDecl();2254 if (PD && !PD->hasAttr<NSReturnsNotRetainedAttr>() &&2255 !PD->isClassProperty()) {2256 ObjCMethodDecl *IM = PID->getGetterMethodDecl();2257 if (IM && !IM->isSynthesizedAccessorStub())2258 continue;2259 ObjCMethodDecl *method = PD->getGetterMethodDecl();2260 if (!method)2261 continue;2262 ObjCMethodFamily family = method->getMethodFamily();2263 if (family == OMF_alloc || family == OMF_copy ||2264 family == OMF_mutableCopy || family == OMF_new) {2265 if (getLangOpts().ObjCAutoRefCount)2266 Diag(PD->getLocation(), diag::err_cocoa_naming_owned_rule);2267 else2268 Diag(PD->getLocation(), diag::warn_cocoa_naming_owned_rule);2269 2270 // Look for a getter explicitly declared alongside the property.2271 // If we find one, use its location for the note.2272 SourceLocation noteLoc = PD->getLocation();2273 SourceLocation fixItLoc;2274 for (auto *getterRedecl : method->redecls()) {2275 if (getterRedecl->isImplicit())2276 continue;2277 if (getterRedecl->getDeclContext() != PD->getDeclContext())2278 continue;2279 noteLoc = getterRedecl->getLocation();2280 fixItLoc = getterRedecl->getEndLoc();2281 }2282 2283 Preprocessor &PP = SemaRef.getPreprocessor();2284 TokenValue tokens[] = {2285 tok::kw___attribute, tok::l_paren, tok::l_paren,2286 PP.getIdentifierInfo("objc_method_family"), tok::l_paren,2287 PP.getIdentifierInfo("none"), tok::r_paren,2288 tok::r_paren, tok::r_paren2289 };2290 StringRef spelling = "__attribute__((objc_method_family(none)))";2291 StringRef macroName = PP.getLastMacroWithSpelling(noteLoc, tokens);2292 if (!macroName.empty())2293 spelling = macroName;2294 2295 auto noteDiag = Diag(noteLoc, diag::note_cocoa_naming_declare_family)2296 << method->getDeclName() << spelling;2297 if (fixItLoc.isValid()) {2298 SmallString<64> fixItText(" ");2299 fixItText += spelling;2300 noteDiag << FixItHint::CreateInsertion(fixItLoc, fixItText);2301 }2302 }2303 }2304 }2305}2306 2307void SemaObjC::DiagnoseMissingDesignatedInitOverrides(2308 const ObjCImplementationDecl *ImplD, const ObjCInterfaceDecl *IFD) {2309 assert(IFD->hasDesignatedInitializers());2310 const ObjCInterfaceDecl *SuperD = IFD->getSuperClass();2311 if (!SuperD)2312 return;2313 2314 SelectorSet InitSelSet;2315 for (const auto *I : ImplD->instance_methods())2316 if (I->getMethodFamily() == OMF_init)2317 InitSelSet.insert(I->getSelector());2318 2319 SmallVector<const ObjCMethodDecl *, 8> DesignatedInits;2320 SuperD->getDesignatedInitializers(DesignatedInits);2321 for (SmallVector<const ObjCMethodDecl *, 8>::iterator2322 I = DesignatedInits.begin(), E = DesignatedInits.end(); I != E; ++I) {2323 const ObjCMethodDecl *MD = *I;2324 if (!InitSelSet.count(MD->getSelector())) {2325 // Don't emit a diagnostic if the overriding method in the subclass is2326 // marked as unavailable.2327 bool Ignore = false;2328 if (auto *IMD = IFD->getInstanceMethod(MD->getSelector())) {2329 Ignore = IMD->isUnavailable();2330 } else {2331 // Check the methods declared in the class extensions too.2332 for (auto *Ext : IFD->visible_extensions())2333 if (auto *IMD = Ext->getInstanceMethod(MD->getSelector())) {2334 Ignore = IMD->isUnavailable();2335 break;2336 }2337 }2338 if (!Ignore) {2339 Diag(ImplD->getLocation(),2340 diag::warn_objc_implementation_missing_designated_init_override)2341 << MD->getSelector();2342 Diag(MD->getLocation(), diag::note_objc_designated_init_marked_here);2343 }2344 }2345 }2346}2347 2348/// AddPropertyAttrs - Propagates attributes from a property to the2349/// implicitly-declared getter or setter for that property.2350static void AddPropertyAttrs(Sema &S, ObjCMethodDecl *PropertyMethod,2351 ObjCPropertyDecl *Property) {2352 // Should we just clone all attributes over?2353 for (const auto *A : Property->attrs()) {2354 if (isa<DeprecatedAttr>(A) ||2355 isa<UnavailableAttr>(A) ||2356 isa<AvailabilityAttr>(A))2357 PropertyMethod->addAttr(A->clone(S.Context));2358 }2359}2360 2361/// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods2362/// have the property type and issue diagnostics if they don't.2363/// Also synthesize a getter/setter method if none exist (and update the2364/// appropriate lookup tables.2365void SemaObjC::ProcessPropertyDecl(ObjCPropertyDecl *property) {2366 ASTContext &Context = getASTContext();2367 ObjCMethodDecl *GetterMethod, *SetterMethod;2368 ObjCContainerDecl *CD = cast<ObjCContainerDecl>(property->getDeclContext());2369 if (CD->isInvalidDecl())2370 return;2371 2372 bool IsClassProperty = property->isClassProperty();2373 GetterMethod = IsClassProperty ?2374 CD->getClassMethod(property->getGetterName()) :2375 CD->getInstanceMethod(property->getGetterName());2376 2377 // if setter or getter is not found in class extension, it might be2378 // in the primary class.2379 if (!GetterMethod)2380 if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD))2381 if (CatDecl->IsClassExtension())2382 GetterMethod = IsClassProperty ? CatDecl->getClassInterface()->2383 getClassMethod(property->getGetterName()) :2384 CatDecl->getClassInterface()->2385 getInstanceMethod(property->getGetterName());2386 2387 SetterMethod = IsClassProperty ?2388 CD->getClassMethod(property->getSetterName()) :2389 CD->getInstanceMethod(property->getSetterName());2390 if (!SetterMethod)2391 if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD))2392 if (CatDecl->IsClassExtension())2393 SetterMethod = IsClassProperty ? CatDecl->getClassInterface()->2394 getClassMethod(property->getSetterName()) :2395 CatDecl->getClassInterface()->2396 getInstanceMethod(property->getSetterName());2397 DiagnosePropertyAccessorMismatch(property, GetterMethod,2398 property->getLocation());2399 2400 // synthesizing accessors must not result in a direct method that is not2401 // monomorphic2402 if (!GetterMethod) {2403 if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD)) {2404 auto *ExistingGetter = CatDecl->getClassInterface()->lookupMethod(2405 property->getGetterName(), !IsClassProperty, true, false, CatDecl);2406 if (ExistingGetter) {2407 if (ExistingGetter->isDirectMethod() || property->isDirectProperty()) {2408 Diag(property->getLocation(), diag::err_objc_direct_duplicate_decl)2409 << property->isDirectProperty() << 1 /* property */2410 << ExistingGetter->isDirectMethod()2411 << ExistingGetter->getDeclName();2412 Diag(ExistingGetter->getLocation(), diag::note_previous_declaration);2413 }2414 }2415 }2416 }2417 2418 if (!property->isReadOnly() && !SetterMethod) {2419 if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD)) {2420 auto *ExistingSetter = CatDecl->getClassInterface()->lookupMethod(2421 property->getSetterName(), !IsClassProperty, true, false, CatDecl);2422 if (ExistingSetter) {2423 if (ExistingSetter->isDirectMethod() || property->isDirectProperty()) {2424 Diag(property->getLocation(), diag::err_objc_direct_duplicate_decl)2425 << property->isDirectProperty() << 1 /* property */2426 << ExistingSetter->isDirectMethod()2427 << ExistingSetter->getDeclName();2428 Diag(ExistingSetter->getLocation(), diag::note_previous_declaration);2429 }2430 }2431 }2432 }2433 2434 if (!property->isReadOnly() && SetterMethod) {2435 if (Context.getCanonicalType(SetterMethod->getReturnType()) !=2436 Context.VoidTy)2437 Diag(SetterMethod->getLocation(), diag::err_setter_type_void);2438 if (SetterMethod->param_size() != 1 ||2439 !Context.hasSameUnqualifiedType(2440 (*SetterMethod->param_begin())->getType().getNonReferenceType(),2441 property->getType().getNonReferenceType())) {2442 Diag(property->getLocation(),2443 diag::warn_accessor_property_type_mismatch)2444 << property->getDeclName()2445 << SetterMethod->getSelector();2446 Diag(SetterMethod->getLocation(), diag::note_declared_at);2447 }2448 }2449 2450 // Synthesize getter/setter methods if none exist.2451 // Find the default getter and if one not found, add one.2452 // FIXME: The synthesized property we set here is misleading. We almost always2453 // synthesize these methods unless the user explicitly provided prototypes2454 // (which is odd, but allowed). Sema should be typechecking that the2455 // declarations jive in that situation (which it is not currently).2456 if (!GetterMethod) {2457 // No instance/class method of same name as property getter name was found.2458 // Declare a getter method and add it to the list of methods2459 // for this class.2460 SourceLocation Loc = property->getLocation();2461 2462 // The getter returns the declared property type with all qualifiers2463 // removed.2464 QualType resultTy = property->getType().getAtomicUnqualifiedType();2465 2466 // If the property is null_resettable, the getter returns nonnull.2467 if (property->getPropertyAttributes() &2468 ObjCPropertyAttribute::kind_null_resettable) {2469 QualType modifiedTy = resultTy;2470 if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)) {2471 if (*nullability == NullabilityKind::Unspecified)2472 resultTy = Context.getAttributedType(NullabilityKind::NonNull,2473 modifiedTy, modifiedTy);2474 }2475 }2476 2477 GetterMethod = ObjCMethodDecl::Create(2478 Context, Loc, Loc, property->getGetterName(), resultTy, nullptr, CD,2479 !IsClassProperty, /*isVariadic=*/false,2480 /*isPropertyAccessor=*/true, /*isSynthesizedAccessorStub=*/false,2481 /*isImplicitlyDeclared=*/true, /*isDefined=*/false,2482 (property->getPropertyImplementation() == ObjCPropertyDecl::Optional)2483 ? ObjCImplementationControl::Optional2484 : ObjCImplementationControl::Required);2485 CD->addDecl(GetterMethod);2486 2487 AddPropertyAttrs(SemaRef, GetterMethod, property);2488 2489 if (property->isDirectProperty())2490 GetterMethod->addAttr(ObjCDirectAttr::CreateImplicit(Context, Loc));2491 2492 if (property->hasAttr<NSReturnsNotRetainedAttr>())2493 GetterMethod->addAttr(NSReturnsNotRetainedAttr::CreateImplicit(Context,2494 Loc));2495 2496 if (property->hasAttr<ObjCReturnsInnerPointerAttr>())2497 GetterMethod->addAttr(2498 ObjCReturnsInnerPointerAttr::CreateImplicit(Context, Loc));2499 2500 if (const SectionAttr *SA = property->getAttr<SectionAttr>())2501 GetterMethod->addAttr(SectionAttr::CreateImplicit(2502 Context, SA->getName(), Loc, SectionAttr::GNU_section));2503 2504 SemaRef.ProcessAPINotes(GetterMethod);2505 2506 if (getLangOpts().ObjCAutoRefCount)2507 CheckARCMethodDecl(GetterMethod);2508 } else2509 // A user declared getter will be synthesize when @synthesize of2510 // the property with the same name is seen in the @implementation2511 GetterMethod->setPropertyAccessor(true);2512 2513 GetterMethod->createImplicitParams(Context,2514 GetterMethod->getClassInterface());2515 property->setGetterMethodDecl(GetterMethod);2516 2517 // Skip setter if property is read-only.2518 if (!property->isReadOnly()) {2519 // Find the default setter and if one not found, add one.2520 if (!SetterMethod) {2521 // No instance/class method of same name as property setter name was2522 // found.2523 // Declare a setter method and add it to the list of methods2524 // for this class.2525 SourceLocation Loc = property->getLocation();2526 2527 SetterMethod = ObjCMethodDecl::Create(2528 Context, Loc, Loc, property->getSetterName(), Context.VoidTy, nullptr,2529 CD, !IsClassProperty,2530 /*isVariadic=*/false,2531 /*isPropertyAccessor=*/true,2532 /*isSynthesizedAccessorStub=*/false,2533 /*isImplicitlyDeclared=*/true,2534 /*isDefined=*/false,2535 (property->getPropertyImplementation() == ObjCPropertyDecl::Optional)2536 ? ObjCImplementationControl::Optional2537 : ObjCImplementationControl::Required);2538 2539 // Remove all qualifiers from the setter's parameter type.2540 QualType paramTy =2541 property->getType().getUnqualifiedType().getAtomicUnqualifiedType();2542 2543 // If the property is null_resettable, the setter accepts a2544 // nullable value.2545 if (property->getPropertyAttributes() &2546 ObjCPropertyAttribute::kind_null_resettable) {2547 QualType modifiedTy = paramTy;2548 if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)){2549 if (*nullability == NullabilityKind::Unspecified)2550 paramTy = Context.getAttributedType(NullabilityKind::Nullable,2551 modifiedTy, modifiedTy);2552 }2553 }2554 2555 // Invent the arguments for the setter. We don't bother making a2556 // nice name for the argument.2557 ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod,2558 Loc, Loc,2559 property->getIdentifier(),2560 paramTy,2561 /*TInfo=*/nullptr,2562 SC_None,2563 nullptr);2564 SetterMethod->setMethodParams(Context, Argument, {});2565 2566 AddPropertyAttrs(SemaRef, SetterMethod, property);2567 2568 if (property->isDirectProperty())2569 SetterMethod->addAttr(ObjCDirectAttr::CreateImplicit(Context, Loc));2570 2571 CD->addDecl(SetterMethod);2572 if (const SectionAttr *SA = property->getAttr<SectionAttr>())2573 SetterMethod->addAttr(SectionAttr::CreateImplicit(2574 Context, SA->getName(), Loc, SectionAttr::GNU_section));2575 2576 SemaRef.ProcessAPINotes(SetterMethod);2577 2578 // It's possible for the user to have set a very odd custom2579 // setter selector that causes it to have a method family.2580 if (getLangOpts().ObjCAutoRefCount)2581 CheckARCMethodDecl(SetterMethod);2582 } else2583 // A user declared setter will be synthesize when @synthesize of2584 // the property with the same name is seen in the @implementation2585 SetterMethod->setPropertyAccessor(true);2586 2587 SetterMethod->createImplicitParams(Context,2588 SetterMethod->getClassInterface());2589 property->setSetterMethodDecl(SetterMethod);2590 }2591 // Add any synthesized methods to the global pool. This allows us to2592 // handle the following, which is supported by GCC (and part of the design).2593 //2594 // @interface Foo2595 // @property double bar;2596 // @end2597 //2598 // void thisIsUnfortunate() {2599 // id foo;2600 // double bar = [foo bar];2601 // }2602 //2603 if (!IsClassProperty) {2604 if (GetterMethod)2605 AddInstanceMethodToGlobalPool(GetterMethod);2606 if (SetterMethod)2607 AddInstanceMethodToGlobalPool(SetterMethod);2608 } else {2609 if (GetterMethod)2610 AddFactoryMethodToGlobalPool(GetterMethod);2611 if (SetterMethod)2612 AddFactoryMethodToGlobalPool(SetterMethod);2613 }2614 2615 ObjCInterfaceDecl *CurrentClass = dyn_cast<ObjCInterfaceDecl>(CD);2616 if (!CurrentClass) {2617 if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(CD))2618 CurrentClass = Cat->getClassInterface();2619 else if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(CD))2620 CurrentClass = Impl->getClassInterface();2621 }2622 if (GetterMethod)2623 CheckObjCMethodOverrides(GetterMethod, CurrentClass, SemaObjC::RTC_Unknown);2624 if (SetterMethod)2625 CheckObjCMethodOverrides(SetterMethod, CurrentClass, SemaObjC::RTC_Unknown);2626}2627 2628void SemaObjC::CheckObjCPropertyAttributes(Decl *PDecl, SourceLocation Loc,2629 unsigned &Attributes,2630 bool propertyInPrimaryClass) {2631 // FIXME: Improve the reported location.2632 if (!PDecl || PDecl->isInvalidDecl())2633 return;2634 2635 if ((Attributes & ObjCPropertyAttribute::kind_readonly) &&2636 (Attributes & ObjCPropertyAttribute::kind_readwrite))2637 Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)2638 << "readonly" << "readwrite";2639 2640 ObjCPropertyDecl *PropertyDecl = cast<ObjCPropertyDecl>(PDecl);2641 QualType PropertyTy = PropertyDecl->getType();2642 2643 // Check for copy or retain on non-object types.2644 if ((Attributes &2645 (ObjCPropertyAttribute::kind_weak | ObjCPropertyAttribute::kind_copy |2646 ObjCPropertyAttribute::kind_retain |2647 ObjCPropertyAttribute::kind_strong)) &&2648 !PropertyTy->isObjCRetainableType() &&2649 !PropertyDecl->hasAttr<ObjCNSObjectAttr>()) {2650 Diag(Loc, diag::err_objc_property_requires_object)2651 << (Attributes & ObjCPropertyAttribute::kind_weak2652 ? "weak"2653 : Attributes & ObjCPropertyAttribute::kind_copy2654 ? "copy"2655 : "retain (or strong)");2656 Attributes &=2657 ~(ObjCPropertyAttribute::kind_weak | ObjCPropertyAttribute::kind_copy |2658 ObjCPropertyAttribute::kind_retain |2659 ObjCPropertyAttribute::kind_strong);2660 PropertyDecl->setInvalidDecl();2661 }2662 2663 // Check for assign on object types.2664 if ((Attributes & ObjCPropertyAttribute::kind_assign) &&2665 !(Attributes & ObjCPropertyAttribute::kind_unsafe_unretained) &&2666 PropertyTy->isObjCRetainableType() &&2667 !PropertyTy->isObjCARCImplicitlyUnretainedType()) {2668 Diag(Loc, diag::warn_objc_property_assign_on_object);2669 }2670 2671 // Check for more than one of { assign, copy, retain }.2672 if (Attributes & ObjCPropertyAttribute::kind_assign) {2673 if (Attributes & ObjCPropertyAttribute::kind_copy) {2674 Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)2675 << "assign" << "copy";2676 Attributes &= ~ObjCPropertyAttribute::kind_copy;2677 }2678 if (Attributes & ObjCPropertyAttribute::kind_retain) {2679 Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)2680 << "assign" << "retain";2681 Attributes &= ~ObjCPropertyAttribute::kind_retain;2682 }2683 if (Attributes & ObjCPropertyAttribute::kind_strong) {2684 Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)2685 << "assign" << "strong";2686 Attributes &= ~ObjCPropertyAttribute::kind_strong;2687 }2688 if (getLangOpts().ObjCAutoRefCount &&2689 (Attributes & ObjCPropertyAttribute::kind_weak)) {2690 Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)2691 << "assign" << "weak";2692 Attributes &= ~ObjCPropertyAttribute::kind_weak;2693 }2694 if (PropertyDecl->hasAttr<IBOutletCollectionAttr>())2695 Diag(Loc, diag::warn_iboutletcollection_property_assign);2696 } else if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained) {2697 if (Attributes & ObjCPropertyAttribute::kind_copy) {2698 Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)2699 << "unsafe_unretained" << "copy";2700 Attributes &= ~ObjCPropertyAttribute::kind_copy;2701 }2702 if (Attributes & ObjCPropertyAttribute::kind_retain) {2703 Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)2704 << "unsafe_unretained" << "retain";2705 Attributes &= ~ObjCPropertyAttribute::kind_retain;2706 }2707 if (Attributes & ObjCPropertyAttribute::kind_strong) {2708 Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)2709 << "unsafe_unretained" << "strong";2710 Attributes &= ~ObjCPropertyAttribute::kind_strong;2711 }2712 if (getLangOpts().ObjCAutoRefCount &&2713 (Attributes & ObjCPropertyAttribute::kind_weak)) {2714 Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)2715 << "unsafe_unretained" << "weak";2716 Attributes &= ~ObjCPropertyAttribute::kind_weak;2717 }2718 } else if (Attributes & ObjCPropertyAttribute::kind_copy) {2719 if (Attributes & ObjCPropertyAttribute::kind_retain) {2720 Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)2721 << "copy" << "retain";2722 Attributes &= ~ObjCPropertyAttribute::kind_retain;2723 }2724 if (Attributes & ObjCPropertyAttribute::kind_strong) {2725 Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)2726 << "copy" << "strong";2727 Attributes &= ~ObjCPropertyAttribute::kind_strong;2728 }2729 if (Attributes & ObjCPropertyAttribute::kind_weak) {2730 Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)2731 << "copy" << "weak";2732 Attributes &= ~ObjCPropertyAttribute::kind_weak;2733 }2734 } else if ((Attributes & ObjCPropertyAttribute::kind_retain) &&2735 (Attributes & ObjCPropertyAttribute::kind_weak)) {2736 Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "retain"2737 << "weak";2738 Attributes &= ~ObjCPropertyAttribute::kind_retain;2739 } else if ((Attributes & ObjCPropertyAttribute::kind_strong) &&2740 (Attributes & ObjCPropertyAttribute::kind_weak)) {2741 Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "strong"2742 << "weak";2743 Attributes &= ~ObjCPropertyAttribute::kind_weak;2744 }2745 2746 if (Attributes & ObjCPropertyAttribute::kind_weak) {2747 // 'weak' and 'nonnull' are mutually exclusive.2748 if (auto nullability = PropertyTy->getNullability()) {2749 if (*nullability == NullabilityKind::NonNull)2750 Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)2751 << "nonnull" << "weak";2752 }2753 }2754 2755 if ((Attributes & ObjCPropertyAttribute::kind_atomic) &&2756 (Attributes & ObjCPropertyAttribute::kind_nonatomic)) {2757 Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "atomic"2758 << "nonatomic";2759 Attributes &= ~ObjCPropertyAttribute::kind_atomic;2760 }2761 2762 // Warn if user supplied no assignment attribute, property is2763 // readwrite, and this is an object type.2764 if (!getOwnershipRule(Attributes) && PropertyTy->isObjCRetainableType()) {2765 if (Attributes & ObjCPropertyAttribute::kind_readonly) {2766 // do nothing2767 } else if (getLangOpts().ObjCAutoRefCount) {2768 // With arc, @property definitions should default to strong when2769 // not specified.2770 PropertyDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_strong);2771 } else if (PropertyTy->isObjCObjectPointerType()) {2772 bool isAnyClassTy = (PropertyTy->isObjCClassType() ||2773 PropertyTy->isObjCQualifiedClassType());2774 // In non-gc, non-arc mode, 'Class' is treated as a 'void *' no need to2775 // issue any warning.2776 if (isAnyClassTy && getLangOpts().getGC() == LangOptions::NonGC)2777 ;2778 else if (propertyInPrimaryClass) {2779 // Don't issue warning on property with no life time in class2780 // extension as it is inherited from property in primary class.2781 // Skip this warning in gc-only mode.2782 if (getLangOpts().getGC() != LangOptions::GCOnly)2783 Diag(Loc, diag::warn_objc_property_no_assignment_attribute);2784 2785 // If non-gc code warn that this is likely inappropriate.2786 if (getLangOpts().getGC() == LangOptions::NonGC)2787 Diag(Loc, diag::warn_objc_property_default_assign_on_object);2788 }2789 }2790 2791 // FIXME: Implement warning dependent on NSCopying being2792 // implemented.2793 }2794 2795 if (!(Attributes & ObjCPropertyAttribute::kind_copy) &&2796 !(Attributes & ObjCPropertyAttribute::kind_readonly) &&2797 getLangOpts().getGC() == LangOptions::GCOnly &&2798 PropertyTy->isBlockPointerType())2799 Diag(Loc, diag::warn_objc_property_copy_missing_on_block);2800 else if ((Attributes & ObjCPropertyAttribute::kind_retain) &&2801 !(Attributes & ObjCPropertyAttribute::kind_readonly) &&2802 !(Attributes & ObjCPropertyAttribute::kind_strong) &&2803 PropertyTy->isBlockPointerType())2804 Diag(Loc, diag::warn_objc_property_retain_of_block);2805 2806 if ((Attributes & ObjCPropertyAttribute::kind_readonly) &&2807 (Attributes & ObjCPropertyAttribute::kind_setter))2808 Diag(Loc, diag::warn_objc_readonly_property_has_setter);2809}2810