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