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