1f4a2713aSLionel Sambuc //===--- SemaObjCProperty.cpp - Semantic Analysis for ObjC @property ------===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc // The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // This file implements semantic analysis for Objective C @property and
11f4a2713aSLionel Sambuc // @synthesize declarations.
12f4a2713aSLionel Sambuc //
13f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
14f4a2713aSLionel Sambuc
15f4a2713aSLionel Sambuc #include "clang/Sema/SemaInternal.h"
16f4a2713aSLionel Sambuc #include "clang/AST/ASTMutationListener.h"
17f4a2713aSLionel Sambuc #include "clang/AST/DeclObjC.h"
18f4a2713aSLionel Sambuc #include "clang/AST/ExprCXX.h"
19f4a2713aSLionel Sambuc #include "clang/AST/ExprObjC.h"
20f4a2713aSLionel Sambuc #include "clang/Basic/SourceManager.h"
21f4a2713aSLionel Sambuc #include "clang/Lex/Lexer.h"
22f4a2713aSLionel Sambuc #include "clang/Sema/Initialization.h"
23f4a2713aSLionel Sambuc #include "llvm/ADT/DenseSet.h"
24f4a2713aSLionel Sambuc #include "llvm/ADT/SmallString.h"
25f4a2713aSLionel Sambuc
26f4a2713aSLionel Sambuc using namespace clang;
27f4a2713aSLionel Sambuc
28f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
29f4a2713aSLionel Sambuc // Grammar actions.
30f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
31f4a2713aSLionel Sambuc
32f4a2713aSLionel Sambuc /// getImpliedARCOwnership - Given a set of property attributes and a
33f4a2713aSLionel Sambuc /// type, infer an expected lifetime. The type's ownership qualification
34f4a2713aSLionel Sambuc /// is not considered.
35f4a2713aSLionel Sambuc ///
36f4a2713aSLionel Sambuc /// Returns OCL_None if the attributes as stated do not imply an ownership.
37f4a2713aSLionel Sambuc /// Never returns OCL_Autoreleasing.
getImpliedARCOwnership(ObjCPropertyDecl::PropertyAttributeKind attrs,QualType type)38f4a2713aSLionel Sambuc static Qualifiers::ObjCLifetime getImpliedARCOwnership(
39f4a2713aSLionel Sambuc ObjCPropertyDecl::PropertyAttributeKind attrs,
40f4a2713aSLionel Sambuc QualType type) {
41f4a2713aSLionel Sambuc // retain, strong, copy, weak, and unsafe_unretained are only legal
42f4a2713aSLionel Sambuc // on properties of retainable pointer type.
43f4a2713aSLionel Sambuc if (attrs & (ObjCPropertyDecl::OBJC_PR_retain |
44f4a2713aSLionel Sambuc ObjCPropertyDecl::OBJC_PR_strong |
45f4a2713aSLionel Sambuc ObjCPropertyDecl::OBJC_PR_copy)) {
46f4a2713aSLionel Sambuc return Qualifiers::OCL_Strong;
47f4a2713aSLionel Sambuc } else if (attrs & ObjCPropertyDecl::OBJC_PR_weak) {
48f4a2713aSLionel Sambuc return Qualifiers::OCL_Weak;
49f4a2713aSLionel Sambuc } else if (attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained) {
50f4a2713aSLionel Sambuc return Qualifiers::OCL_ExplicitNone;
51f4a2713aSLionel Sambuc }
52f4a2713aSLionel Sambuc
53f4a2713aSLionel Sambuc // assign can appear on other types, so we have to check the
54f4a2713aSLionel Sambuc // property type.
55f4a2713aSLionel Sambuc if (attrs & ObjCPropertyDecl::OBJC_PR_assign &&
56f4a2713aSLionel Sambuc type->isObjCRetainableType()) {
57f4a2713aSLionel Sambuc return Qualifiers::OCL_ExplicitNone;
58f4a2713aSLionel Sambuc }
59f4a2713aSLionel Sambuc
60f4a2713aSLionel Sambuc return Qualifiers::OCL_None;
61f4a2713aSLionel Sambuc }
62f4a2713aSLionel Sambuc
63f4a2713aSLionel Sambuc /// Check the internal consistency of a property declaration.
checkARCPropertyDecl(Sema & S,ObjCPropertyDecl * property)64f4a2713aSLionel Sambuc static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) {
65f4a2713aSLionel Sambuc if (property->isInvalidDecl()) return;
66f4a2713aSLionel Sambuc
67f4a2713aSLionel Sambuc ObjCPropertyDecl::PropertyAttributeKind propertyKind
68f4a2713aSLionel Sambuc = property->getPropertyAttributes();
69f4a2713aSLionel Sambuc Qualifiers::ObjCLifetime propertyLifetime
70f4a2713aSLionel Sambuc = property->getType().getObjCLifetime();
71f4a2713aSLionel Sambuc
72f4a2713aSLionel Sambuc // Nothing to do if we don't have a lifetime.
73f4a2713aSLionel Sambuc if (propertyLifetime == Qualifiers::OCL_None) return;
74f4a2713aSLionel Sambuc
75f4a2713aSLionel Sambuc Qualifiers::ObjCLifetime expectedLifetime
76f4a2713aSLionel Sambuc = getImpliedARCOwnership(propertyKind, property->getType());
77f4a2713aSLionel Sambuc if (!expectedLifetime) {
78f4a2713aSLionel Sambuc // We have a lifetime qualifier but no dominating property
79f4a2713aSLionel Sambuc // attribute. That's okay, but restore reasonable invariants by
80f4a2713aSLionel Sambuc // setting the property attribute according to the lifetime
81f4a2713aSLionel Sambuc // qualifier.
82f4a2713aSLionel Sambuc ObjCPropertyDecl::PropertyAttributeKind attr;
83f4a2713aSLionel Sambuc if (propertyLifetime == Qualifiers::OCL_Strong) {
84f4a2713aSLionel Sambuc attr = ObjCPropertyDecl::OBJC_PR_strong;
85f4a2713aSLionel Sambuc } else if (propertyLifetime == Qualifiers::OCL_Weak) {
86f4a2713aSLionel Sambuc attr = ObjCPropertyDecl::OBJC_PR_weak;
87f4a2713aSLionel Sambuc } else {
88f4a2713aSLionel Sambuc assert(propertyLifetime == Qualifiers::OCL_ExplicitNone);
89f4a2713aSLionel Sambuc attr = ObjCPropertyDecl::OBJC_PR_unsafe_unretained;
90f4a2713aSLionel Sambuc }
91f4a2713aSLionel Sambuc property->setPropertyAttributes(attr);
92f4a2713aSLionel Sambuc return;
93f4a2713aSLionel Sambuc }
94f4a2713aSLionel Sambuc
95f4a2713aSLionel Sambuc if (propertyLifetime == expectedLifetime) return;
96f4a2713aSLionel Sambuc
97f4a2713aSLionel Sambuc property->setInvalidDecl();
98f4a2713aSLionel Sambuc S.Diag(property->getLocation(),
99f4a2713aSLionel Sambuc diag::err_arc_inconsistent_property_ownership)
100f4a2713aSLionel Sambuc << property->getDeclName()
101f4a2713aSLionel Sambuc << expectedLifetime
102f4a2713aSLionel Sambuc << propertyLifetime;
103f4a2713aSLionel Sambuc }
104f4a2713aSLionel Sambuc
deduceWeakPropertyFromType(Sema & S,QualType T)105f4a2713aSLionel Sambuc static unsigned deduceWeakPropertyFromType(Sema &S, QualType T) {
106f4a2713aSLionel Sambuc if ((S.getLangOpts().getGC() != LangOptions::NonGC &&
107f4a2713aSLionel Sambuc T.isObjCGCWeak()) ||
108f4a2713aSLionel Sambuc (S.getLangOpts().ObjCAutoRefCount &&
109f4a2713aSLionel Sambuc T.getObjCLifetime() == Qualifiers::OCL_Weak))
110f4a2713aSLionel Sambuc return ObjCDeclSpec::DQ_PR_weak;
111f4a2713aSLionel Sambuc return 0;
112f4a2713aSLionel Sambuc }
113f4a2713aSLionel Sambuc
114f4a2713aSLionel Sambuc /// \brief Check this Objective-C property against a property declared in the
115f4a2713aSLionel Sambuc /// given protocol.
116f4a2713aSLionel Sambuc static void
CheckPropertyAgainstProtocol(Sema & S,ObjCPropertyDecl * Prop,ObjCProtocolDecl * Proto,llvm::SmallPtrSetImpl<ObjCProtocolDecl * > & Known)117f4a2713aSLionel Sambuc CheckPropertyAgainstProtocol(Sema &S, ObjCPropertyDecl *Prop,
118f4a2713aSLionel Sambuc ObjCProtocolDecl *Proto,
119*0a6a1f1dSLionel Sambuc llvm::SmallPtrSetImpl<ObjCProtocolDecl *> &Known) {
120f4a2713aSLionel Sambuc // Have we seen this protocol before?
121*0a6a1f1dSLionel Sambuc if (!Known.insert(Proto).second)
122f4a2713aSLionel Sambuc return;
123f4a2713aSLionel Sambuc
124f4a2713aSLionel Sambuc // Look for a property with the same name.
125f4a2713aSLionel Sambuc DeclContext::lookup_result R = Proto->lookup(Prop->getDeclName());
126f4a2713aSLionel Sambuc for (unsigned I = 0, N = R.size(); I != N; ++I) {
127f4a2713aSLionel Sambuc if (ObjCPropertyDecl *ProtoProp = dyn_cast<ObjCPropertyDecl>(R[I])) {
128f4a2713aSLionel Sambuc S.DiagnosePropertyMismatch(Prop, ProtoProp, Proto->getIdentifier(), true);
129f4a2713aSLionel Sambuc return;
130f4a2713aSLionel Sambuc }
131f4a2713aSLionel Sambuc }
132f4a2713aSLionel Sambuc
133f4a2713aSLionel Sambuc // Check this property against any protocols we inherit.
134*0a6a1f1dSLionel Sambuc for (auto *P : Proto->protocols())
135*0a6a1f1dSLionel Sambuc CheckPropertyAgainstProtocol(S, Prop, P, Known);
136f4a2713aSLionel Sambuc }
137f4a2713aSLionel Sambuc
ActOnProperty(Scope * S,SourceLocation AtLoc,SourceLocation LParenLoc,FieldDeclarator & FD,ObjCDeclSpec & ODS,Selector GetterSel,Selector SetterSel,bool * isOverridingProperty,tok::ObjCKeywordKind MethodImplKind,DeclContext * lexicalDC)138f4a2713aSLionel Sambuc Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
139f4a2713aSLionel Sambuc SourceLocation LParenLoc,
140f4a2713aSLionel Sambuc FieldDeclarator &FD,
141f4a2713aSLionel Sambuc ObjCDeclSpec &ODS,
142f4a2713aSLionel Sambuc Selector GetterSel,
143f4a2713aSLionel Sambuc Selector SetterSel,
144f4a2713aSLionel Sambuc bool *isOverridingProperty,
145f4a2713aSLionel Sambuc tok::ObjCKeywordKind MethodImplKind,
146f4a2713aSLionel Sambuc DeclContext *lexicalDC) {
147f4a2713aSLionel Sambuc unsigned Attributes = ODS.getPropertyAttributes();
148f4a2713aSLionel Sambuc TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S);
149f4a2713aSLionel Sambuc QualType T = TSI->getType();
150f4a2713aSLionel Sambuc Attributes |= deduceWeakPropertyFromType(*this, T);
151f4a2713aSLionel Sambuc
152f4a2713aSLionel Sambuc bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) ||
153f4a2713aSLionel Sambuc // default is readwrite!
154f4a2713aSLionel Sambuc !(Attributes & ObjCDeclSpec::DQ_PR_readonly));
155f4a2713aSLionel Sambuc // property is defaulted to 'assign' if it is readwrite and is
156f4a2713aSLionel Sambuc // not retain or copy
157f4a2713aSLionel Sambuc bool isAssign = ((Attributes & ObjCDeclSpec::DQ_PR_assign) ||
158f4a2713aSLionel Sambuc (isReadWrite &&
159f4a2713aSLionel Sambuc !(Attributes & ObjCDeclSpec::DQ_PR_retain) &&
160f4a2713aSLionel Sambuc !(Attributes & ObjCDeclSpec::DQ_PR_strong) &&
161f4a2713aSLionel Sambuc !(Attributes & ObjCDeclSpec::DQ_PR_copy) &&
162f4a2713aSLionel Sambuc !(Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) &&
163f4a2713aSLionel Sambuc !(Attributes & ObjCDeclSpec::DQ_PR_weak)));
164f4a2713aSLionel Sambuc
165f4a2713aSLionel Sambuc // Proceed with constructing the ObjCPropertyDecls.
166f4a2713aSLionel Sambuc ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(CurContext);
167*0a6a1f1dSLionel Sambuc ObjCPropertyDecl *Res = nullptr;
168f4a2713aSLionel Sambuc if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
169f4a2713aSLionel Sambuc if (CDecl->IsClassExtension()) {
170f4a2713aSLionel Sambuc Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc,
171f4a2713aSLionel Sambuc FD, GetterSel, SetterSel,
172f4a2713aSLionel Sambuc isAssign, isReadWrite,
173f4a2713aSLionel Sambuc Attributes,
174f4a2713aSLionel Sambuc ODS.getPropertyAttributes(),
175f4a2713aSLionel Sambuc isOverridingProperty, TSI,
176f4a2713aSLionel Sambuc MethodImplKind);
177f4a2713aSLionel Sambuc if (!Res)
178*0a6a1f1dSLionel Sambuc return nullptr;
179f4a2713aSLionel Sambuc }
180f4a2713aSLionel Sambuc }
181f4a2713aSLionel Sambuc
182f4a2713aSLionel Sambuc if (!Res) {
183f4a2713aSLionel Sambuc Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD,
184f4a2713aSLionel Sambuc GetterSel, SetterSel, isAssign, isReadWrite,
185f4a2713aSLionel Sambuc Attributes, ODS.getPropertyAttributes(),
186f4a2713aSLionel Sambuc TSI, MethodImplKind);
187f4a2713aSLionel Sambuc if (lexicalDC)
188f4a2713aSLionel Sambuc Res->setLexicalDeclContext(lexicalDC);
189f4a2713aSLionel Sambuc }
190f4a2713aSLionel Sambuc
191f4a2713aSLionel Sambuc // Validate the attributes on the @property.
192f4a2713aSLionel Sambuc CheckObjCPropertyAttributes(Res, AtLoc, Attributes,
193f4a2713aSLionel Sambuc (isa<ObjCInterfaceDecl>(ClassDecl) ||
194f4a2713aSLionel Sambuc isa<ObjCProtocolDecl>(ClassDecl)));
195f4a2713aSLionel Sambuc
196f4a2713aSLionel Sambuc if (getLangOpts().ObjCAutoRefCount)
197f4a2713aSLionel Sambuc checkARCPropertyDecl(*this, Res);
198f4a2713aSLionel Sambuc
199f4a2713aSLionel Sambuc llvm::SmallPtrSet<ObjCProtocolDecl *, 16> KnownProtos;
200f4a2713aSLionel Sambuc if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
201f4a2713aSLionel Sambuc // For a class, compare the property against a property in our superclass.
202f4a2713aSLionel Sambuc bool FoundInSuper = false;
203*0a6a1f1dSLionel Sambuc ObjCInterfaceDecl *CurrentInterfaceDecl = IFace;
204*0a6a1f1dSLionel Sambuc while (ObjCInterfaceDecl *Super = CurrentInterfaceDecl->getSuperClass()) {
205f4a2713aSLionel Sambuc DeclContext::lookup_result R = Super->lookup(Res->getDeclName());
206f4a2713aSLionel Sambuc for (unsigned I = 0, N = R.size(); I != N; ++I) {
207f4a2713aSLionel Sambuc if (ObjCPropertyDecl *SuperProp = dyn_cast<ObjCPropertyDecl>(R[I])) {
208f4a2713aSLionel Sambuc DiagnosePropertyMismatch(Res, SuperProp, Super->getIdentifier(), false);
209f4a2713aSLionel Sambuc FoundInSuper = true;
210f4a2713aSLionel Sambuc break;
211f4a2713aSLionel Sambuc }
212f4a2713aSLionel Sambuc }
213*0a6a1f1dSLionel Sambuc if (FoundInSuper)
214*0a6a1f1dSLionel Sambuc break;
215*0a6a1f1dSLionel Sambuc else
216*0a6a1f1dSLionel Sambuc CurrentInterfaceDecl = Super;
217f4a2713aSLionel Sambuc }
218f4a2713aSLionel Sambuc
219f4a2713aSLionel Sambuc if (FoundInSuper) {
220f4a2713aSLionel Sambuc // Also compare the property against a property in our protocols.
221*0a6a1f1dSLionel Sambuc for (auto *P : CurrentInterfaceDecl->protocols()) {
222*0a6a1f1dSLionel Sambuc CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos);
223f4a2713aSLionel Sambuc }
224f4a2713aSLionel Sambuc } else {
225f4a2713aSLionel Sambuc // Slower path: look in all protocols we referenced.
226*0a6a1f1dSLionel Sambuc for (auto *P : IFace->all_referenced_protocols()) {
227*0a6a1f1dSLionel Sambuc CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos);
228f4a2713aSLionel Sambuc }
229f4a2713aSLionel Sambuc }
230f4a2713aSLionel Sambuc } else if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
231*0a6a1f1dSLionel Sambuc for (auto *P : Cat->protocols())
232*0a6a1f1dSLionel Sambuc CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos);
233f4a2713aSLionel Sambuc } else {
234f4a2713aSLionel Sambuc ObjCProtocolDecl *Proto = cast<ObjCProtocolDecl>(ClassDecl);
235*0a6a1f1dSLionel Sambuc for (auto *P : Proto->protocols())
236*0a6a1f1dSLionel Sambuc CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos);
237f4a2713aSLionel Sambuc }
238f4a2713aSLionel Sambuc
239f4a2713aSLionel Sambuc ActOnDocumentableDecl(Res);
240f4a2713aSLionel Sambuc return Res;
241f4a2713aSLionel Sambuc }
242f4a2713aSLionel Sambuc
243f4a2713aSLionel Sambuc static ObjCPropertyDecl::PropertyAttributeKind
makePropertyAttributesAsWritten(unsigned Attributes)244f4a2713aSLionel Sambuc makePropertyAttributesAsWritten(unsigned Attributes) {
245f4a2713aSLionel Sambuc unsigned attributesAsWritten = 0;
246f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
247f4a2713aSLionel Sambuc attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readonly;
248f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_readwrite)
249f4a2713aSLionel Sambuc attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readwrite;
250f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_getter)
251f4a2713aSLionel Sambuc attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_getter;
252f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_setter)
253f4a2713aSLionel Sambuc attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_setter;
254f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_assign)
255f4a2713aSLionel Sambuc attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_assign;
256f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_retain)
257f4a2713aSLionel Sambuc attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_retain;
258f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_strong)
259f4a2713aSLionel Sambuc attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_strong;
260f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_weak)
261f4a2713aSLionel Sambuc attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_weak;
262f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_copy)
263f4a2713aSLionel Sambuc attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_copy;
264f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained)
265f4a2713aSLionel Sambuc attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_unsafe_unretained;
266f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
267f4a2713aSLionel Sambuc attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_nonatomic;
268f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_atomic)
269f4a2713aSLionel Sambuc attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_atomic;
270f4a2713aSLionel Sambuc
271f4a2713aSLionel Sambuc return (ObjCPropertyDecl::PropertyAttributeKind)attributesAsWritten;
272f4a2713aSLionel Sambuc }
273f4a2713aSLionel Sambuc
LocPropertyAttribute(ASTContext & Context,const char * attrName,SourceLocation LParenLoc,SourceLocation & Loc)274f4a2713aSLionel Sambuc static bool LocPropertyAttribute( ASTContext &Context, const char *attrName,
275f4a2713aSLionel Sambuc SourceLocation LParenLoc, SourceLocation &Loc) {
276f4a2713aSLionel Sambuc if (LParenLoc.isMacroID())
277f4a2713aSLionel Sambuc return false;
278f4a2713aSLionel Sambuc
279f4a2713aSLionel Sambuc SourceManager &SM = Context.getSourceManager();
280f4a2713aSLionel Sambuc std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(LParenLoc);
281f4a2713aSLionel Sambuc // Try to load the file buffer.
282f4a2713aSLionel Sambuc bool invalidTemp = false;
283f4a2713aSLionel Sambuc StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
284f4a2713aSLionel Sambuc if (invalidTemp)
285f4a2713aSLionel Sambuc return false;
286f4a2713aSLionel Sambuc const char *tokenBegin = file.data() + locInfo.second;
287f4a2713aSLionel Sambuc
288f4a2713aSLionel Sambuc // Lex from the start of the given location.
289f4a2713aSLionel Sambuc Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
290f4a2713aSLionel Sambuc Context.getLangOpts(),
291f4a2713aSLionel Sambuc file.begin(), tokenBegin, file.end());
292f4a2713aSLionel Sambuc Token Tok;
293f4a2713aSLionel Sambuc do {
294f4a2713aSLionel Sambuc lexer.LexFromRawLexer(Tok);
295*0a6a1f1dSLionel Sambuc if (Tok.is(tok::raw_identifier) && Tok.getRawIdentifier() == attrName) {
296f4a2713aSLionel Sambuc Loc = Tok.getLocation();
297f4a2713aSLionel Sambuc return true;
298f4a2713aSLionel Sambuc }
299f4a2713aSLionel Sambuc } while (Tok.isNot(tok::r_paren));
300f4a2713aSLionel Sambuc return false;
301f4a2713aSLionel Sambuc
302f4a2713aSLionel Sambuc }
303f4a2713aSLionel Sambuc
getOwnershipRule(unsigned attr)304f4a2713aSLionel Sambuc static unsigned getOwnershipRule(unsigned attr) {
305f4a2713aSLionel Sambuc return attr & (ObjCPropertyDecl::OBJC_PR_assign |
306f4a2713aSLionel Sambuc ObjCPropertyDecl::OBJC_PR_retain |
307f4a2713aSLionel Sambuc ObjCPropertyDecl::OBJC_PR_copy |
308f4a2713aSLionel Sambuc ObjCPropertyDecl::OBJC_PR_weak |
309f4a2713aSLionel Sambuc ObjCPropertyDecl::OBJC_PR_strong |
310f4a2713aSLionel Sambuc ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
311f4a2713aSLionel Sambuc }
312f4a2713aSLionel Sambuc
313f4a2713aSLionel Sambuc ObjCPropertyDecl *
HandlePropertyInClassExtension(Scope * S,SourceLocation AtLoc,SourceLocation LParenLoc,FieldDeclarator & FD,Selector GetterSel,Selector SetterSel,const bool isAssign,const bool isReadWrite,const unsigned Attributes,const unsigned AttributesAsWritten,bool * isOverridingProperty,TypeSourceInfo * T,tok::ObjCKeywordKind MethodImplKind)314f4a2713aSLionel Sambuc Sema::HandlePropertyInClassExtension(Scope *S,
315f4a2713aSLionel Sambuc SourceLocation AtLoc,
316f4a2713aSLionel Sambuc SourceLocation LParenLoc,
317f4a2713aSLionel Sambuc FieldDeclarator &FD,
318f4a2713aSLionel Sambuc Selector GetterSel, Selector SetterSel,
319f4a2713aSLionel Sambuc const bool isAssign,
320f4a2713aSLionel Sambuc const bool isReadWrite,
321f4a2713aSLionel Sambuc const unsigned Attributes,
322f4a2713aSLionel Sambuc const unsigned AttributesAsWritten,
323f4a2713aSLionel Sambuc bool *isOverridingProperty,
324f4a2713aSLionel Sambuc TypeSourceInfo *T,
325f4a2713aSLionel Sambuc tok::ObjCKeywordKind MethodImplKind) {
326f4a2713aSLionel Sambuc ObjCCategoryDecl *CDecl = cast<ObjCCategoryDecl>(CurContext);
327f4a2713aSLionel Sambuc // Diagnose if this property is already in continuation class.
328f4a2713aSLionel Sambuc DeclContext *DC = CurContext;
329f4a2713aSLionel Sambuc IdentifierInfo *PropertyId = FD.D.getIdentifier();
330f4a2713aSLionel Sambuc ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface();
331f4a2713aSLionel Sambuc
332f4a2713aSLionel Sambuc if (CCPrimary) {
333f4a2713aSLionel Sambuc // Check for duplicate declaration of this property in current and
334f4a2713aSLionel Sambuc // other class extensions.
335*0a6a1f1dSLionel Sambuc for (const auto *Ext : CCPrimary->known_extensions()) {
336f4a2713aSLionel Sambuc if (ObjCPropertyDecl *prevDecl
337*0a6a1f1dSLionel Sambuc = ObjCPropertyDecl::findPropertyDecl(Ext, PropertyId)) {
338f4a2713aSLionel Sambuc Diag(AtLoc, diag::err_duplicate_property);
339f4a2713aSLionel Sambuc Diag(prevDecl->getLocation(), diag::note_property_declare);
340*0a6a1f1dSLionel Sambuc return nullptr;
341f4a2713aSLionel Sambuc }
342f4a2713aSLionel Sambuc }
343f4a2713aSLionel Sambuc }
344f4a2713aSLionel Sambuc
345f4a2713aSLionel Sambuc // Create a new ObjCPropertyDecl with the DeclContext being
346f4a2713aSLionel Sambuc // the class extension.
347f4a2713aSLionel Sambuc // FIXME. We should really be using CreatePropertyDecl for this.
348f4a2713aSLionel Sambuc ObjCPropertyDecl *PDecl =
349f4a2713aSLionel Sambuc ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(),
350f4a2713aSLionel Sambuc PropertyId, AtLoc, LParenLoc, T);
351f4a2713aSLionel Sambuc PDecl->setPropertyAttributesAsWritten(
352f4a2713aSLionel Sambuc makePropertyAttributesAsWritten(AttributesAsWritten));
353f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
354f4a2713aSLionel Sambuc PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
355f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_readwrite)
356f4a2713aSLionel Sambuc PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite);
357f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
358f4a2713aSLionel Sambuc PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic);
359f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_atomic)
360f4a2713aSLionel Sambuc PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_atomic);
361f4a2713aSLionel Sambuc // Set setter/getter selector name. Needed later.
362f4a2713aSLionel Sambuc PDecl->setGetterName(GetterSel);
363f4a2713aSLionel Sambuc PDecl->setSetterName(SetterSel);
364f4a2713aSLionel Sambuc ProcessDeclAttributes(S, PDecl, FD.D);
365f4a2713aSLionel Sambuc DC->addDecl(PDecl);
366f4a2713aSLionel Sambuc
367f4a2713aSLionel Sambuc // We need to look in the @interface to see if the @property was
368f4a2713aSLionel Sambuc // already declared.
369f4a2713aSLionel Sambuc if (!CCPrimary) {
370f4a2713aSLionel Sambuc Diag(CDecl->getLocation(), diag::err_continuation_class);
371f4a2713aSLionel Sambuc *isOverridingProperty = true;
372*0a6a1f1dSLionel Sambuc return nullptr;
373f4a2713aSLionel Sambuc }
374f4a2713aSLionel Sambuc
375f4a2713aSLionel Sambuc // Find the property in continuation class's primary class only.
376f4a2713aSLionel Sambuc ObjCPropertyDecl *PIDecl =
377f4a2713aSLionel Sambuc CCPrimary->FindPropertyVisibleInPrimaryClass(PropertyId);
378f4a2713aSLionel Sambuc
379f4a2713aSLionel Sambuc if (!PIDecl) {
380f4a2713aSLionel Sambuc // No matching property found in the primary class. Just fall thru
381f4a2713aSLionel Sambuc // and add property to continuation class's primary class.
382f4a2713aSLionel Sambuc ObjCPropertyDecl *PrimaryPDecl =
383f4a2713aSLionel Sambuc CreatePropertyDecl(S, CCPrimary, AtLoc, LParenLoc,
384f4a2713aSLionel Sambuc FD, GetterSel, SetterSel, isAssign, isReadWrite,
385f4a2713aSLionel Sambuc Attributes,AttributesAsWritten, T, MethodImplKind, DC);
386f4a2713aSLionel Sambuc
387f4a2713aSLionel Sambuc // A case of continuation class adding a new property in the class. This
388f4a2713aSLionel Sambuc // is not what it was meant for. However, gcc supports it and so should we.
389f4a2713aSLionel Sambuc // Make sure setter/getters are declared here.
390*0a6a1f1dSLionel Sambuc ProcessPropertyDecl(PrimaryPDecl, CCPrimary,
391*0a6a1f1dSLionel Sambuc /* redeclaredProperty = */ nullptr,
392f4a2713aSLionel Sambuc /* lexicalDC = */ CDecl);
393f4a2713aSLionel Sambuc PDecl->setGetterMethodDecl(PrimaryPDecl->getGetterMethodDecl());
394f4a2713aSLionel Sambuc PDecl->setSetterMethodDecl(PrimaryPDecl->getSetterMethodDecl());
395f4a2713aSLionel Sambuc if (ASTMutationListener *L = Context.getASTMutationListener())
396*0a6a1f1dSLionel Sambuc L->AddedObjCPropertyInClassExtension(PrimaryPDecl, /*OrigProp=*/nullptr,
397*0a6a1f1dSLionel Sambuc CDecl);
398f4a2713aSLionel Sambuc return PrimaryPDecl;
399f4a2713aSLionel Sambuc }
400f4a2713aSLionel Sambuc if (!Context.hasSameType(PIDecl->getType(), PDecl->getType())) {
401f4a2713aSLionel Sambuc bool IncompatibleObjC = false;
402f4a2713aSLionel Sambuc QualType ConvertedType;
403f4a2713aSLionel Sambuc // Relax the strict type matching for property type in continuation class.
404f4a2713aSLionel Sambuc // Allow property object type of continuation class to be different as long
405f4a2713aSLionel Sambuc // as it narrows the object type in its primary class property. Note that
406f4a2713aSLionel Sambuc // this conversion is safe only because the wider type is for a 'readonly'
407f4a2713aSLionel Sambuc // property in primary class and 'narrowed' type for a 'readwrite' property
408f4a2713aSLionel Sambuc // in continuation class.
409f4a2713aSLionel Sambuc if (!isa<ObjCObjectPointerType>(PIDecl->getType()) ||
410f4a2713aSLionel Sambuc !isa<ObjCObjectPointerType>(PDecl->getType()) ||
411f4a2713aSLionel Sambuc (!isObjCPointerConversion(PDecl->getType(), PIDecl->getType(),
412f4a2713aSLionel Sambuc ConvertedType, IncompatibleObjC))
413f4a2713aSLionel Sambuc || IncompatibleObjC) {
414f4a2713aSLionel Sambuc Diag(AtLoc,
415f4a2713aSLionel Sambuc diag::err_type_mismatch_continuation_class) << PDecl->getType();
416f4a2713aSLionel Sambuc Diag(PIDecl->getLocation(), diag::note_property_declare);
417*0a6a1f1dSLionel Sambuc return nullptr;
418f4a2713aSLionel Sambuc }
419f4a2713aSLionel Sambuc }
420f4a2713aSLionel Sambuc
421f4a2713aSLionel Sambuc // The property 'PIDecl's readonly attribute will be over-ridden
422f4a2713aSLionel Sambuc // with continuation class's readwrite property attribute!
423f4a2713aSLionel Sambuc unsigned PIkind = PIDecl->getPropertyAttributesAsWritten();
424f4a2713aSLionel Sambuc if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) {
425f4a2713aSLionel Sambuc PIkind &= ~ObjCPropertyDecl::OBJC_PR_readonly;
426f4a2713aSLionel Sambuc PIkind |= ObjCPropertyDecl::OBJC_PR_readwrite;
427f4a2713aSLionel Sambuc PIkind |= deduceWeakPropertyFromType(*this, PIDecl->getType());
428f4a2713aSLionel Sambuc unsigned ClassExtensionMemoryModel = getOwnershipRule(Attributes);
429f4a2713aSLionel Sambuc unsigned PrimaryClassMemoryModel = getOwnershipRule(PIkind);
430f4a2713aSLionel Sambuc if (PrimaryClassMemoryModel && ClassExtensionMemoryModel &&
431f4a2713aSLionel Sambuc (PrimaryClassMemoryModel != ClassExtensionMemoryModel)) {
432f4a2713aSLionel Sambuc Diag(AtLoc, diag::warn_property_attr_mismatch);
433f4a2713aSLionel Sambuc Diag(PIDecl->getLocation(), diag::note_property_declare);
434f4a2713aSLionel Sambuc }
435f4a2713aSLionel Sambuc else if (getLangOpts().ObjCAutoRefCount) {
436f4a2713aSLionel Sambuc QualType PrimaryPropertyQT =
437f4a2713aSLionel Sambuc Context.getCanonicalType(PIDecl->getType()).getUnqualifiedType();
438f4a2713aSLionel Sambuc if (isa<ObjCObjectPointerType>(PrimaryPropertyQT)) {
439f4a2713aSLionel Sambuc bool PropertyIsWeak = ((PIkind & ObjCPropertyDecl::OBJC_PR_weak) != 0);
440f4a2713aSLionel Sambuc Qualifiers::ObjCLifetime PrimaryPropertyLifeTime =
441f4a2713aSLionel Sambuc PrimaryPropertyQT.getObjCLifetime();
442f4a2713aSLionel Sambuc if (PrimaryPropertyLifeTime == Qualifiers::OCL_None &&
443f4a2713aSLionel Sambuc (Attributes & ObjCDeclSpec::DQ_PR_weak) &&
444f4a2713aSLionel Sambuc !PropertyIsWeak) {
445f4a2713aSLionel Sambuc Diag(AtLoc, diag::warn_property_implicitly_mismatched);
446f4a2713aSLionel Sambuc Diag(PIDecl->getLocation(), diag::note_property_declare);
447f4a2713aSLionel Sambuc }
448f4a2713aSLionel Sambuc }
449f4a2713aSLionel Sambuc }
450f4a2713aSLionel Sambuc
451f4a2713aSLionel Sambuc DeclContext *DC = cast<DeclContext>(CCPrimary);
452f4a2713aSLionel Sambuc if (!ObjCPropertyDecl::findPropertyDecl(DC,
453f4a2713aSLionel Sambuc PIDecl->getDeclName().getAsIdentifierInfo())) {
454*0a6a1f1dSLionel Sambuc // In mrr mode, 'readwrite' property must have an explicit
455*0a6a1f1dSLionel Sambuc // memory attribute. If none specified, select the default (assign).
456*0a6a1f1dSLionel Sambuc if (!getLangOpts().ObjCAutoRefCount) {
457*0a6a1f1dSLionel Sambuc if (!(PIkind & (ObjCDeclSpec::DQ_PR_assign |
458*0a6a1f1dSLionel Sambuc ObjCDeclSpec::DQ_PR_retain |
459*0a6a1f1dSLionel Sambuc ObjCDeclSpec::DQ_PR_strong |
460*0a6a1f1dSLionel Sambuc ObjCDeclSpec::DQ_PR_copy |
461*0a6a1f1dSLionel Sambuc ObjCDeclSpec::DQ_PR_unsafe_unretained |
462*0a6a1f1dSLionel Sambuc ObjCDeclSpec::DQ_PR_weak)))
463*0a6a1f1dSLionel Sambuc PIkind |= ObjCPropertyDecl::OBJC_PR_assign;
464*0a6a1f1dSLionel Sambuc }
465*0a6a1f1dSLionel Sambuc
466f4a2713aSLionel Sambuc // Protocol is not in the primary class. Must build one for it.
467f4a2713aSLionel Sambuc ObjCDeclSpec ProtocolPropertyODS;
468f4a2713aSLionel Sambuc // FIXME. Assuming that ObjCDeclSpec::ObjCPropertyAttributeKind
469f4a2713aSLionel Sambuc // and ObjCPropertyDecl::PropertyAttributeKind have identical
470f4a2713aSLionel Sambuc // values. Should consolidate both into one enum type.
471f4a2713aSLionel Sambuc ProtocolPropertyODS.
472f4a2713aSLionel Sambuc setPropertyAttributes((ObjCDeclSpec::ObjCPropertyAttributeKind)
473f4a2713aSLionel Sambuc PIkind);
474f4a2713aSLionel Sambuc // Must re-establish the context from class extension to primary
475f4a2713aSLionel Sambuc // class context.
476f4a2713aSLionel Sambuc ContextRAII SavedContext(*this, CCPrimary);
477f4a2713aSLionel Sambuc
478f4a2713aSLionel Sambuc Decl *ProtocolPtrTy =
479f4a2713aSLionel Sambuc ActOnProperty(S, AtLoc, LParenLoc, FD, ProtocolPropertyODS,
480f4a2713aSLionel Sambuc PIDecl->getGetterName(),
481f4a2713aSLionel Sambuc PIDecl->getSetterName(),
482f4a2713aSLionel Sambuc isOverridingProperty,
483f4a2713aSLionel Sambuc MethodImplKind,
484f4a2713aSLionel Sambuc /* lexicalDC = */ CDecl);
485f4a2713aSLionel Sambuc PIDecl = cast<ObjCPropertyDecl>(ProtocolPtrTy);
486f4a2713aSLionel Sambuc }
487f4a2713aSLionel Sambuc PIDecl->makeitReadWriteAttribute();
488f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_retain)
489f4a2713aSLionel Sambuc PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
490f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_strong)
491f4a2713aSLionel Sambuc PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
492f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_copy)
493f4a2713aSLionel Sambuc PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
494f4a2713aSLionel Sambuc PIDecl->setSetterName(SetterSel);
495f4a2713aSLionel Sambuc } else {
496f4a2713aSLionel Sambuc // Tailor the diagnostics for the common case where a readwrite
497f4a2713aSLionel Sambuc // property is declared both in the @interface and the continuation.
498f4a2713aSLionel Sambuc // This is a common error where the user often intended the original
499f4a2713aSLionel Sambuc // declaration to be readonly.
500f4a2713aSLionel Sambuc unsigned diag =
501f4a2713aSLionel Sambuc (Attributes & ObjCDeclSpec::DQ_PR_readwrite) &&
502f4a2713aSLionel Sambuc (PIkind & ObjCPropertyDecl::OBJC_PR_readwrite)
503f4a2713aSLionel Sambuc ? diag::err_use_continuation_class_redeclaration_readwrite
504f4a2713aSLionel Sambuc : diag::err_use_continuation_class;
505f4a2713aSLionel Sambuc Diag(AtLoc, diag)
506f4a2713aSLionel Sambuc << CCPrimary->getDeclName();
507f4a2713aSLionel Sambuc Diag(PIDecl->getLocation(), diag::note_property_declare);
508*0a6a1f1dSLionel Sambuc return nullptr;
509f4a2713aSLionel Sambuc }
510f4a2713aSLionel Sambuc *isOverridingProperty = true;
511f4a2713aSLionel Sambuc // Make sure setter decl is synthesized, and added to primary class's list.
512f4a2713aSLionel Sambuc ProcessPropertyDecl(PIDecl, CCPrimary, PDecl, CDecl);
513f4a2713aSLionel Sambuc PDecl->setGetterMethodDecl(PIDecl->getGetterMethodDecl());
514f4a2713aSLionel Sambuc PDecl->setSetterMethodDecl(PIDecl->getSetterMethodDecl());
515f4a2713aSLionel Sambuc if (ASTMutationListener *L = Context.getASTMutationListener())
516f4a2713aSLionel Sambuc L->AddedObjCPropertyInClassExtension(PDecl, PIDecl, CDecl);
517f4a2713aSLionel Sambuc return PDecl;
518f4a2713aSLionel Sambuc }
519f4a2713aSLionel Sambuc
CreatePropertyDecl(Scope * S,ObjCContainerDecl * CDecl,SourceLocation AtLoc,SourceLocation LParenLoc,FieldDeclarator & FD,Selector GetterSel,Selector SetterSel,const bool isAssign,const bool isReadWrite,const unsigned Attributes,const unsigned AttributesAsWritten,TypeSourceInfo * TInfo,tok::ObjCKeywordKind MethodImplKind,DeclContext * lexicalDC)520f4a2713aSLionel Sambuc ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
521f4a2713aSLionel Sambuc ObjCContainerDecl *CDecl,
522f4a2713aSLionel Sambuc SourceLocation AtLoc,
523f4a2713aSLionel Sambuc SourceLocation LParenLoc,
524f4a2713aSLionel Sambuc FieldDeclarator &FD,
525f4a2713aSLionel Sambuc Selector GetterSel,
526f4a2713aSLionel Sambuc Selector SetterSel,
527f4a2713aSLionel Sambuc const bool isAssign,
528f4a2713aSLionel Sambuc const bool isReadWrite,
529f4a2713aSLionel Sambuc const unsigned Attributes,
530f4a2713aSLionel Sambuc const unsigned AttributesAsWritten,
531f4a2713aSLionel Sambuc TypeSourceInfo *TInfo,
532f4a2713aSLionel Sambuc tok::ObjCKeywordKind MethodImplKind,
533f4a2713aSLionel Sambuc DeclContext *lexicalDC){
534f4a2713aSLionel Sambuc IdentifierInfo *PropertyId = FD.D.getIdentifier();
535f4a2713aSLionel Sambuc QualType T = TInfo->getType();
536f4a2713aSLionel Sambuc
537f4a2713aSLionel Sambuc // Issue a warning if property is 'assign' as default and its object, which is
538f4a2713aSLionel Sambuc // gc'able conforms to NSCopying protocol
539f4a2713aSLionel Sambuc if (getLangOpts().getGC() != LangOptions::NonGC &&
540f4a2713aSLionel Sambuc isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign))
541f4a2713aSLionel Sambuc if (const ObjCObjectPointerType *ObjPtrTy =
542f4a2713aSLionel Sambuc T->getAs<ObjCObjectPointerType>()) {
543f4a2713aSLionel Sambuc ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
544f4a2713aSLionel Sambuc if (IDecl)
545f4a2713aSLionel Sambuc if (ObjCProtocolDecl* PNSCopying =
546f4a2713aSLionel Sambuc LookupProtocol(&Context.Idents.get("NSCopying"), AtLoc))
547f4a2713aSLionel Sambuc if (IDecl->ClassImplementsProtocol(PNSCopying, true))
548f4a2713aSLionel Sambuc Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId;
549f4a2713aSLionel Sambuc }
550f4a2713aSLionel Sambuc
551f4a2713aSLionel Sambuc if (T->isObjCObjectType()) {
552f4a2713aSLionel Sambuc SourceLocation StarLoc = TInfo->getTypeLoc().getLocEnd();
553*0a6a1f1dSLionel Sambuc StarLoc = getLocForEndOfToken(StarLoc);
554f4a2713aSLionel Sambuc Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object)
555f4a2713aSLionel Sambuc << FixItHint::CreateInsertion(StarLoc, "*");
556f4a2713aSLionel Sambuc T = Context.getObjCObjectPointerType(T);
557f4a2713aSLionel Sambuc SourceLocation TLoc = TInfo->getTypeLoc().getLocStart();
558f4a2713aSLionel Sambuc TInfo = Context.getTrivialTypeSourceInfo(T, TLoc);
559f4a2713aSLionel Sambuc }
560f4a2713aSLionel Sambuc
561f4a2713aSLionel Sambuc DeclContext *DC = cast<DeclContext>(CDecl);
562f4a2713aSLionel Sambuc ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
563f4a2713aSLionel Sambuc FD.D.getIdentifierLoc(),
564f4a2713aSLionel Sambuc PropertyId, AtLoc, LParenLoc, TInfo);
565f4a2713aSLionel Sambuc
566f4a2713aSLionel Sambuc if (ObjCPropertyDecl *prevDecl =
567f4a2713aSLionel Sambuc ObjCPropertyDecl::findPropertyDecl(DC, PropertyId)) {
568f4a2713aSLionel Sambuc Diag(PDecl->getLocation(), diag::err_duplicate_property);
569f4a2713aSLionel Sambuc Diag(prevDecl->getLocation(), diag::note_property_declare);
570f4a2713aSLionel Sambuc PDecl->setInvalidDecl();
571f4a2713aSLionel Sambuc }
572f4a2713aSLionel Sambuc else {
573f4a2713aSLionel Sambuc DC->addDecl(PDecl);
574f4a2713aSLionel Sambuc if (lexicalDC)
575f4a2713aSLionel Sambuc PDecl->setLexicalDeclContext(lexicalDC);
576f4a2713aSLionel Sambuc }
577f4a2713aSLionel Sambuc
578f4a2713aSLionel Sambuc if (T->isArrayType() || T->isFunctionType()) {
579f4a2713aSLionel Sambuc Diag(AtLoc, diag::err_property_type) << T;
580f4a2713aSLionel Sambuc PDecl->setInvalidDecl();
581f4a2713aSLionel Sambuc }
582f4a2713aSLionel Sambuc
583f4a2713aSLionel Sambuc ProcessDeclAttributes(S, PDecl, FD.D);
584f4a2713aSLionel Sambuc
585f4a2713aSLionel Sambuc // Regardless of setter/getter attribute, we save the default getter/setter
586f4a2713aSLionel Sambuc // selector names in anticipation of declaration of setter/getter methods.
587f4a2713aSLionel Sambuc PDecl->setGetterName(GetterSel);
588f4a2713aSLionel Sambuc PDecl->setSetterName(SetterSel);
589f4a2713aSLionel Sambuc PDecl->setPropertyAttributesAsWritten(
590f4a2713aSLionel Sambuc makePropertyAttributesAsWritten(AttributesAsWritten));
591f4a2713aSLionel Sambuc
592f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
593f4a2713aSLionel Sambuc PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
594f4a2713aSLionel Sambuc
595f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_getter)
596f4a2713aSLionel Sambuc PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_getter);
597f4a2713aSLionel Sambuc
598f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_setter)
599f4a2713aSLionel Sambuc PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter);
600f4a2713aSLionel Sambuc
601f4a2713aSLionel Sambuc if (isReadWrite)
602f4a2713aSLionel Sambuc PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite);
603f4a2713aSLionel Sambuc
604f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_retain)
605f4a2713aSLionel Sambuc PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
606f4a2713aSLionel Sambuc
607f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_strong)
608f4a2713aSLionel Sambuc PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
609f4a2713aSLionel Sambuc
610f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_weak)
611f4a2713aSLionel Sambuc PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_weak);
612f4a2713aSLionel Sambuc
613f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_copy)
614f4a2713aSLionel Sambuc PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
615f4a2713aSLionel Sambuc
616f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained)
617f4a2713aSLionel Sambuc PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
618f4a2713aSLionel Sambuc
619f4a2713aSLionel Sambuc if (isAssign)
620f4a2713aSLionel Sambuc PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
621f4a2713aSLionel Sambuc
622f4a2713aSLionel Sambuc // In the semantic attributes, one of nonatomic or atomic is always set.
623f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
624f4a2713aSLionel Sambuc PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic);
625f4a2713aSLionel Sambuc else
626f4a2713aSLionel Sambuc PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_atomic);
627f4a2713aSLionel Sambuc
628f4a2713aSLionel Sambuc // 'unsafe_unretained' is alias for 'assign'.
629f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained)
630f4a2713aSLionel Sambuc PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
631f4a2713aSLionel Sambuc if (isAssign)
632f4a2713aSLionel Sambuc PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
633f4a2713aSLionel Sambuc
634f4a2713aSLionel Sambuc if (MethodImplKind == tok::objc_required)
635f4a2713aSLionel Sambuc PDecl->setPropertyImplementation(ObjCPropertyDecl::Required);
636f4a2713aSLionel Sambuc else if (MethodImplKind == tok::objc_optional)
637f4a2713aSLionel Sambuc PDecl->setPropertyImplementation(ObjCPropertyDecl::Optional);
638f4a2713aSLionel Sambuc
639f4a2713aSLionel Sambuc return PDecl;
640f4a2713aSLionel Sambuc }
641f4a2713aSLionel Sambuc
checkARCPropertyImpl(Sema & S,SourceLocation propertyImplLoc,ObjCPropertyDecl * property,ObjCIvarDecl * ivar)642f4a2713aSLionel Sambuc static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc,
643f4a2713aSLionel Sambuc ObjCPropertyDecl *property,
644f4a2713aSLionel Sambuc ObjCIvarDecl *ivar) {
645f4a2713aSLionel Sambuc if (property->isInvalidDecl() || ivar->isInvalidDecl()) return;
646f4a2713aSLionel Sambuc
647f4a2713aSLionel Sambuc QualType ivarType = ivar->getType();
648f4a2713aSLionel Sambuc Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime();
649f4a2713aSLionel Sambuc
650f4a2713aSLionel Sambuc // The lifetime implied by the property's attributes.
651f4a2713aSLionel Sambuc Qualifiers::ObjCLifetime propertyLifetime =
652f4a2713aSLionel Sambuc getImpliedARCOwnership(property->getPropertyAttributes(),
653f4a2713aSLionel Sambuc property->getType());
654f4a2713aSLionel Sambuc
655f4a2713aSLionel Sambuc // We're fine if they match.
656f4a2713aSLionel Sambuc if (propertyLifetime == ivarLifetime) return;
657f4a2713aSLionel Sambuc
658f4a2713aSLionel Sambuc // These aren't valid lifetimes for object ivars; don't diagnose twice.
659f4a2713aSLionel Sambuc if (ivarLifetime == Qualifiers::OCL_None ||
660f4a2713aSLionel Sambuc ivarLifetime == Qualifiers::OCL_Autoreleasing)
661f4a2713aSLionel Sambuc return;
662f4a2713aSLionel Sambuc
663f4a2713aSLionel Sambuc // If the ivar is private, and it's implicitly __unsafe_unretained
664f4a2713aSLionel Sambuc // becaues of its type, then pretend it was actually implicitly
665f4a2713aSLionel Sambuc // __strong. This is only sound because we're processing the
666f4a2713aSLionel Sambuc // property implementation before parsing any method bodies.
667f4a2713aSLionel Sambuc if (ivarLifetime == Qualifiers::OCL_ExplicitNone &&
668f4a2713aSLionel Sambuc propertyLifetime == Qualifiers::OCL_Strong &&
669f4a2713aSLionel Sambuc ivar->getAccessControl() == ObjCIvarDecl::Private) {
670f4a2713aSLionel Sambuc SplitQualType split = ivarType.split();
671f4a2713aSLionel Sambuc if (split.Quals.hasObjCLifetime()) {
672f4a2713aSLionel Sambuc assert(ivarType->isObjCARCImplicitlyUnretainedType());
673f4a2713aSLionel Sambuc split.Quals.setObjCLifetime(Qualifiers::OCL_Strong);
674f4a2713aSLionel Sambuc ivarType = S.Context.getQualifiedType(split);
675f4a2713aSLionel Sambuc ivar->setType(ivarType);
676f4a2713aSLionel Sambuc return;
677f4a2713aSLionel Sambuc }
678f4a2713aSLionel Sambuc }
679f4a2713aSLionel Sambuc
680f4a2713aSLionel Sambuc switch (propertyLifetime) {
681f4a2713aSLionel Sambuc case Qualifiers::OCL_Strong:
682f4a2713aSLionel Sambuc S.Diag(ivar->getLocation(), diag::err_arc_strong_property_ownership)
683f4a2713aSLionel Sambuc << property->getDeclName()
684f4a2713aSLionel Sambuc << ivar->getDeclName()
685f4a2713aSLionel Sambuc << ivarLifetime;
686f4a2713aSLionel Sambuc break;
687f4a2713aSLionel Sambuc
688f4a2713aSLionel Sambuc case Qualifiers::OCL_Weak:
689f4a2713aSLionel Sambuc S.Diag(ivar->getLocation(), diag::error_weak_property)
690f4a2713aSLionel Sambuc << property->getDeclName()
691f4a2713aSLionel Sambuc << ivar->getDeclName();
692f4a2713aSLionel Sambuc break;
693f4a2713aSLionel Sambuc
694f4a2713aSLionel Sambuc case Qualifiers::OCL_ExplicitNone:
695f4a2713aSLionel Sambuc S.Diag(ivar->getLocation(), diag::err_arc_assign_property_ownership)
696f4a2713aSLionel Sambuc << property->getDeclName()
697f4a2713aSLionel Sambuc << ivar->getDeclName()
698f4a2713aSLionel Sambuc << ((property->getPropertyAttributesAsWritten()
699f4a2713aSLionel Sambuc & ObjCPropertyDecl::OBJC_PR_assign) != 0);
700f4a2713aSLionel Sambuc break;
701f4a2713aSLionel Sambuc
702f4a2713aSLionel Sambuc case Qualifiers::OCL_Autoreleasing:
703f4a2713aSLionel Sambuc llvm_unreachable("properties cannot be autoreleasing");
704f4a2713aSLionel Sambuc
705f4a2713aSLionel Sambuc case Qualifiers::OCL_None:
706f4a2713aSLionel Sambuc // Any other property should be ignored.
707f4a2713aSLionel Sambuc return;
708f4a2713aSLionel Sambuc }
709f4a2713aSLionel Sambuc
710f4a2713aSLionel Sambuc S.Diag(property->getLocation(), diag::note_property_declare);
711f4a2713aSLionel Sambuc if (propertyImplLoc.isValid())
712f4a2713aSLionel Sambuc S.Diag(propertyImplLoc, diag::note_property_synthesize);
713f4a2713aSLionel Sambuc }
714f4a2713aSLionel Sambuc
715f4a2713aSLionel Sambuc /// setImpliedPropertyAttributeForReadOnlyProperty -
716f4a2713aSLionel Sambuc /// This routine evaludates life-time attributes for a 'readonly'
717f4a2713aSLionel Sambuc /// property with no known lifetime of its own, using backing
718f4a2713aSLionel Sambuc /// 'ivar's attribute, if any. If no backing 'ivar', property's
719f4a2713aSLionel Sambuc /// life-time is assumed 'strong'.
setImpliedPropertyAttributeForReadOnlyProperty(ObjCPropertyDecl * property,ObjCIvarDecl * ivar)720f4a2713aSLionel Sambuc static void setImpliedPropertyAttributeForReadOnlyProperty(
721f4a2713aSLionel Sambuc ObjCPropertyDecl *property, ObjCIvarDecl *ivar) {
722f4a2713aSLionel Sambuc Qualifiers::ObjCLifetime propertyLifetime =
723f4a2713aSLionel Sambuc getImpliedARCOwnership(property->getPropertyAttributes(),
724f4a2713aSLionel Sambuc property->getType());
725f4a2713aSLionel Sambuc if (propertyLifetime != Qualifiers::OCL_None)
726f4a2713aSLionel Sambuc return;
727f4a2713aSLionel Sambuc
728f4a2713aSLionel Sambuc if (!ivar) {
729f4a2713aSLionel Sambuc // if no backing ivar, make property 'strong'.
730f4a2713aSLionel Sambuc property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
731f4a2713aSLionel Sambuc return;
732f4a2713aSLionel Sambuc }
733f4a2713aSLionel Sambuc // property assumes owenership of backing ivar.
734f4a2713aSLionel Sambuc QualType ivarType = ivar->getType();
735f4a2713aSLionel Sambuc Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime();
736f4a2713aSLionel Sambuc if (ivarLifetime == Qualifiers::OCL_Strong)
737f4a2713aSLionel Sambuc property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
738f4a2713aSLionel Sambuc else if (ivarLifetime == Qualifiers::OCL_Weak)
739f4a2713aSLionel Sambuc property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_weak);
740f4a2713aSLionel Sambuc return;
741f4a2713aSLionel Sambuc }
742f4a2713aSLionel Sambuc
743f4a2713aSLionel Sambuc /// DiagnosePropertyMismatchDeclInProtocols - diagnose properties declared
744f4a2713aSLionel Sambuc /// in inherited protocols with mismatched types. Since any of them can
745f4a2713aSLionel Sambuc /// be candidate for synthesis.
746f4a2713aSLionel Sambuc static void
DiagnosePropertyMismatchDeclInProtocols(Sema & S,SourceLocation AtLoc,ObjCInterfaceDecl * ClassDecl,ObjCPropertyDecl * Property)747f4a2713aSLionel Sambuc DiagnosePropertyMismatchDeclInProtocols(Sema &S, SourceLocation AtLoc,
748f4a2713aSLionel Sambuc ObjCInterfaceDecl *ClassDecl,
749f4a2713aSLionel Sambuc ObjCPropertyDecl *Property) {
750f4a2713aSLionel Sambuc ObjCInterfaceDecl::ProtocolPropertyMap PropMap;
751*0a6a1f1dSLionel Sambuc for (const auto *PI : ClassDecl->all_referenced_protocols()) {
752*0a6a1f1dSLionel Sambuc if (const ObjCProtocolDecl *PDecl = PI->getDefinition())
753f4a2713aSLionel Sambuc PDecl->collectInheritedProtocolProperties(Property, PropMap);
754f4a2713aSLionel Sambuc }
755f4a2713aSLionel Sambuc if (ObjCInterfaceDecl *SDecl = ClassDecl->getSuperClass())
756f4a2713aSLionel Sambuc while (SDecl) {
757*0a6a1f1dSLionel Sambuc for (const auto *PI : SDecl->all_referenced_protocols()) {
758*0a6a1f1dSLionel Sambuc if (const ObjCProtocolDecl *PDecl = PI->getDefinition())
759f4a2713aSLionel Sambuc PDecl->collectInheritedProtocolProperties(Property, PropMap);
760f4a2713aSLionel Sambuc }
761f4a2713aSLionel Sambuc SDecl = SDecl->getSuperClass();
762f4a2713aSLionel Sambuc }
763f4a2713aSLionel Sambuc
764f4a2713aSLionel Sambuc if (PropMap.empty())
765f4a2713aSLionel Sambuc return;
766f4a2713aSLionel Sambuc
767f4a2713aSLionel Sambuc QualType RHSType = S.Context.getCanonicalType(Property->getType());
768f4a2713aSLionel Sambuc bool FirsTime = true;
769f4a2713aSLionel Sambuc for (ObjCInterfaceDecl::ProtocolPropertyMap::iterator
770f4a2713aSLionel Sambuc I = PropMap.begin(), E = PropMap.end(); I != E; I++) {
771f4a2713aSLionel Sambuc ObjCPropertyDecl *Prop = I->second;
772f4a2713aSLionel Sambuc QualType LHSType = S.Context.getCanonicalType(Prop->getType());
773f4a2713aSLionel Sambuc if (!S.Context.propertyTypesAreCompatible(LHSType, RHSType)) {
774f4a2713aSLionel Sambuc bool IncompatibleObjC = false;
775f4a2713aSLionel Sambuc QualType ConvertedType;
776f4a2713aSLionel Sambuc if (!S.isObjCPointerConversion(RHSType, LHSType, ConvertedType, IncompatibleObjC)
777f4a2713aSLionel Sambuc || IncompatibleObjC) {
778f4a2713aSLionel Sambuc if (FirsTime) {
779f4a2713aSLionel Sambuc S.Diag(Property->getLocation(), diag::warn_protocol_property_mismatch)
780f4a2713aSLionel Sambuc << Property->getType();
781f4a2713aSLionel Sambuc FirsTime = false;
782f4a2713aSLionel Sambuc }
783f4a2713aSLionel Sambuc S.Diag(Prop->getLocation(), diag::note_protocol_property_declare)
784f4a2713aSLionel Sambuc << Prop->getType();
785f4a2713aSLionel Sambuc }
786f4a2713aSLionel Sambuc }
787f4a2713aSLionel Sambuc }
788f4a2713aSLionel Sambuc if (!FirsTime && AtLoc.isValid())
789f4a2713aSLionel Sambuc S.Diag(AtLoc, diag::note_property_synthesize);
790f4a2713aSLionel Sambuc }
791f4a2713aSLionel Sambuc
792f4a2713aSLionel Sambuc /// ActOnPropertyImplDecl - This routine performs semantic checks and
793f4a2713aSLionel Sambuc /// builds the AST node for a property implementation declaration; declared
794f4a2713aSLionel Sambuc /// as \@synthesize or \@dynamic.
795f4a2713aSLionel Sambuc ///
ActOnPropertyImplDecl(Scope * S,SourceLocation AtLoc,SourceLocation PropertyLoc,bool Synthesize,IdentifierInfo * PropertyId,IdentifierInfo * PropertyIvar,SourceLocation PropertyIvarLoc)796f4a2713aSLionel Sambuc Decl *Sema::ActOnPropertyImplDecl(Scope *S,
797f4a2713aSLionel Sambuc SourceLocation AtLoc,
798f4a2713aSLionel Sambuc SourceLocation PropertyLoc,
799f4a2713aSLionel Sambuc bool Synthesize,
800f4a2713aSLionel Sambuc IdentifierInfo *PropertyId,
801f4a2713aSLionel Sambuc IdentifierInfo *PropertyIvar,
802f4a2713aSLionel Sambuc SourceLocation PropertyIvarLoc) {
803f4a2713aSLionel Sambuc ObjCContainerDecl *ClassImpDecl =
804f4a2713aSLionel Sambuc dyn_cast<ObjCContainerDecl>(CurContext);
805f4a2713aSLionel Sambuc // Make sure we have a context for the property implementation declaration.
806f4a2713aSLionel Sambuc if (!ClassImpDecl) {
807f4a2713aSLionel Sambuc Diag(AtLoc, diag::error_missing_property_context);
808*0a6a1f1dSLionel Sambuc return nullptr;
809f4a2713aSLionel Sambuc }
810f4a2713aSLionel Sambuc if (PropertyIvarLoc.isInvalid())
811f4a2713aSLionel Sambuc PropertyIvarLoc = PropertyLoc;
812f4a2713aSLionel Sambuc SourceLocation PropertyDiagLoc = PropertyLoc;
813f4a2713aSLionel Sambuc if (PropertyDiagLoc.isInvalid())
814f4a2713aSLionel Sambuc PropertyDiagLoc = ClassImpDecl->getLocStart();
815*0a6a1f1dSLionel Sambuc ObjCPropertyDecl *property = nullptr;
816*0a6a1f1dSLionel Sambuc ObjCInterfaceDecl *IDecl = nullptr;
817f4a2713aSLionel Sambuc // Find the class or category class where this property must have
818f4a2713aSLionel Sambuc // a declaration.
819*0a6a1f1dSLionel Sambuc ObjCImplementationDecl *IC = nullptr;
820*0a6a1f1dSLionel Sambuc ObjCCategoryImplDecl *CatImplClass = nullptr;
821f4a2713aSLionel Sambuc if ((IC = dyn_cast<ObjCImplementationDecl>(ClassImpDecl))) {
822f4a2713aSLionel Sambuc IDecl = IC->getClassInterface();
823f4a2713aSLionel Sambuc // We always synthesize an interface for an implementation
824f4a2713aSLionel Sambuc // without an interface decl. So, IDecl is always non-zero.
825f4a2713aSLionel Sambuc assert(IDecl &&
826f4a2713aSLionel Sambuc "ActOnPropertyImplDecl - @implementation without @interface");
827f4a2713aSLionel Sambuc
828f4a2713aSLionel Sambuc // Look for this property declaration in the @implementation's @interface
829f4a2713aSLionel Sambuc property = IDecl->FindPropertyDeclaration(PropertyId);
830f4a2713aSLionel Sambuc if (!property) {
831f4a2713aSLionel Sambuc Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName();
832*0a6a1f1dSLionel Sambuc return nullptr;
833f4a2713aSLionel Sambuc }
834f4a2713aSLionel Sambuc unsigned PIkind = property->getPropertyAttributesAsWritten();
835f4a2713aSLionel Sambuc if ((PIkind & (ObjCPropertyDecl::OBJC_PR_atomic |
836f4a2713aSLionel Sambuc ObjCPropertyDecl::OBJC_PR_nonatomic) ) == 0) {
837f4a2713aSLionel Sambuc if (AtLoc.isValid())
838f4a2713aSLionel Sambuc Diag(AtLoc, diag::warn_implicit_atomic_property);
839f4a2713aSLionel Sambuc else
840f4a2713aSLionel Sambuc Diag(IC->getLocation(), diag::warn_auto_implicit_atomic_property);
841f4a2713aSLionel Sambuc Diag(property->getLocation(), diag::note_property_declare);
842f4a2713aSLionel Sambuc }
843f4a2713aSLionel Sambuc
844f4a2713aSLionel Sambuc if (const ObjCCategoryDecl *CD =
845f4a2713aSLionel Sambuc dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) {
846f4a2713aSLionel Sambuc if (!CD->IsClassExtension()) {
847f4a2713aSLionel Sambuc Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName();
848f4a2713aSLionel Sambuc Diag(property->getLocation(), diag::note_property_declare);
849*0a6a1f1dSLionel Sambuc return nullptr;
850f4a2713aSLionel Sambuc }
851f4a2713aSLionel Sambuc }
852f4a2713aSLionel Sambuc if (Synthesize&&
853f4a2713aSLionel Sambuc (PIkind & ObjCPropertyDecl::OBJC_PR_readonly) &&
854f4a2713aSLionel Sambuc property->hasAttr<IBOutletAttr>() &&
855f4a2713aSLionel Sambuc !AtLoc.isValid()) {
856f4a2713aSLionel Sambuc bool ReadWriteProperty = false;
857f4a2713aSLionel Sambuc // Search into the class extensions and see if 'readonly property is
858f4a2713aSLionel Sambuc // redeclared 'readwrite', then no warning is to be issued.
859*0a6a1f1dSLionel Sambuc for (auto *Ext : IDecl->known_extensions()) {
860f4a2713aSLionel Sambuc DeclContext::lookup_result R = Ext->lookup(property->getDeclName());
861f4a2713aSLionel Sambuc if (!R.empty())
862f4a2713aSLionel Sambuc if (ObjCPropertyDecl *ExtProp = dyn_cast<ObjCPropertyDecl>(R[0])) {
863f4a2713aSLionel Sambuc PIkind = ExtProp->getPropertyAttributesAsWritten();
864f4a2713aSLionel Sambuc if (PIkind & ObjCPropertyDecl::OBJC_PR_readwrite) {
865f4a2713aSLionel Sambuc ReadWriteProperty = true;
866f4a2713aSLionel Sambuc break;
867f4a2713aSLionel Sambuc }
868f4a2713aSLionel Sambuc }
869f4a2713aSLionel Sambuc }
870f4a2713aSLionel Sambuc
871f4a2713aSLionel Sambuc if (!ReadWriteProperty) {
872f4a2713aSLionel Sambuc Diag(property->getLocation(), diag::warn_auto_readonly_iboutlet_property)
873*0a6a1f1dSLionel Sambuc << property;
874f4a2713aSLionel Sambuc SourceLocation readonlyLoc;
875f4a2713aSLionel Sambuc if (LocPropertyAttribute(Context, "readonly",
876f4a2713aSLionel Sambuc property->getLParenLoc(), readonlyLoc)) {
877f4a2713aSLionel Sambuc SourceLocation endLoc =
878f4a2713aSLionel Sambuc readonlyLoc.getLocWithOffset(strlen("readonly")-1);
879f4a2713aSLionel Sambuc SourceRange ReadonlySourceRange(readonlyLoc, endLoc);
880f4a2713aSLionel Sambuc Diag(property->getLocation(),
881f4a2713aSLionel Sambuc diag::note_auto_readonly_iboutlet_fixup_suggest) <<
882f4a2713aSLionel Sambuc FixItHint::CreateReplacement(ReadonlySourceRange, "readwrite");
883f4a2713aSLionel Sambuc }
884f4a2713aSLionel Sambuc }
885f4a2713aSLionel Sambuc }
886f4a2713aSLionel Sambuc if (Synthesize && isa<ObjCProtocolDecl>(property->getDeclContext()))
887f4a2713aSLionel Sambuc DiagnosePropertyMismatchDeclInProtocols(*this, AtLoc, IDecl, property);
888f4a2713aSLionel Sambuc
889f4a2713aSLionel Sambuc } else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) {
890f4a2713aSLionel Sambuc if (Synthesize) {
891f4a2713aSLionel Sambuc Diag(AtLoc, diag::error_synthesize_category_decl);
892*0a6a1f1dSLionel Sambuc return nullptr;
893f4a2713aSLionel Sambuc }
894f4a2713aSLionel Sambuc IDecl = CatImplClass->getClassInterface();
895f4a2713aSLionel Sambuc if (!IDecl) {
896f4a2713aSLionel Sambuc Diag(AtLoc, diag::error_missing_property_interface);
897*0a6a1f1dSLionel Sambuc return nullptr;
898f4a2713aSLionel Sambuc }
899f4a2713aSLionel Sambuc ObjCCategoryDecl *Category =
900f4a2713aSLionel Sambuc IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier());
901f4a2713aSLionel Sambuc
902f4a2713aSLionel Sambuc // If category for this implementation not found, it is an error which
903f4a2713aSLionel Sambuc // has already been reported eralier.
904f4a2713aSLionel Sambuc if (!Category)
905*0a6a1f1dSLionel Sambuc return nullptr;
906f4a2713aSLionel Sambuc // Look for this property declaration in @implementation's category
907f4a2713aSLionel Sambuc property = Category->FindPropertyDeclaration(PropertyId);
908f4a2713aSLionel Sambuc if (!property) {
909f4a2713aSLionel Sambuc Diag(PropertyLoc, diag::error_bad_category_property_decl)
910f4a2713aSLionel Sambuc << Category->getDeclName();
911*0a6a1f1dSLionel Sambuc return nullptr;
912f4a2713aSLionel Sambuc }
913f4a2713aSLionel Sambuc } else {
914f4a2713aSLionel Sambuc Diag(AtLoc, diag::error_bad_property_context);
915*0a6a1f1dSLionel Sambuc return nullptr;
916f4a2713aSLionel Sambuc }
917*0a6a1f1dSLionel Sambuc ObjCIvarDecl *Ivar = nullptr;
918f4a2713aSLionel Sambuc bool CompleteTypeErr = false;
919f4a2713aSLionel Sambuc bool compat = true;
920f4a2713aSLionel Sambuc // Check that we have a valid, previously declared ivar for @synthesize
921f4a2713aSLionel Sambuc if (Synthesize) {
922f4a2713aSLionel Sambuc // @synthesize
923f4a2713aSLionel Sambuc if (!PropertyIvar)
924f4a2713aSLionel Sambuc PropertyIvar = PropertyId;
925f4a2713aSLionel Sambuc // Check that this is a previously declared 'ivar' in 'IDecl' interface
926f4a2713aSLionel Sambuc ObjCInterfaceDecl *ClassDeclared;
927f4a2713aSLionel Sambuc Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared);
928f4a2713aSLionel Sambuc QualType PropType = property->getType();
929f4a2713aSLionel Sambuc QualType PropertyIvarType = PropType.getNonReferenceType();
930f4a2713aSLionel Sambuc
931f4a2713aSLionel Sambuc if (RequireCompleteType(PropertyDiagLoc, PropertyIvarType,
932f4a2713aSLionel Sambuc diag::err_incomplete_synthesized_property,
933f4a2713aSLionel Sambuc property->getDeclName())) {
934f4a2713aSLionel Sambuc Diag(property->getLocation(), diag::note_property_declare);
935f4a2713aSLionel Sambuc CompleteTypeErr = true;
936f4a2713aSLionel Sambuc }
937f4a2713aSLionel Sambuc
938f4a2713aSLionel Sambuc if (getLangOpts().ObjCAutoRefCount &&
939f4a2713aSLionel Sambuc (property->getPropertyAttributesAsWritten() &
940f4a2713aSLionel Sambuc ObjCPropertyDecl::OBJC_PR_readonly) &&
941f4a2713aSLionel Sambuc PropertyIvarType->isObjCRetainableType()) {
942f4a2713aSLionel Sambuc setImpliedPropertyAttributeForReadOnlyProperty(property, Ivar);
943f4a2713aSLionel Sambuc }
944f4a2713aSLionel Sambuc
945f4a2713aSLionel Sambuc ObjCPropertyDecl::PropertyAttributeKind kind
946f4a2713aSLionel Sambuc = property->getPropertyAttributes();
947f4a2713aSLionel Sambuc
948f4a2713aSLionel Sambuc // Add GC __weak to the ivar type if the property is weak.
949f4a2713aSLionel Sambuc if ((kind & ObjCPropertyDecl::OBJC_PR_weak) &&
950f4a2713aSLionel Sambuc getLangOpts().getGC() != LangOptions::NonGC) {
951f4a2713aSLionel Sambuc assert(!getLangOpts().ObjCAutoRefCount);
952f4a2713aSLionel Sambuc if (PropertyIvarType.isObjCGCStrong()) {
953f4a2713aSLionel Sambuc Diag(PropertyDiagLoc, diag::err_gc_weak_property_strong_type);
954f4a2713aSLionel Sambuc Diag(property->getLocation(), diag::note_property_declare);
955f4a2713aSLionel Sambuc } else {
956f4a2713aSLionel Sambuc PropertyIvarType =
957f4a2713aSLionel Sambuc Context.getObjCGCQualType(PropertyIvarType, Qualifiers::Weak);
958f4a2713aSLionel Sambuc }
959f4a2713aSLionel Sambuc }
960f4a2713aSLionel Sambuc if (AtLoc.isInvalid()) {
961f4a2713aSLionel Sambuc // Check when default synthesizing a property that there is
962f4a2713aSLionel Sambuc // an ivar matching property name and issue warning; since this
963f4a2713aSLionel Sambuc // is the most common case of not using an ivar used for backing
964f4a2713aSLionel Sambuc // property in non-default synthesis case.
965*0a6a1f1dSLionel Sambuc ObjCInterfaceDecl *ClassDeclared=nullptr;
966f4a2713aSLionel Sambuc ObjCIvarDecl *originalIvar =
967f4a2713aSLionel Sambuc IDecl->lookupInstanceVariable(property->getIdentifier(),
968f4a2713aSLionel Sambuc ClassDeclared);
969f4a2713aSLionel Sambuc if (originalIvar) {
970f4a2713aSLionel Sambuc Diag(PropertyDiagLoc,
971f4a2713aSLionel Sambuc diag::warn_autosynthesis_property_ivar_match)
972*0a6a1f1dSLionel Sambuc << PropertyId << (Ivar == nullptr) << PropertyIvar
973f4a2713aSLionel Sambuc << originalIvar->getIdentifier();
974f4a2713aSLionel Sambuc Diag(property->getLocation(), diag::note_property_declare);
975f4a2713aSLionel Sambuc Diag(originalIvar->getLocation(), diag::note_ivar_decl);
976f4a2713aSLionel Sambuc }
977f4a2713aSLionel Sambuc }
978f4a2713aSLionel Sambuc
979f4a2713aSLionel Sambuc if (!Ivar) {
980f4a2713aSLionel Sambuc // In ARC, give the ivar a lifetime qualifier based on the
981f4a2713aSLionel Sambuc // property attributes.
982f4a2713aSLionel Sambuc if (getLangOpts().ObjCAutoRefCount &&
983f4a2713aSLionel Sambuc !PropertyIvarType.getObjCLifetime() &&
984f4a2713aSLionel Sambuc PropertyIvarType->isObjCRetainableType()) {
985f4a2713aSLionel Sambuc
986f4a2713aSLionel Sambuc // It's an error if we have to do this and the user didn't
987f4a2713aSLionel Sambuc // explicitly write an ownership attribute on the property.
988f4a2713aSLionel Sambuc if (!property->hasWrittenStorageAttribute() &&
989f4a2713aSLionel Sambuc !(kind & ObjCPropertyDecl::OBJC_PR_strong)) {
990f4a2713aSLionel Sambuc Diag(PropertyDiagLoc,
991f4a2713aSLionel Sambuc diag::err_arc_objc_property_default_assign_on_object);
992f4a2713aSLionel Sambuc Diag(property->getLocation(), diag::note_property_declare);
993f4a2713aSLionel Sambuc } else {
994f4a2713aSLionel Sambuc Qualifiers::ObjCLifetime lifetime =
995f4a2713aSLionel Sambuc getImpliedARCOwnership(kind, PropertyIvarType);
996f4a2713aSLionel Sambuc assert(lifetime && "no lifetime for property?");
997f4a2713aSLionel Sambuc if (lifetime == Qualifiers::OCL_Weak) {
998f4a2713aSLionel Sambuc bool err = false;
999f4a2713aSLionel Sambuc if (const ObjCObjectPointerType *ObjT =
1000f4a2713aSLionel Sambuc PropertyIvarType->getAs<ObjCObjectPointerType>()) {
1001f4a2713aSLionel Sambuc const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl();
1002f4a2713aSLionel Sambuc if (ObjI && ObjI->isArcWeakrefUnavailable()) {
1003f4a2713aSLionel Sambuc Diag(property->getLocation(),
1004f4a2713aSLionel Sambuc diag::err_arc_weak_unavailable_property) << PropertyIvarType;
1005f4a2713aSLionel Sambuc Diag(ClassImpDecl->getLocation(), diag::note_implemented_by_class)
1006f4a2713aSLionel Sambuc << ClassImpDecl->getName();
1007f4a2713aSLionel Sambuc err = true;
1008f4a2713aSLionel Sambuc }
1009f4a2713aSLionel Sambuc }
1010f4a2713aSLionel Sambuc if (!err && !getLangOpts().ObjCARCWeak) {
1011f4a2713aSLionel Sambuc Diag(PropertyDiagLoc, diag::err_arc_weak_no_runtime);
1012f4a2713aSLionel Sambuc Diag(property->getLocation(), diag::note_property_declare);
1013f4a2713aSLionel Sambuc }
1014f4a2713aSLionel Sambuc }
1015f4a2713aSLionel Sambuc
1016f4a2713aSLionel Sambuc Qualifiers qs;
1017f4a2713aSLionel Sambuc qs.addObjCLifetime(lifetime);
1018f4a2713aSLionel Sambuc PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs);
1019f4a2713aSLionel Sambuc }
1020f4a2713aSLionel Sambuc }
1021f4a2713aSLionel Sambuc
1022f4a2713aSLionel Sambuc if (kind & ObjCPropertyDecl::OBJC_PR_weak &&
1023f4a2713aSLionel Sambuc !getLangOpts().ObjCAutoRefCount &&
1024f4a2713aSLionel Sambuc getLangOpts().getGC() == LangOptions::NonGC) {
1025f4a2713aSLionel Sambuc Diag(PropertyDiagLoc, diag::error_synthesize_weak_non_arc_or_gc);
1026f4a2713aSLionel Sambuc Diag(property->getLocation(), diag::note_property_declare);
1027f4a2713aSLionel Sambuc }
1028f4a2713aSLionel Sambuc
1029f4a2713aSLionel Sambuc Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl,
1030f4a2713aSLionel Sambuc PropertyIvarLoc,PropertyIvarLoc, PropertyIvar,
1031*0a6a1f1dSLionel Sambuc PropertyIvarType, /*Dinfo=*/nullptr,
1032f4a2713aSLionel Sambuc ObjCIvarDecl::Private,
1033*0a6a1f1dSLionel Sambuc (Expr *)nullptr, true);
1034f4a2713aSLionel Sambuc if (RequireNonAbstractType(PropertyIvarLoc,
1035f4a2713aSLionel Sambuc PropertyIvarType,
1036f4a2713aSLionel Sambuc diag::err_abstract_type_in_decl,
1037f4a2713aSLionel Sambuc AbstractSynthesizedIvarType)) {
1038f4a2713aSLionel Sambuc Diag(property->getLocation(), diag::note_property_declare);
1039f4a2713aSLionel Sambuc Ivar->setInvalidDecl();
1040f4a2713aSLionel Sambuc } else if (CompleteTypeErr)
1041f4a2713aSLionel Sambuc Ivar->setInvalidDecl();
1042f4a2713aSLionel Sambuc ClassImpDecl->addDecl(Ivar);
1043f4a2713aSLionel Sambuc IDecl->makeDeclVisibleInContext(Ivar);
1044f4a2713aSLionel Sambuc
1045f4a2713aSLionel Sambuc if (getLangOpts().ObjCRuntime.isFragile())
1046f4a2713aSLionel Sambuc Diag(PropertyDiagLoc, diag::error_missing_property_ivar_decl)
1047f4a2713aSLionel Sambuc << PropertyId;
1048f4a2713aSLionel Sambuc // Note! I deliberately want it to fall thru so, we have a
1049f4a2713aSLionel Sambuc // a property implementation and to avoid future warnings.
1050f4a2713aSLionel Sambuc } else if (getLangOpts().ObjCRuntime.isNonFragile() &&
1051f4a2713aSLionel Sambuc !declaresSameEntity(ClassDeclared, IDecl)) {
1052f4a2713aSLionel Sambuc Diag(PropertyDiagLoc, diag::error_ivar_in_superclass_use)
1053f4a2713aSLionel Sambuc << property->getDeclName() << Ivar->getDeclName()
1054f4a2713aSLionel Sambuc << ClassDeclared->getDeclName();
1055f4a2713aSLionel Sambuc Diag(Ivar->getLocation(), diag::note_previous_access_declaration)
1056f4a2713aSLionel Sambuc << Ivar << Ivar->getName();
1057f4a2713aSLionel Sambuc // Note! I deliberately want it to fall thru so more errors are caught.
1058f4a2713aSLionel Sambuc }
1059f4a2713aSLionel Sambuc property->setPropertyIvarDecl(Ivar);
1060f4a2713aSLionel Sambuc
1061f4a2713aSLionel Sambuc QualType IvarType = Context.getCanonicalType(Ivar->getType());
1062f4a2713aSLionel Sambuc
1063f4a2713aSLionel Sambuc // Check that type of property and its ivar are type compatible.
1064f4a2713aSLionel Sambuc if (!Context.hasSameType(PropertyIvarType, IvarType)) {
1065f4a2713aSLionel Sambuc if (isa<ObjCObjectPointerType>(PropertyIvarType)
1066f4a2713aSLionel Sambuc && isa<ObjCObjectPointerType>(IvarType))
1067f4a2713aSLionel Sambuc compat =
1068f4a2713aSLionel Sambuc Context.canAssignObjCInterfaces(
1069f4a2713aSLionel Sambuc PropertyIvarType->getAs<ObjCObjectPointerType>(),
1070f4a2713aSLionel Sambuc IvarType->getAs<ObjCObjectPointerType>());
1071f4a2713aSLionel Sambuc else {
1072f4a2713aSLionel Sambuc compat = (CheckAssignmentConstraints(PropertyIvarLoc, PropertyIvarType,
1073f4a2713aSLionel Sambuc IvarType)
1074f4a2713aSLionel Sambuc == Compatible);
1075f4a2713aSLionel Sambuc }
1076f4a2713aSLionel Sambuc if (!compat) {
1077f4a2713aSLionel Sambuc Diag(PropertyDiagLoc, diag::error_property_ivar_type)
1078f4a2713aSLionel Sambuc << property->getDeclName() << PropType
1079f4a2713aSLionel Sambuc << Ivar->getDeclName() << IvarType;
1080f4a2713aSLionel Sambuc Diag(Ivar->getLocation(), diag::note_ivar_decl);
1081f4a2713aSLionel Sambuc // Note! I deliberately want it to fall thru so, we have a
1082f4a2713aSLionel Sambuc // a property implementation and to avoid future warnings.
1083f4a2713aSLionel Sambuc }
1084f4a2713aSLionel Sambuc else {
1085f4a2713aSLionel Sambuc // FIXME! Rules for properties are somewhat different that those
1086f4a2713aSLionel Sambuc // for assignments. Use a new routine to consolidate all cases;
1087f4a2713aSLionel Sambuc // specifically for property redeclarations as well as for ivars.
1088f4a2713aSLionel Sambuc QualType lhsType =Context.getCanonicalType(PropertyIvarType).getUnqualifiedType();
1089f4a2713aSLionel Sambuc QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType();
1090f4a2713aSLionel Sambuc if (lhsType != rhsType &&
1091f4a2713aSLionel Sambuc lhsType->isArithmeticType()) {
1092f4a2713aSLionel Sambuc Diag(PropertyDiagLoc, diag::error_property_ivar_type)
1093f4a2713aSLionel Sambuc << property->getDeclName() << PropType
1094f4a2713aSLionel Sambuc << Ivar->getDeclName() << IvarType;
1095f4a2713aSLionel Sambuc Diag(Ivar->getLocation(), diag::note_ivar_decl);
1096f4a2713aSLionel Sambuc // Fall thru - see previous comment
1097f4a2713aSLionel Sambuc }
1098f4a2713aSLionel Sambuc }
1099f4a2713aSLionel Sambuc // __weak is explicit. So it works on Canonical type.
1100f4a2713aSLionel Sambuc if ((PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() &&
1101f4a2713aSLionel Sambuc getLangOpts().getGC() != LangOptions::NonGC)) {
1102f4a2713aSLionel Sambuc Diag(PropertyDiagLoc, diag::error_weak_property)
1103f4a2713aSLionel Sambuc << property->getDeclName() << Ivar->getDeclName();
1104f4a2713aSLionel Sambuc Diag(Ivar->getLocation(), diag::note_ivar_decl);
1105f4a2713aSLionel Sambuc // Fall thru - see previous comment
1106f4a2713aSLionel Sambuc }
1107f4a2713aSLionel Sambuc // Fall thru - see previous comment
1108f4a2713aSLionel Sambuc if ((property->getType()->isObjCObjectPointerType() ||
1109f4a2713aSLionel Sambuc PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&
1110f4a2713aSLionel Sambuc getLangOpts().getGC() != LangOptions::NonGC) {
1111f4a2713aSLionel Sambuc Diag(PropertyDiagLoc, diag::error_strong_property)
1112f4a2713aSLionel Sambuc << property->getDeclName() << Ivar->getDeclName();
1113f4a2713aSLionel Sambuc // Fall thru - see previous comment
1114f4a2713aSLionel Sambuc }
1115f4a2713aSLionel Sambuc }
1116f4a2713aSLionel Sambuc if (getLangOpts().ObjCAutoRefCount)
1117f4a2713aSLionel Sambuc checkARCPropertyImpl(*this, PropertyLoc, property, Ivar);
1118f4a2713aSLionel Sambuc } else if (PropertyIvar)
1119f4a2713aSLionel Sambuc // @dynamic
1120f4a2713aSLionel Sambuc Diag(PropertyDiagLoc, diag::error_dynamic_property_ivar_decl);
1121f4a2713aSLionel Sambuc
1122f4a2713aSLionel Sambuc assert (property && "ActOnPropertyImplDecl - property declaration missing");
1123f4a2713aSLionel Sambuc ObjCPropertyImplDecl *PIDecl =
1124f4a2713aSLionel Sambuc ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc,
1125f4a2713aSLionel Sambuc property,
1126f4a2713aSLionel Sambuc (Synthesize ?
1127f4a2713aSLionel Sambuc ObjCPropertyImplDecl::Synthesize
1128f4a2713aSLionel Sambuc : ObjCPropertyImplDecl::Dynamic),
1129f4a2713aSLionel Sambuc Ivar, PropertyIvarLoc);
1130f4a2713aSLionel Sambuc
1131f4a2713aSLionel Sambuc if (CompleteTypeErr || !compat)
1132f4a2713aSLionel Sambuc PIDecl->setInvalidDecl();
1133f4a2713aSLionel Sambuc
1134f4a2713aSLionel Sambuc if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) {
1135f4a2713aSLionel Sambuc getterMethod->createImplicitParams(Context, IDecl);
1136f4a2713aSLionel Sambuc if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr &&
1137f4a2713aSLionel Sambuc Ivar->getType()->isRecordType()) {
1138f4a2713aSLionel Sambuc // For Objective-C++, need to synthesize the AST for the IVAR object to be
1139f4a2713aSLionel Sambuc // returned by the getter as it must conform to C++'s copy-return rules.
1140f4a2713aSLionel Sambuc // FIXME. Eventually we want to do this for Objective-C as well.
1141f4a2713aSLionel Sambuc SynthesizedFunctionScope Scope(*this, getterMethod);
1142f4a2713aSLionel Sambuc ImplicitParamDecl *SelfDecl = getterMethod->getSelfDecl();
1143f4a2713aSLionel Sambuc DeclRefExpr *SelfExpr =
1144f4a2713aSLionel Sambuc new (Context) DeclRefExpr(SelfDecl, false, SelfDecl->getType(),
1145*0a6a1f1dSLionel Sambuc VK_LValue, PropertyDiagLoc);
1146f4a2713aSLionel Sambuc MarkDeclRefReferenced(SelfExpr);
1147*0a6a1f1dSLionel Sambuc Expr *LoadSelfExpr =
1148*0a6a1f1dSLionel Sambuc ImplicitCastExpr::Create(Context, SelfDecl->getType(),
1149*0a6a1f1dSLionel Sambuc CK_LValueToRValue, SelfExpr, nullptr,
1150*0a6a1f1dSLionel Sambuc VK_RValue);
1151f4a2713aSLionel Sambuc Expr *IvarRefExpr =
1152f4a2713aSLionel Sambuc new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc,
1153f4a2713aSLionel Sambuc Ivar->getLocation(),
1154*0a6a1f1dSLionel Sambuc LoadSelfExpr, true, true);
1155*0a6a1f1dSLionel Sambuc ExprResult Res = PerformCopyInitialization(
1156*0a6a1f1dSLionel Sambuc InitializedEntity::InitializeResult(PropertyDiagLoc,
1157*0a6a1f1dSLionel Sambuc getterMethod->getReturnType(),
1158f4a2713aSLionel Sambuc /*NRVO=*/false),
1159*0a6a1f1dSLionel Sambuc PropertyDiagLoc, IvarRefExpr);
1160f4a2713aSLionel Sambuc if (!Res.isInvalid()) {
1161*0a6a1f1dSLionel Sambuc Expr *ResExpr = Res.getAs<Expr>();
1162f4a2713aSLionel Sambuc if (ResExpr)
1163f4a2713aSLionel Sambuc ResExpr = MaybeCreateExprWithCleanups(ResExpr);
1164f4a2713aSLionel Sambuc PIDecl->setGetterCXXConstructor(ResExpr);
1165f4a2713aSLionel Sambuc }
1166f4a2713aSLionel Sambuc }
1167f4a2713aSLionel Sambuc if (property->hasAttr<NSReturnsNotRetainedAttr>() &&
1168f4a2713aSLionel Sambuc !getterMethod->hasAttr<NSReturnsNotRetainedAttr>()) {
1169f4a2713aSLionel Sambuc Diag(getterMethod->getLocation(),
1170f4a2713aSLionel Sambuc diag::warn_property_getter_owning_mismatch);
1171f4a2713aSLionel Sambuc Diag(property->getLocation(), diag::note_property_declare);
1172f4a2713aSLionel Sambuc }
1173f4a2713aSLionel Sambuc if (getLangOpts().ObjCAutoRefCount && Synthesize)
1174f4a2713aSLionel Sambuc switch (getterMethod->getMethodFamily()) {
1175f4a2713aSLionel Sambuc case OMF_retain:
1176f4a2713aSLionel Sambuc case OMF_retainCount:
1177f4a2713aSLionel Sambuc case OMF_release:
1178f4a2713aSLionel Sambuc case OMF_autorelease:
1179f4a2713aSLionel Sambuc Diag(getterMethod->getLocation(), diag::err_arc_illegal_method_def)
1180f4a2713aSLionel Sambuc << 1 << getterMethod->getSelector();
1181f4a2713aSLionel Sambuc break;
1182f4a2713aSLionel Sambuc default:
1183f4a2713aSLionel Sambuc break;
1184f4a2713aSLionel Sambuc }
1185f4a2713aSLionel Sambuc }
1186f4a2713aSLionel Sambuc if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) {
1187f4a2713aSLionel Sambuc setterMethod->createImplicitParams(Context, IDecl);
1188f4a2713aSLionel Sambuc if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr &&
1189f4a2713aSLionel Sambuc Ivar->getType()->isRecordType()) {
1190f4a2713aSLionel Sambuc // FIXME. Eventually we want to do this for Objective-C as well.
1191f4a2713aSLionel Sambuc SynthesizedFunctionScope Scope(*this, setterMethod);
1192f4a2713aSLionel Sambuc ImplicitParamDecl *SelfDecl = setterMethod->getSelfDecl();
1193f4a2713aSLionel Sambuc DeclRefExpr *SelfExpr =
1194f4a2713aSLionel Sambuc new (Context) DeclRefExpr(SelfDecl, false, SelfDecl->getType(),
1195*0a6a1f1dSLionel Sambuc VK_LValue, PropertyDiagLoc);
1196f4a2713aSLionel Sambuc MarkDeclRefReferenced(SelfExpr);
1197*0a6a1f1dSLionel Sambuc Expr *LoadSelfExpr =
1198*0a6a1f1dSLionel Sambuc ImplicitCastExpr::Create(Context, SelfDecl->getType(),
1199*0a6a1f1dSLionel Sambuc CK_LValueToRValue, SelfExpr, nullptr,
1200*0a6a1f1dSLionel Sambuc VK_RValue);
1201f4a2713aSLionel Sambuc Expr *lhs =
1202f4a2713aSLionel Sambuc new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc,
1203f4a2713aSLionel Sambuc Ivar->getLocation(),
1204*0a6a1f1dSLionel Sambuc LoadSelfExpr, true, true);
1205f4a2713aSLionel Sambuc ObjCMethodDecl::param_iterator P = setterMethod->param_begin();
1206f4a2713aSLionel Sambuc ParmVarDecl *Param = (*P);
1207f4a2713aSLionel Sambuc QualType T = Param->getType().getNonReferenceType();
1208f4a2713aSLionel Sambuc DeclRefExpr *rhs = new (Context) DeclRefExpr(Param, false, T,
1209f4a2713aSLionel Sambuc VK_LValue, PropertyDiagLoc);
1210f4a2713aSLionel Sambuc MarkDeclRefReferenced(rhs);
1211f4a2713aSLionel Sambuc ExprResult Res = BuildBinOp(S, PropertyDiagLoc,
1212f4a2713aSLionel Sambuc BO_Assign, lhs, rhs);
1213f4a2713aSLionel Sambuc if (property->getPropertyAttributes() &
1214f4a2713aSLionel Sambuc ObjCPropertyDecl::OBJC_PR_atomic) {
1215*0a6a1f1dSLionel Sambuc Expr *callExpr = Res.getAs<Expr>();
1216f4a2713aSLionel Sambuc if (const CXXOperatorCallExpr *CXXCE =
1217f4a2713aSLionel Sambuc dyn_cast_or_null<CXXOperatorCallExpr>(callExpr))
1218f4a2713aSLionel Sambuc if (const FunctionDecl *FuncDecl = CXXCE->getDirectCallee())
1219f4a2713aSLionel Sambuc if (!FuncDecl->isTrivial())
1220f4a2713aSLionel Sambuc if (property->getType()->isReferenceType()) {
1221f4a2713aSLionel Sambuc Diag(PropertyDiagLoc,
1222f4a2713aSLionel Sambuc diag::err_atomic_property_nontrivial_assign_op)
1223f4a2713aSLionel Sambuc << property->getType();
1224f4a2713aSLionel Sambuc Diag(FuncDecl->getLocStart(),
1225f4a2713aSLionel Sambuc diag::note_callee_decl) << FuncDecl;
1226f4a2713aSLionel Sambuc }
1227f4a2713aSLionel Sambuc }
1228*0a6a1f1dSLionel Sambuc PIDecl->setSetterCXXAssignment(Res.getAs<Expr>());
1229f4a2713aSLionel Sambuc }
1230f4a2713aSLionel Sambuc }
1231f4a2713aSLionel Sambuc
1232f4a2713aSLionel Sambuc if (IC) {
1233f4a2713aSLionel Sambuc if (Synthesize)
1234f4a2713aSLionel Sambuc if (ObjCPropertyImplDecl *PPIDecl =
1235f4a2713aSLionel Sambuc IC->FindPropertyImplIvarDecl(PropertyIvar)) {
1236f4a2713aSLionel Sambuc Diag(PropertyLoc, diag::error_duplicate_ivar_use)
1237f4a2713aSLionel Sambuc << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
1238f4a2713aSLionel Sambuc << PropertyIvar;
1239f4a2713aSLionel Sambuc Diag(PPIDecl->getLocation(), diag::note_previous_use);
1240f4a2713aSLionel Sambuc }
1241f4a2713aSLionel Sambuc
1242f4a2713aSLionel Sambuc if (ObjCPropertyImplDecl *PPIDecl
1243f4a2713aSLionel Sambuc = IC->FindPropertyImplDecl(PropertyId)) {
1244f4a2713aSLionel Sambuc Diag(PropertyLoc, diag::error_property_implemented) << PropertyId;
1245f4a2713aSLionel Sambuc Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
1246*0a6a1f1dSLionel Sambuc return nullptr;
1247f4a2713aSLionel Sambuc }
1248f4a2713aSLionel Sambuc IC->addPropertyImplementation(PIDecl);
1249f4a2713aSLionel Sambuc if (getLangOpts().ObjCDefaultSynthProperties &&
1250f4a2713aSLionel Sambuc getLangOpts().ObjCRuntime.isNonFragile() &&
1251f4a2713aSLionel Sambuc !IDecl->isObjCRequiresPropertyDefs()) {
1252f4a2713aSLionel Sambuc // Diagnose if an ivar was lazily synthesdized due to a previous
1253f4a2713aSLionel Sambuc // use and if 1) property is @dynamic or 2) property is synthesized
1254f4a2713aSLionel Sambuc // but it requires an ivar of different name.
1255*0a6a1f1dSLionel Sambuc ObjCInterfaceDecl *ClassDeclared=nullptr;
1256*0a6a1f1dSLionel Sambuc ObjCIvarDecl *Ivar = nullptr;
1257f4a2713aSLionel Sambuc if (!Synthesize)
1258f4a2713aSLionel Sambuc Ivar = IDecl->lookupInstanceVariable(PropertyId, ClassDeclared);
1259f4a2713aSLionel Sambuc else {
1260f4a2713aSLionel Sambuc if (PropertyIvar && PropertyIvar != PropertyId)
1261f4a2713aSLionel Sambuc Ivar = IDecl->lookupInstanceVariable(PropertyId, ClassDeclared);
1262f4a2713aSLionel Sambuc }
1263f4a2713aSLionel Sambuc // Issue diagnostics only if Ivar belongs to current class.
1264f4a2713aSLionel Sambuc if (Ivar && Ivar->getSynthesize() &&
1265f4a2713aSLionel Sambuc declaresSameEntity(IC->getClassInterface(), ClassDeclared)) {
1266f4a2713aSLionel Sambuc Diag(Ivar->getLocation(), diag::err_undeclared_var_use)
1267f4a2713aSLionel Sambuc << PropertyId;
1268f4a2713aSLionel Sambuc Ivar->setInvalidDecl();
1269f4a2713aSLionel Sambuc }
1270f4a2713aSLionel Sambuc }
1271f4a2713aSLionel Sambuc } else {
1272f4a2713aSLionel Sambuc if (Synthesize)
1273f4a2713aSLionel Sambuc if (ObjCPropertyImplDecl *PPIDecl =
1274f4a2713aSLionel Sambuc CatImplClass->FindPropertyImplIvarDecl(PropertyIvar)) {
1275f4a2713aSLionel Sambuc Diag(PropertyDiagLoc, diag::error_duplicate_ivar_use)
1276f4a2713aSLionel Sambuc << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
1277f4a2713aSLionel Sambuc << PropertyIvar;
1278f4a2713aSLionel Sambuc Diag(PPIDecl->getLocation(), diag::note_previous_use);
1279f4a2713aSLionel Sambuc }
1280f4a2713aSLionel Sambuc
1281f4a2713aSLionel Sambuc if (ObjCPropertyImplDecl *PPIDecl =
1282f4a2713aSLionel Sambuc CatImplClass->FindPropertyImplDecl(PropertyId)) {
1283f4a2713aSLionel Sambuc Diag(PropertyDiagLoc, diag::error_property_implemented) << PropertyId;
1284f4a2713aSLionel Sambuc Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
1285*0a6a1f1dSLionel Sambuc return nullptr;
1286f4a2713aSLionel Sambuc }
1287f4a2713aSLionel Sambuc CatImplClass->addPropertyImplementation(PIDecl);
1288f4a2713aSLionel Sambuc }
1289f4a2713aSLionel Sambuc
1290f4a2713aSLionel Sambuc return PIDecl;
1291f4a2713aSLionel Sambuc }
1292f4a2713aSLionel Sambuc
1293f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
1294f4a2713aSLionel Sambuc // Helper methods.
1295f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
1296f4a2713aSLionel Sambuc
1297f4a2713aSLionel Sambuc /// DiagnosePropertyMismatch - Compares two properties for their
1298f4a2713aSLionel Sambuc /// attributes and types and warns on a variety of inconsistencies.
1299f4a2713aSLionel Sambuc ///
1300f4a2713aSLionel Sambuc void
DiagnosePropertyMismatch(ObjCPropertyDecl * Property,ObjCPropertyDecl * SuperProperty,const IdentifierInfo * inheritedName,bool OverridingProtocolProperty)1301f4a2713aSLionel Sambuc Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
1302f4a2713aSLionel Sambuc ObjCPropertyDecl *SuperProperty,
1303f4a2713aSLionel Sambuc const IdentifierInfo *inheritedName,
1304f4a2713aSLionel Sambuc bool OverridingProtocolProperty) {
1305f4a2713aSLionel Sambuc ObjCPropertyDecl::PropertyAttributeKind CAttr =
1306f4a2713aSLionel Sambuc Property->getPropertyAttributes();
1307f4a2713aSLionel Sambuc ObjCPropertyDecl::PropertyAttributeKind SAttr =
1308f4a2713aSLionel Sambuc SuperProperty->getPropertyAttributes();
1309f4a2713aSLionel Sambuc
1310f4a2713aSLionel Sambuc // We allow readonly properties without an explicit ownership
1311f4a2713aSLionel Sambuc // (assign/unsafe_unretained/weak/retain/strong/copy) in super class
1312f4a2713aSLionel Sambuc // to be overridden by a property with any explicit ownership in the subclass.
1313f4a2713aSLionel Sambuc if (!OverridingProtocolProperty &&
1314f4a2713aSLionel Sambuc !getOwnershipRule(SAttr) && getOwnershipRule(CAttr))
1315f4a2713aSLionel Sambuc ;
1316f4a2713aSLionel Sambuc else {
1317f4a2713aSLionel Sambuc if ((CAttr & ObjCPropertyDecl::OBJC_PR_readonly)
1318f4a2713aSLionel Sambuc && (SAttr & ObjCPropertyDecl::OBJC_PR_readwrite))
1319f4a2713aSLionel Sambuc Diag(Property->getLocation(), diag::warn_readonly_property)
1320f4a2713aSLionel Sambuc << Property->getDeclName() << inheritedName;
1321f4a2713aSLionel Sambuc if ((CAttr & ObjCPropertyDecl::OBJC_PR_copy)
1322f4a2713aSLionel Sambuc != (SAttr & ObjCPropertyDecl::OBJC_PR_copy))
1323f4a2713aSLionel Sambuc Diag(Property->getLocation(), diag::warn_property_attribute)
1324f4a2713aSLionel Sambuc << Property->getDeclName() << "copy" << inheritedName;
1325f4a2713aSLionel Sambuc else if (!(SAttr & ObjCPropertyDecl::OBJC_PR_readonly)){
1326f4a2713aSLionel Sambuc unsigned CAttrRetain =
1327f4a2713aSLionel Sambuc (CAttr &
1328f4a2713aSLionel Sambuc (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong));
1329f4a2713aSLionel Sambuc unsigned SAttrRetain =
1330f4a2713aSLionel Sambuc (SAttr &
1331f4a2713aSLionel Sambuc (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong));
1332f4a2713aSLionel Sambuc bool CStrong = (CAttrRetain != 0);
1333f4a2713aSLionel Sambuc bool SStrong = (SAttrRetain != 0);
1334f4a2713aSLionel Sambuc if (CStrong != SStrong)
1335f4a2713aSLionel Sambuc Diag(Property->getLocation(), diag::warn_property_attribute)
1336f4a2713aSLionel Sambuc << Property->getDeclName() << "retain (or strong)" << inheritedName;
1337f4a2713aSLionel Sambuc }
1338f4a2713aSLionel Sambuc }
1339f4a2713aSLionel Sambuc
1340f4a2713aSLionel Sambuc if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)
1341f4a2713aSLionel Sambuc != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)) {
1342f4a2713aSLionel Sambuc Diag(Property->getLocation(), diag::warn_property_attribute)
1343f4a2713aSLionel Sambuc << Property->getDeclName() << "atomic" << inheritedName;
1344f4a2713aSLionel Sambuc Diag(SuperProperty->getLocation(), diag::note_property_declare);
1345f4a2713aSLionel Sambuc }
1346f4a2713aSLionel Sambuc if (Property->getSetterName() != SuperProperty->getSetterName()) {
1347f4a2713aSLionel Sambuc Diag(Property->getLocation(), diag::warn_property_attribute)
1348f4a2713aSLionel Sambuc << Property->getDeclName() << "setter" << inheritedName;
1349f4a2713aSLionel Sambuc Diag(SuperProperty->getLocation(), diag::note_property_declare);
1350f4a2713aSLionel Sambuc }
1351f4a2713aSLionel Sambuc if (Property->getGetterName() != SuperProperty->getGetterName()) {
1352f4a2713aSLionel Sambuc Diag(Property->getLocation(), diag::warn_property_attribute)
1353f4a2713aSLionel Sambuc << Property->getDeclName() << "getter" << inheritedName;
1354f4a2713aSLionel Sambuc Diag(SuperProperty->getLocation(), diag::note_property_declare);
1355f4a2713aSLionel Sambuc }
1356f4a2713aSLionel Sambuc
1357f4a2713aSLionel Sambuc QualType LHSType =
1358f4a2713aSLionel Sambuc Context.getCanonicalType(SuperProperty->getType());
1359f4a2713aSLionel Sambuc QualType RHSType =
1360f4a2713aSLionel Sambuc Context.getCanonicalType(Property->getType());
1361f4a2713aSLionel Sambuc
1362f4a2713aSLionel Sambuc if (!Context.propertyTypesAreCompatible(LHSType, RHSType)) {
1363f4a2713aSLionel Sambuc // Do cases not handled in above.
1364f4a2713aSLionel Sambuc // FIXME. For future support of covariant property types, revisit this.
1365f4a2713aSLionel Sambuc bool IncompatibleObjC = false;
1366f4a2713aSLionel Sambuc QualType ConvertedType;
1367f4a2713aSLionel Sambuc if (!isObjCPointerConversion(RHSType, LHSType,
1368f4a2713aSLionel Sambuc ConvertedType, IncompatibleObjC) ||
1369f4a2713aSLionel Sambuc IncompatibleObjC) {
1370f4a2713aSLionel Sambuc Diag(Property->getLocation(), diag::warn_property_types_are_incompatible)
1371f4a2713aSLionel Sambuc << Property->getType() << SuperProperty->getType() << inheritedName;
1372f4a2713aSLionel Sambuc Diag(SuperProperty->getLocation(), diag::note_property_declare);
1373f4a2713aSLionel Sambuc }
1374f4a2713aSLionel Sambuc }
1375f4a2713aSLionel Sambuc }
1376f4a2713aSLionel Sambuc
DiagnosePropertyAccessorMismatch(ObjCPropertyDecl * property,ObjCMethodDecl * GetterMethod,SourceLocation Loc)1377f4a2713aSLionel Sambuc bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
1378f4a2713aSLionel Sambuc ObjCMethodDecl *GetterMethod,
1379f4a2713aSLionel Sambuc SourceLocation Loc) {
1380f4a2713aSLionel Sambuc if (!GetterMethod)
1381f4a2713aSLionel Sambuc return false;
1382*0a6a1f1dSLionel Sambuc QualType GetterType = GetterMethod->getReturnType().getNonReferenceType();
1383f4a2713aSLionel Sambuc QualType PropertyIvarType = property->getType().getNonReferenceType();
1384f4a2713aSLionel Sambuc bool compat = Context.hasSameType(PropertyIvarType, GetterType);
1385f4a2713aSLionel Sambuc if (!compat) {
1386f4a2713aSLionel Sambuc if (isa<ObjCObjectPointerType>(PropertyIvarType) &&
1387f4a2713aSLionel Sambuc isa<ObjCObjectPointerType>(GetterType))
1388f4a2713aSLionel Sambuc compat =
1389f4a2713aSLionel Sambuc Context.canAssignObjCInterfaces(
1390f4a2713aSLionel Sambuc GetterType->getAs<ObjCObjectPointerType>(),
1391f4a2713aSLionel Sambuc PropertyIvarType->getAs<ObjCObjectPointerType>());
1392f4a2713aSLionel Sambuc else if (CheckAssignmentConstraints(Loc, GetterType, PropertyIvarType)
1393f4a2713aSLionel Sambuc != Compatible) {
1394f4a2713aSLionel Sambuc Diag(Loc, diag::error_property_accessor_type)
1395f4a2713aSLionel Sambuc << property->getDeclName() << PropertyIvarType
1396f4a2713aSLionel Sambuc << GetterMethod->getSelector() << GetterType;
1397f4a2713aSLionel Sambuc Diag(GetterMethod->getLocation(), diag::note_declared_at);
1398f4a2713aSLionel Sambuc return true;
1399f4a2713aSLionel Sambuc } else {
1400f4a2713aSLionel Sambuc compat = true;
1401f4a2713aSLionel Sambuc QualType lhsType =Context.getCanonicalType(PropertyIvarType).getUnqualifiedType();
1402f4a2713aSLionel Sambuc QualType rhsType =Context.getCanonicalType(GetterType).getUnqualifiedType();
1403f4a2713aSLionel Sambuc if (lhsType != rhsType && lhsType->isArithmeticType())
1404f4a2713aSLionel Sambuc compat = false;
1405f4a2713aSLionel Sambuc }
1406f4a2713aSLionel Sambuc }
1407f4a2713aSLionel Sambuc
1408f4a2713aSLionel Sambuc if (!compat) {
1409f4a2713aSLionel Sambuc Diag(Loc, diag::warn_accessor_property_type_mismatch)
1410f4a2713aSLionel Sambuc << property->getDeclName()
1411f4a2713aSLionel Sambuc << GetterMethod->getSelector();
1412f4a2713aSLionel Sambuc Diag(GetterMethod->getLocation(), diag::note_declared_at);
1413f4a2713aSLionel Sambuc return true;
1414f4a2713aSLionel Sambuc }
1415f4a2713aSLionel Sambuc
1416f4a2713aSLionel Sambuc return false;
1417f4a2713aSLionel Sambuc }
1418f4a2713aSLionel Sambuc
1419f4a2713aSLionel Sambuc /// CollectImmediateProperties - This routine collects all properties in
1420f4a2713aSLionel Sambuc /// the class and its conforming protocols; but not those in its super class.
CollectImmediateProperties(ObjCContainerDecl * CDecl,ObjCContainerDecl::PropertyMap & PropMap,ObjCContainerDecl::PropertyMap & SuperPropMap,bool IncludeProtocols=true)1421*0a6a1f1dSLionel Sambuc static void CollectImmediateProperties(ObjCContainerDecl *CDecl,
1422f4a2713aSLionel Sambuc ObjCContainerDecl::PropertyMap &PropMap,
1423*0a6a1f1dSLionel Sambuc ObjCContainerDecl::PropertyMap &SuperPropMap,
1424*0a6a1f1dSLionel Sambuc bool IncludeProtocols = true) {
1425*0a6a1f1dSLionel Sambuc
1426f4a2713aSLionel Sambuc if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
1427*0a6a1f1dSLionel Sambuc for (auto *Prop : IDecl->properties())
1428f4a2713aSLionel Sambuc PropMap[Prop->getIdentifier()] = Prop;
1429*0a6a1f1dSLionel Sambuc if (IncludeProtocols) {
1430*0a6a1f1dSLionel Sambuc // Scan through class's protocols.
1431*0a6a1f1dSLionel Sambuc for (auto *PI : IDecl->all_referenced_protocols())
1432*0a6a1f1dSLionel Sambuc CollectImmediateProperties(PI, PropMap, SuperPropMap);
1433f4a2713aSLionel Sambuc }
1434f4a2713aSLionel Sambuc }
1435f4a2713aSLionel Sambuc if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
1436f4a2713aSLionel Sambuc if (!CATDecl->IsClassExtension())
1437*0a6a1f1dSLionel Sambuc for (auto *Prop : CATDecl->properties())
1438f4a2713aSLionel Sambuc PropMap[Prop->getIdentifier()] = Prop;
1439*0a6a1f1dSLionel Sambuc if (IncludeProtocols) {
1440*0a6a1f1dSLionel Sambuc // Scan through class's protocols.
1441*0a6a1f1dSLionel Sambuc for (auto *PI : CATDecl->protocols())
1442*0a6a1f1dSLionel Sambuc CollectImmediateProperties(PI, PropMap, SuperPropMap);
1443f4a2713aSLionel Sambuc }
1444f4a2713aSLionel Sambuc }
1445f4a2713aSLionel Sambuc else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) {
1446*0a6a1f1dSLionel Sambuc for (auto *Prop : PDecl->properties()) {
1447f4a2713aSLionel Sambuc ObjCPropertyDecl *PropertyFromSuper = SuperPropMap[Prop->getIdentifier()];
1448f4a2713aSLionel Sambuc // Exclude property for protocols which conform to class's super-class,
1449f4a2713aSLionel Sambuc // as super-class has to implement the property.
1450f4a2713aSLionel Sambuc if (!PropertyFromSuper ||
1451f4a2713aSLionel Sambuc PropertyFromSuper->getIdentifier() != Prop->getIdentifier()) {
1452f4a2713aSLionel Sambuc ObjCPropertyDecl *&PropEntry = PropMap[Prop->getIdentifier()];
1453f4a2713aSLionel Sambuc if (!PropEntry)
1454f4a2713aSLionel Sambuc PropEntry = Prop;
1455f4a2713aSLionel Sambuc }
1456f4a2713aSLionel Sambuc }
1457f4a2713aSLionel Sambuc // scan through protocol's protocols.
1458*0a6a1f1dSLionel Sambuc for (auto *PI : PDecl->protocols())
1459*0a6a1f1dSLionel Sambuc CollectImmediateProperties(PI, PropMap, SuperPropMap);
1460f4a2713aSLionel Sambuc }
1461f4a2713aSLionel Sambuc }
1462f4a2713aSLionel Sambuc
1463f4a2713aSLionel Sambuc /// CollectSuperClassPropertyImplementations - This routine collects list of
1464f4a2713aSLionel Sambuc /// properties to be implemented in super class(s) and also coming from their
1465f4a2713aSLionel Sambuc /// conforming protocols.
CollectSuperClassPropertyImplementations(ObjCInterfaceDecl * CDecl,ObjCInterfaceDecl::PropertyMap & PropMap)1466f4a2713aSLionel Sambuc static void CollectSuperClassPropertyImplementations(ObjCInterfaceDecl *CDecl,
1467f4a2713aSLionel Sambuc ObjCInterfaceDecl::PropertyMap &PropMap) {
1468f4a2713aSLionel Sambuc if (ObjCInterfaceDecl *SDecl = CDecl->getSuperClass()) {
1469f4a2713aSLionel Sambuc ObjCInterfaceDecl::PropertyDeclOrder PO;
1470f4a2713aSLionel Sambuc while (SDecl) {
1471f4a2713aSLionel Sambuc SDecl->collectPropertiesToImplement(PropMap, PO);
1472f4a2713aSLionel Sambuc SDecl = SDecl->getSuperClass();
1473f4a2713aSLionel Sambuc }
1474f4a2713aSLionel Sambuc }
1475f4a2713aSLionel Sambuc }
1476f4a2713aSLionel Sambuc
1477f4a2713aSLionel Sambuc /// IvarBacksCurrentMethodAccessor - This routine returns 'true' if 'IV' is
1478f4a2713aSLionel Sambuc /// an ivar synthesized for 'Method' and 'Method' is a property accessor
1479f4a2713aSLionel Sambuc /// declared in class 'IFace'.
1480f4a2713aSLionel Sambuc bool
IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl * IFace,ObjCMethodDecl * Method,ObjCIvarDecl * IV)1481f4a2713aSLionel Sambuc Sema::IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace,
1482f4a2713aSLionel Sambuc ObjCMethodDecl *Method, ObjCIvarDecl *IV) {
1483f4a2713aSLionel Sambuc if (!IV->getSynthesize())
1484f4a2713aSLionel Sambuc return false;
1485f4a2713aSLionel Sambuc ObjCMethodDecl *IMD = IFace->lookupMethod(Method->getSelector(),
1486f4a2713aSLionel Sambuc Method->isInstanceMethod());
1487f4a2713aSLionel Sambuc if (!IMD || !IMD->isPropertyAccessor())
1488f4a2713aSLionel Sambuc return false;
1489f4a2713aSLionel Sambuc
1490f4a2713aSLionel Sambuc // look up a property declaration whose one of its accessors is implemented
1491f4a2713aSLionel Sambuc // by this method.
1492*0a6a1f1dSLionel Sambuc for (const auto *Property : IFace->properties()) {
1493*0a6a1f1dSLionel Sambuc if ((Property->getGetterName() == IMD->getSelector() ||
1494*0a6a1f1dSLionel Sambuc Property->getSetterName() == IMD->getSelector()) &&
1495*0a6a1f1dSLionel Sambuc (Property->getPropertyIvarDecl() == IV))
1496f4a2713aSLionel Sambuc return true;
1497f4a2713aSLionel Sambuc }
1498f4a2713aSLionel Sambuc return false;
1499f4a2713aSLionel Sambuc }
1500f4a2713aSLionel Sambuc
SuperClassImplementsProperty(ObjCInterfaceDecl * IDecl,ObjCPropertyDecl * Prop)1501*0a6a1f1dSLionel Sambuc static bool SuperClassImplementsProperty(ObjCInterfaceDecl *IDecl,
1502*0a6a1f1dSLionel Sambuc ObjCPropertyDecl *Prop) {
1503*0a6a1f1dSLionel Sambuc bool SuperClassImplementsGetter = false;
1504*0a6a1f1dSLionel Sambuc bool SuperClassImplementsSetter = false;
1505*0a6a1f1dSLionel Sambuc if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly)
1506*0a6a1f1dSLionel Sambuc SuperClassImplementsSetter = true;
1507*0a6a1f1dSLionel Sambuc
1508*0a6a1f1dSLionel Sambuc while (IDecl->getSuperClass()) {
1509*0a6a1f1dSLionel Sambuc ObjCInterfaceDecl *SDecl = IDecl->getSuperClass();
1510*0a6a1f1dSLionel Sambuc if (!SuperClassImplementsGetter && SDecl->getInstanceMethod(Prop->getGetterName()))
1511*0a6a1f1dSLionel Sambuc SuperClassImplementsGetter = true;
1512*0a6a1f1dSLionel Sambuc
1513*0a6a1f1dSLionel Sambuc if (!SuperClassImplementsSetter && SDecl->getInstanceMethod(Prop->getSetterName()))
1514*0a6a1f1dSLionel Sambuc SuperClassImplementsSetter = true;
1515*0a6a1f1dSLionel Sambuc if (SuperClassImplementsGetter && SuperClassImplementsSetter)
1516*0a6a1f1dSLionel Sambuc return true;
1517*0a6a1f1dSLionel Sambuc IDecl = IDecl->getSuperClass();
1518*0a6a1f1dSLionel Sambuc }
1519*0a6a1f1dSLionel Sambuc return false;
1520*0a6a1f1dSLionel Sambuc }
1521f4a2713aSLionel Sambuc
1522f4a2713aSLionel Sambuc /// \brief Default synthesizes all properties which must be synthesized
1523f4a2713aSLionel Sambuc /// in class's \@implementation.
DefaultSynthesizeProperties(Scope * S,ObjCImplDecl * IMPDecl,ObjCInterfaceDecl * IDecl)1524f4a2713aSLionel Sambuc void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
1525f4a2713aSLionel Sambuc ObjCInterfaceDecl *IDecl) {
1526f4a2713aSLionel Sambuc
1527f4a2713aSLionel Sambuc ObjCInterfaceDecl::PropertyMap PropMap;
1528f4a2713aSLionel Sambuc ObjCInterfaceDecl::PropertyDeclOrder PropertyOrder;
1529f4a2713aSLionel Sambuc IDecl->collectPropertiesToImplement(PropMap, PropertyOrder);
1530f4a2713aSLionel Sambuc if (PropMap.empty())
1531f4a2713aSLionel Sambuc return;
1532f4a2713aSLionel Sambuc ObjCInterfaceDecl::PropertyMap SuperPropMap;
1533f4a2713aSLionel Sambuc CollectSuperClassPropertyImplementations(IDecl, SuperPropMap);
1534f4a2713aSLionel Sambuc
1535f4a2713aSLionel Sambuc for (unsigned i = 0, e = PropertyOrder.size(); i != e; i++) {
1536f4a2713aSLionel Sambuc ObjCPropertyDecl *Prop = PropertyOrder[i];
1537f4a2713aSLionel Sambuc // Is there a matching property synthesize/dynamic?
1538f4a2713aSLionel Sambuc if (Prop->isInvalidDecl() ||
1539f4a2713aSLionel Sambuc Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional)
1540f4a2713aSLionel Sambuc continue;
1541f4a2713aSLionel Sambuc // Property may have been synthesized by user.
1542f4a2713aSLionel Sambuc if (IMPDecl->FindPropertyImplDecl(Prop->getIdentifier()))
1543f4a2713aSLionel Sambuc continue;
1544f4a2713aSLionel Sambuc if (IMPDecl->getInstanceMethod(Prop->getGetterName())) {
1545f4a2713aSLionel Sambuc if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly)
1546f4a2713aSLionel Sambuc continue;
1547f4a2713aSLionel Sambuc if (IMPDecl->getInstanceMethod(Prop->getSetterName()))
1548f4a2713aSLionel Sambuc continue;
1549f4a2713aSLionel Sambuc }
1550*0a6a1f1dSLionel Sambuc if (ObjCPropertyImplDecl *PID =
1551*0a6a1f1dSLionel Sambuc IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier())) {
1552*0a6a1f1dSLionel Sambuc Diag(Prop->getLocation(), diag::warn_no_autosynthesis_shared_ivar_property)
1553*0a6a1f1dSLionel Sambuc << Prop->getIdentifier();
1554*0a6a1f1dSLionel Sambuc if (!PID->getLocation().isInvalid())
1555*0a6a1f1dSLionel Sambuc Diag(PID->getLocation(), diag::note_property_synthesize);
1556*0a6a1f1dSLionel Sambuc continue;
1557*0a6a1f1dSLionel Sambuc }
1558f4a2713aSLionel Sambuc ObjCPropertyDecl *PropInSuperClass = SuperPropMap[Prop->getIdentifier()];
1559*0a6a1f1dSLionel Sambuc if (ObjCProtocolDecl *Proto =
1560*0a6a1f1dSLionel Sambuc dyn_cast<ObjCProtocolDecl>(Prop->getDeclContext())) {
1561*0a6a1f1dSLionel Sambuc // We won't auto-synthesize properties declared in protocols.
1562*0a6a1f1dSLionel Sambuc // Suppress the warning if class's superclass implements property's
1563*0a6a1f1dSLionel Sambuc // getter and implements property's setter (if readwrite property).
1564*0a6a1f1dSLionel Sambuc // Or, if property is going to be implemented in its super class.
1565*0a6a1f1dSLionel Sambuc if (!SuperClassImplementsProperty(IDecl, Prop) && !PropInSuperClass) {
1566*0a6a1f1dSLionel Sambuc Diag(IMPDecl->getLocation(),
1567*0a6a1f1dSLionel Sambuc diag::warn_auto_synthesizing_protocol_property)
1568*0a6a1f1dSLionel Sambuc << Prop << Proto;
1569*0a6a1f1dSLionel Sambuc Diag(Prop->getLocation(), diag::note_property_declare);
1570*0a6a1f1dSLionel Sambuc }
1571*0a6a1f1dSLionel Sambuc continue;
1572*0a6a1f1dSLionel Sambuc }
1573*0a6a1f1dSLionel Sambuc // If property to be implemented in the super class, ignore.
1574*0a6a1f1dSLionel Sambuc if (PropInSuperClass) {
1575f4a2713aSLionel Sambuc if ((Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite) &&
1576f4a2713aSLionel Sambuc (PropInSuperClass->getPropertyAttributes() &
1577f4a2713aSLionel Sambuc ObjCPropertyDecl::OBJC_PR_readonly) &&
1578f4a2713aSLionel Sambuc !IMPDecl->getInstanceMethod(Prop->getSetterName()) &&
1579f4a2713aSLionel Sambuc !IDecl->HasUserDeclaredSetterMethod(Prop)) {
1580f4a2713aSLionel Sambuc Diag(Prop->getLocation(), diag::warn_no_autosynthesis_property)
1581*0a6a1f1dSLionel Sambuc << Prop->getIdentifier();
1582f4a2713aSLionel Sambuc Diag(PropInSuperClass->getLocation(), diag::note_property_declare);
1583f4a2713aSLionel Sambuc }
1584*0a6a1f1dSLionel Sambuc else {
1585*0a6a1f1dSLionel Sambuc Diag(Prop->getLocation(), diag::warn_autosynthesis_property_in_superclass)
1586*0a6a1f1dSLionel Sambuc << Prop->getIdentifier();
1587*0a6a1f1dSLionel Sambuc Diag(PropInSuperClass->getLocation(), diag::note_property_declare);
1588*0a6a1f1dSLionel Sambuc Diag(IMPDecl->getLocation(), diag::note_while_in_implementation);
1589f4a2713aSLionel Sambuc }
1590f4a2713aSLionel Sambuc continue;
1591f4a2713aSLionel Sambuc }
1592f4a2713aSLionel Sambuc // We use invalid SourceLocations for the synthesized ivars since they
1593f4a2713aSLionel Sambuc // aren't really synthesized at a particular location; they just exist.
1594f4a2713aSLionel Sambuc // Saying that they are located at the @implementation isn't really going
1595f4a2713aSLionel Sambuc // to help users.
1596f4a2713aSLionel Sambuc ObjCPropertyImplDecl *PIDecl = dyn_cast_or_null<ObjCPropertyImplDecl>(
1597f4a2713aSLionel Sambuc ActOnPropertyImplDecl(S, SourceLocation(), SourceLocation(),
1598f4a2713aSLionel Sambuc true,
1599f4a2713aSLionel Sambuc /* property = */ Prop->getIdentifier(),
1600f4a2713aSLionel Sambuc /* ivar = */ Prop->getDefaultSynthIvarName(Context),
1601f4a2713aSLionel Sambuc Prop->getLocation()));
1602f4a2713aSLionel Sambuc if (PIDecl) {
1603f4a2713aSLionel Sambuc Diag(Prop->getLocation(), diag::warn_missing_explicit_synthesis);
1604f4a2713aSLionel Sambuc Diag(IMPDecl->getLocation(), diag::note_while_in_implementation);
1605f4a2713aSLionel Sambuc }
1606f4a2713aSLionel Sambuc }
1607f4a2713aSLionel Sambuc }
1608f4a2713aSLionel Sambuc
DefaultSynthesizeProperties(Scope * S,Decl * D)1609f4a2713aSLionel Sambuc void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) {
1610f4a2713aSLionel Sambuc if (!LangOpts.ObjCDefaultSynthProperties || LangOpts.ObjCRuntime.isFragile())
1611f4a2713aSLionel Sambuc return;
1612f4a2713aSLionel Sambuc ObjCImplementationDecl *IC=dyn_cast_or_null<ObjCImplementationDecl>(D);
1613f4a2713aSLionel Sambuc if (!IC)
1614f4a2713aSLionel Sambuc return;
1615f4a2713aSLionel Sambuc if (ObjCInterfaceDecl* IDecl = IC->getClassInterface())
1616f4a2713aSLionel Sambuc if (!IDecl->isObjCRequiresPropertyDefs())
1617f4a2713aSLionel Sambuc DefaultSynthesizeProperties(S, IC, IDecl);
1618f4a2713aSLionel Sambuc }
1619f4a2713aSLionel Sambuc
DiagnoseUnimplementedAccessor(Sema & S,ObjCInterfaceDecl * PrimaryClass,Selector Method,ObjCImplDecl * IMPDecl,ObjCContainerDecl * CDecl,ObjCCategoryDecl * C,ObjCPropertyDecl * Prop,Sema::SelectorSet & SMap)1620*0a6a1f1dSLionel Sambuc static void DiagnoseUnimplementedAccessor(Sema &S,
1621*0a6a1f1dSLionel Sambuc ObjCInterfaceDecl *PrimaryClass,
1622*0a6a1f1dSLionel Sambuc Selector Method,
1623*0a6a1f1dSLionel Sambuc ObjCImplDecl* IMPDecl,
1624*0a6a1f1dSLionel Sambuc ObjCContainerDecl *CDecl,
1625*0a6a1f1dSLionel Sambuc ObjCCategoryDecl *C,
1626*0a6a1f1dSLionel Sambuc ObjCPropertyDecl *Prop,
1627*0a6a1f1dSLionel Sambuc Sema::SelectorSet &SMap) {
1628*0a6a1f1dSLionel Sambuc // When reporting on missing property setter/getter implementation in
1629*0a6a1f1dSLionel Sambuc // categories, do not report when they are declared in primary class,
1630*0a6a1f1dSLionel Sambuc // class's protocol, or one of it super classes. This is because,
1631*0a6a1f1dSLionel Sambuc // the class is going to implement them.
1632*0a6a1f1dSLionel Sambuc if (!SMap.count(Method) &&
1633*0a6a1f1dSLionel Sambuc (PrimaryClass == nullptr ||
1634*0a6a1f1dSLionel Sambuc !PrimaryClass->lookupPropertyAccessor(Method, C))) {
1635*0a6a1f1dSLionel Sambuc S.Diag(IMPDecl->getLocation(),
1636*0a6a1f1dSLionel Sambuc isa<ObjCCategoryDecl>(CDecl) ?
1637*0a6a1f1dSLionel Sambuc diag::warn_setter_getter_impl_required_in_category :
1638*0a6a1f1dSLionel Sambuc diag::warn_setter_getter_impl_required)
1639*0a6a1f1dSLionel Sambuc << Prop->getDeclName() << Method;
1640*0a6a1f1dSLionel Sambuc S.Diag(Prop->getLocation(),
1641*0a6a1f1dSLionel Sambuc diag::note_property_declare);
1642*0a6a1f1dSLionel Sambuc if (S.LangOpts.ObjCDefaultSynthProperties &&
1643*0a6a1f1dSLionel Sambuc S.LangOpts.ObjCRuntime.isNonFragile())
1644*0a6a1f1dSLionel Sambuc if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl))
1645*0a6a1f1dSLionel Sambuc if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs())
1646*0a6a1f1dSLionel Sambuc S.Diag(RID->getLocation(), diag::note_suppressed_class_declare);
1647*0a6a1f1dSLionel Sambuc }
1648*0a6a1f1dSLionel Sambuc }
1649*0a6a1f1dSLionel Sambuc
DiagnoseUnimplementedProperties(Scope * S,ObjCImplDecl * IMPDecl,ObjCContainerDecl * CDecl,bool SynthesizeProperties)1650f4a2713aSLionel Sambuc void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
1651*0a6a1f1dSLionel Sambuc ObjCContainerDecl *CDecl,
1652*0a6a1f1dSLionel Sambuc bool SynthesizeProperties) {
1653*0a6a1f1dSLionel Sambuc ObjCContainerDecl::PropertyMap PropMap;
1654*0a6a1f1dSLionel Sambuc ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
1655*0a6a1f1dSLionel Sambuc
1656*0a6a1f1dSLionel Sambuc if (!SynthesizeProperties) {
1657f4a2713aSLionel Sambuc ObjCContainerDecl::PropertyMap NoNeedToImplPropMap;
1658f4a2713aSLionel Sambuc // Gather properties which need not be implemented in this class
1659f4a2713aSLionel Sambuc // or category.
1660*0a6a1f1dSLionel Sambuc if (!IDecl)
1661f4a2713aSLionel Sambuc if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
1662f4a2713aSLionel Sambuc // For categories, no need to implement properties declared in
1663f4a2713aSLionel Sambuc // its primary class (and its super classes) if property is
1664f4a2713aSLionel Sambuc // declared in one of those containers.
1665f4a2713aSLionel Sambuc if ((IDecl = C->getClassInterface())) {
1666f4a2713aSLionel Sambuc ObjCInterfaceDecl::PropertyDeclOrder PO;
1667f4a2713aSLionel Sambuc IDecl->collectPropertiesToImplement(NoNeedToImplPropMap, PO);
1668f4a2713aSLionel Sambuc }
1669f4a2713aSLionel Sambuc }
1670f4a2713aSLionel Sambuc if (IDecl)
1671f4a2713aSLionel Sambuc CollectSuperClassPropertyImplementations(IDecl, NoNeedToImplPropMap);
1672f4a2713aSLionel Sambuc
1673f4a2713aSLionel Sambuc CollectImmediateProperties(CDecl, PropMap, NoNeedToImplPropMap);
1674*0a6a1f1dSLionel Sambuc }
1675*0a6a1f1dSLionel Sambuc
1676*0a6a1f1dSLionel Sambuc // Scan the @interface to see if any of the protocols it adopts
1677*0a6a1f1dSLionel Sambuc // require an explicit implementation, via attribute
1678*0a6a1f1dSLionel Sambuc // 'objc_protocol_requires_explicit_implementation'.
1679*0a6a1f1dSLionel Sambuc if (IDecl) {
1680*0a6a1f1dSLionel Sambuc std::unique_ptr<ObjCContainerDecl::PropertyMap> LazyMap;
1681*0a6a1f1dSLionel Sambuc
1682*0a6a1f1dSLionel Sambuc for (auto *PDecl : IDecl->all_referenced_protocols()) {
1683*0a6a1f1dSLionel Sambuc if (!PDecl->hasAttr<ObjCExplicitProtocolImplAttr>())
1684*0a6a1f1dSLionel Sambuc continue;
1685*0a6a1f1dSLionel Sambuc // Lazily construct a set of all the properties in the @interface
1686*0a6a1f1dSLionel Sambuc // of the class, without looking at the superclass. We cannot
1687*0a6a1f1dSLionel Sambuc // use the call to CollectImmediateProperties() above as that
1688*0a6a1f1dSLionel Sambuc // utilizes information from the super class's properties as well
1689*0a6a1f1dSLionel Sambuc // as scans the adopted protocols. This work only triggers for protocols
1690*0a6a1f1dSLionel Sambuc // with the attribute, which is very rare, and only occurs when
1691*0a6a1f1dSLionel Sambuc // analyzing the @implementation.
1692*0a6a1f1dSLionel Sambuc if (!LazyMap) {
1693*0a6a1f1dSLionel Sambuc ObjCContainerDecl::PropertyMap NoNeedToImplPropMap;
1694*0a6a1f1dSLionel Sambuc LazyMap.reset(new ObjCContainerDecl::PropertyMap());
1695*0a6a1f1dSLionel Sambuc CollectImmediateProperties(CDecl, *LazyMap, NoNeedToImplPropMap,
1696*0a6a1f1dSLionel Sambuc /* IncludeProtocols */ false);
1697*0a6a1f1dSLionel Sambuc }
1698*0a6a1f1dSLionel Sambuc // Add the properties of 'PDecl' to the list of properties that
1699*0a6a1f1dSLionel Sambuc // need to be implemented.
1700*0a6a1f1dSLionel Sambuc for (auto *PropDecl : PDecl->properties()) {
1701*0a6a1f1dSLionel Sambuc if ((*LazyMap)[PropDecl->getIdentifier()])
1702*0a6a1f1dSLionel Sambuc continue;
1703*0a6a1f1dSLionel Sambuc PropMap[PropDecl->getIdentifier()] = PropDecl;
1704*0a6a1f1dSLionel Sambuc }
1705*0a6a1f1dSLionel Sambuc }
1706*0a6a1f1dSLionel Sambuc }
1707*0a6a1f1dSLionel Sambuc
1708f4a2713aSLionel Sambuc if (PropMap.empty())
1709f4a2713aSLionel Sambuc return;
1710f4a2713aSLionel Sambuc
1711f4a2713aSLionel Sambuc llvm::DenseSet<ObjCPropertyDecl *> PropImplMap;
1712*0a6a1f1dSLionel Sambuc for (const auto *I : IMPDecl->property_impls())
1713f4a2713aSLionel Sambuc PropImplMap.insert(I->getPropertyDecl());
1714f4a2713aSLionel Sambuc
1715f4a2713aSLionel Sambuc SelectorSet InsMap;
1716f4a2713aSLionel Sambuc // Collect property accessors implemented in current implementation.
1717*0a6a1f1dSLionel Sambuc for (const auto *I : IMPDecl->instance_methods())
1718*0a6a1f1dSLionel Sambuc InsMap.insert(I->getSelector());
1719f4a2713aSLionel Sambuc
1720f4a2713aSLionel Sambuc ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl);
1721*0a6a1f1dSLionel Sambuc ObjCInterfaceDecl *PrimaryClass = nullptr;
1722f4a2713aSLionel Sambuc if (C && !C->IsClassExtension())
1723f4a2713aSLionel Sambuc if ((PrimaryClass = C->getClassInterface()))
1724f4a2713aSLionel Sambuc // Report unimplemented properties in the category as well.
1725f4a2713aSLionel Sambuc if (ObjCImplDecl *IMP = PrimaryClass->getImplementation()) {
1726f4a2713aSLionel Sambuc // When reporting on missing setter/getters, do not report when
1727f4a2713aSLionel Sambuc // setter/getter is implemented in category's primary class
1728f4a2713aSLionel Sambuc // implementation.
1729*0a6a1f1dSLionel Sambuc for (const auto *I : IMP->instance_methods())
1730*0a6a1f1dSLionel Sambuc InsMap.insert(I->getSelector());
1731f4a2713aSLionel Sambuc }
1732f4a2713aSLionel Sambuc
1733f4a2713aSLionel Sambuc for (ObjCContainerDecl::PropertyMap::iterator
1734f4a2713aSLionel Sambuc P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
1735f4a2713aSLionel Sambuc ObjCPropertyDecl *Prop = P->second;
1736f4a2713aSLionel Sambuc // Is there a matching propery synthesize/dynamic?
1737f4a2713aSLionel Sambuc if (Prop->isInvalidDecl() ||
1738f4a2713aSLionel Sambuc Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
1739f4a2713aSLionel Sambuc PropImplMap.count(Prop) ||
1740f4a2713aSLionel Sambuc Prop->getAvailability() == AR_Unavailable)
1741f4a2713aSLionel Sambuc continue;
1742f4a2713aSLionel Sambuc
1743*0a6a1f1dSLionel Sambuc // Diagnose unimplemented getters and setters.
1744*0a6a1f1dSLionel Sambuc DiagnoseUnimplementedAccessor(*this,
1745*0a6a1f1dSLionel Sambuc PrimaryClass, Prop->getGetterName(), IMPDecl, CDecl, C, Prop, InsMap);
1746*0a6a1f1dSLionel Sambuc if (!Prop->isReadOnly())
1747*0a6a1f1dSLionel Sambuc DiagnoseUnimplementedAccessor(*this,
1748*0a6a1f1dSLionel Sambuc PrimaryClass, Prop->getSetterName(),
1749*0a6a1f1dSLionel Sambuc IMPDecl, CDecl, C, Prop, InsMap);
1750f4a2713aSLionel Sambuc }
1751f4a2713aSLionel Sambuc }
1752f4a2713aSLionel Sambuc
1753f4a2713aSLionel Sambuc void
AtomicPropertySetterGetterRules(ObjCImplDecl * IMPDecl,ObjCContainerDecl * IDecl)1754f4a2713aSLionel Sambuc Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
1755f4a2713aSLionel Sambuc ObjCContainerDecl* IDecl) {
1756f4a2713aSLionel Sambuc // Rules apply in non-GC mode only
1757f4a2713aSLionel Sambuc if (getLangOpts().getGC() != LangOptions::NonGC)
1758f4a2713aSLionel Sambuc return;
1759*0a6a1f1dSLionel Sambuc for (const auto *Property : IDecl->properties()) {
1760*0a6a1f1dSLionel Sambuc ObjCMethodDecl *GetterMethod = nullptr;
1761*0a6a1f1dSLionel Sambuc ObjCMethodDecl *SetterMethod = nullptr;
1762f4a2713aSLionel Sambuc bool LookedUpGetterSetter = false;
1763f4a2713aSLionel Sambuc
1764f4a2713aSLionel Sambuc unsigned Attributes = Property->getPropertyAttributes();
1765f4a2713aSLionel Sambuc unsigned AttributesAsWritten = Property->getPropertyAttributesAsWritten();
1766f4a2713aSLionel Sambuc
1767f4a2713aSLionel Sambuc if (!(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_atomic) &&
1768f4a2713aSLionel Sambuc !(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_nonatomic)) {
1769f4a2713aSLionel Sambuc GetterMethod = IMPDecl->getInstanceMethod(Property->getGetterName());
1770f4a2713aSLionel Sambuc SetterMethod = IMPDecl->getInstanceMethod(Property->getSetterName());
1771f4a2713aSLionel Sambuc LookedUpGetterSetter = true;
1772f4a2713aSLionel Sambuc if (GetterMethod) {
1773f4a2713aSLionel Sambuc Diag(GetterMethod->getLocation(),
1774f4a2713aSLionel Sambuc diag::warn_default_atomic_custom_getter_setter)
1775f4a2713aSLionel Sambuc << Property->getIdentifier() << 0;
1776f4a2713aSLionel Sambuc Diag(Property->getLocation(), diag::note_property_declare);
1777f4a2713aSLionel Sambuc }
1778f4a2713aSLionel Sambuc if (SetterMethod) {
1779f4a2713aSLionel Sambuc Diag(SetterMethod->getLocation(),
1780f4a2713aSLionel Sambuc diag::warn_default_atomic_custom_getter_setter)
1781f4a2713aSLionel Sambuc << Property->getIdentifier() << 1;
1782f4a2713aSLionel Sambuc Diag(Property->getLocation(), diag::note_property_declare);
1783f4a2713aSLionel Sambuc }
1784f4a2713aSLionel Sambuc }
1785f4a2713aSLionel Sambuc
1786f4a2713aSLionel Sambuc // We only care about readwrite atomic property.
1787f4a2713aSLionel Sambuc if ((Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) ||
1788f4a2713aSLionel Sambuc !(Attributes & ObjCPropertyDecl::OBJC_PR_readwrite))
1789f4a2713aSLionel Sambuc continue;
1790f4a2713aSLionel Sambuc if (const ObjCPropertyImplDecl *PIDecl
1791f4a2713aSLionel Sambuc = IMPDecl->FindPropertyImplDecl(Property->getIdentifier())) {
1792f4a2713aSLionel Sambuc if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
1793f4a2713aSLionel Sambuc continue;
1794f4a2713aSLionel Sambuc if (!LookedUpGetterSetter) {
1795f4a2713aSLionel Sambuc GetterMethod = IMPDecl->getInstanceMethod(Property->getGetterName());
1796f4a2713aSLionel Sambuc SetterMethod = IMPDecl->getInstanceMethod(Property->getSetterName());
1797f4a2713aSLionel Sambuc }
1798f4a2713aSLionel Sambuc if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) {
1799f4a2713aSLionel Sambuc SourceLocation MethodLoc =
1800f4a2713aSLionel Sambuc (GetterMethod ? GetterMethod->getLocation()
1801f4a2713aSLionel Sambuc : SetterMethod->getLocation());
1802f4a2713aSLionel Sambuc Diag(MethodLoc, diag::warn_atomic_property_rule)
1803*0a6a1f1dSLionel Sambuc << Property->getIdentifier() << (GetterMethod != nullptr)
1804*0a6a1f1dSLionel Sambuc << (SetterMethod != nullptr);
1805f4a2713aSLionel Sambuc // fixit stuff.
1806f4a2713aSLionel Sambuc if (!AttributesAsWritten) {
1807f4a2713aSLionel Sambuc if (Property->getLParenLoc().isValid()) {
1808f4a2713aSLionel Sambuc // @property () ... case.
1809f4a2713aSLionel Sambuc SourceRange PropSourceRange(Property->getAtLoc(),
1810f4a2713aSLionel Sambuc Property->getLParenLoc());
1811f4a2713aSLionel Sambuc Diag(Property->getLocation(), diag::note_atomic_property_fixup_suggest) <<
1812f4a2713aSLionel Sambuc FixItHint::CreateReplacement(PropSourceRange, "@property (nonatomic");
1813f4a2713aSLionel Sambuc }
1814f4a2713aSLionel Sambuc else {
1815f4a2713aSLionel Sambuc //@property id etc.
1816f4a2713aSLionel Sambuc SourceLocation endLoc =
1817f4a2713aSLionel Sambuc Property->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
1818f4a2713aSLionel Sambuc endLoc = endLoc.getLocWithOffset(-1);
1819f4a2713aSLionel Sambuc SourceRange PropSourceRange(Property->getAtLoc(), endLoc);
1820f4a2713aSLionel Sambuc Diag(Property->getLocation(), diag::note_atomic_property_fixup_suggest) <<
1821f4a2713aSLionel Sambuc FixItHint::CreateReplacement(PropSourceRange, "@property (nonatomic) ");
1822f4a2713aSLionel Sambuc }
1823f4a2713aSLionel Sambuc }
1824f4a2713aSLionel Sambuc else if (!(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_atomic)) {
1825f4a2713aSLionel Sambuc // @property () ... case.
1826f4a2713aSLionel Sambuc SourceLocation endLoc = Property->getLParenLoc();
1827f4a2713aSLionel Sambuc SourceRange PropSourceRange(Property->getAtLoc(), endLoc);
1828f4a2713aSLionel Sambuc Diag(Property->getLocation(), diag::note_atomic_property_fixup_suggest) <<
1829f4a2713aSLionel Sambuc FixItHint::CreateReplacement(PropSourceRange, "@property (nonatomic, ");
1830f4a2713aSLionel Sambuc }
1831f4a2713aSLionel Sambuc else
1832f4a2713aSLionel Sambuc Diag(MethodLoc, diag::note_atomic_property_fixup_suggest);
1833f4a2713aSLionel Sambuc Diag(Property->getLocation(), diag::note_property_declare);
1834f4a2713aSLionel Sambuc }
1835f4a2713aSLionel Sambuc }
1836f4a2713aSLionel Sambuc }
1837f4a2713aSLionel Sambuc }
1838f4a2713aSLionel Sambuc
DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl * D)1839f4a2713aSLionel Sambuc void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D) {
1840f4a2713aSLionel Sambuc if (getLangOpts().getGC() == LangOptions::GCOnly)
1841f4a2713aSLionel Sambuc return;
1842f4a2713aSLionel Sambuc
1843*0a6a1f1dSLionel Sambuc for (const auto *PID : D->property_impls()) {
1844f4a2713aSLionel Sambuc const ObjCPropertyDecl *PD = PID->getPropertyDecl();
1845f4a2713aSLionel Sambuc if (PD && !PD->hasAttr<NSReturnsNotRetainedAttr>() &&
1846f4a2713aSLionel Sambuc !D->getInstanceMethod(PD->getGetterName())) {
1847f4a2713aSLionel Sambuc ObjCMethodDecl *method = PD->getGetterMethodDecl();
1848f4a2713aSLionel Sambuc if (!method)
1849f4a2713aSLionel Sambuc continue;
1850f4a2713aSLionel Sambuc ObjCMethodFamily family = method->getMethodFamily();
1851f4a2713aSLionel Sambuc if (family == OMF_alloc || family == OMF_copy ||
1852f4a2713aSLionel Sambuc family == OMF_mutableCopy || family == OMF_new) {
1853f4a2713aSLionel Sambuc if (getLangOpts().ObjCAutoRefCount)
1854*0a6a1f1dSLionel Sambuc Diag(PD->getLocation(), diag::err_cocoa_naming_owned_rule);
1855f4a2713aSLionel Sambuc else
1856*0a6a1f1dSLionel Sambuc Diag(PD->getLocation(), diag::warn_cocoa_naming_owned_rule);
1857f4a2713aSLionel Sambuc }
1858f4a2713aSLionel Sambuc }
1859f4a2713aSLionel Sambuc }
1860f4a2713aSLionel Sambuc }
1861f4a2713aSLionel Sambuc
DiagnoseMissingDesignatedInitOverrides(const ObjCImplementationDecl * ImplD,const ObjCInterfaceDecl * IFD)1862*0a6a1f1dSLionel Sambuc void Sema::DiagnoseMissingDesignatedInitOverrides(
1863*0a6a1f1dSLionel Sambuc const ObjCImplementationDecl *ImplD,
1864*0a6a1f1dSLionel Sambuc const ObjCInterfaceDecl *IFD) {
1865*0a6a1f1dSLionel Sambuc assert(IFD->hasDesignatedInitializers());
1866*0a6a1f1dSLionel Sambuc const ObjCInterfaceDecl *SuperD = IFD->getSuperClass();
1867*0a6a1f1dSLionel Sambuc if (!SuperD)
1868*0a6a1f1dSLionel Sambuc return;
1869*0a6a1f1dSLionel Sambuc
1870*0a6a1f1dSLionel Sambuc SelectorSet InitSelSet;
1871*0a6a1f1dSLionel Sambuc for (const auto *I : ImplD->instance_methods())
1872*0a6a1f1dSLionel Sambuc if (I->getMethodFamily() == OMF_init)
1873*0a6a1f1dSLionel Sambuc InitSelSet.insert(I->getSelector());
1874*0a6a1f1dSLionel Sambuc
1875*0a6a1f1dSLionel Sambuc SmallVector<const ObjCMethodDecl *, 8> DesignatedInits;
1876*0a6a1f1dSLionel Sambuc SuperD->getDesignatedInitializers(DesignatedInits);
1877*0a6a1f1dSLionel Sambuc for (SmallVector<const ObjCMethodDecl *, 8>::iterator
1878*0a6a1f1dSLionel Sambuc I = DesignatedInits.begin(), E = DesignatedInits.end(); I != E; ++I) {
1879*0a6a1f1dSLionel Sambuc const ObjCMethodDecl *MD = *I;
1880*0a6a1f1dSLionel Sambuc if (!InitSelSet.count(MD->getSelector())) {
1881*0a6a1f1dSLionel Sambuc Diag(ImplD->getLocation(),
1882*0a6a1f1dSLionel Sambuc diag::warn_objc_implementation_missing_designated_init_override)
1883*0a6a1f1dSLionel Sambuc << MD->getSelector();
1884*0a6a1f1dSLionel Sambuc Diag(MD->getLocation(), diag::note_objc_designated_init_marked_here);
1885*0a6a1f1dSLionel Sambuc }
1886*0a6a1f1dSLionel Sambuc }
1887*0a6a1f1dSLionel Sambuc }
1888*0a6a1f1dSLionel Sambuc
1889f4a2713aSLionel Sambuc /// AddPropertyAttrs - Propagates attributes from a property to the
1890f4a2713aSLionel Sambuc /// implicitly-declared getter or setter for that property.
AddPropertyAttrs(Sema & S,ObjCMethodDecl * PropertyMethod,ObjCPropertyDecl * Property)1891f4a2713aSLionel Sambuc static void AddPropertyAttrs(Sema &S, ObjCMethodDecl *PropertyMethod,
1892f4a2713aSLionel Sambuc ObjCPropertyDecl *Property) {
1893f4a2713aSLionel Sambuc // Should we just clone all attributes over?
1894*0a6a1f1dSLionel Sambuc for (const auto *A : Property->attrs()) {
1895*0a6a1f1dSLionel Sambuc if (isa<DeprecatedAttr>(A) ||
1896*0a6a1f1dSLionel Sambuc isa<UnavailableAttr>(A) ||
1897*0a6a1f1dSLionel Sambuc isa<AvailabilityAttr>(A))
1898*0a6a1f1dSLionel Sambuc PropertyMethod->addAttr(A->clone(S.Context));
1899f4a2713aSLionel Sambuc }
1900f4a2713aSLionel Sambuc }
1901f4a2713aSLionel Sambuc
1902f4a2713aSLionel Sambuc /// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods
1903f4a2713aSLionel Sambuc /// have the property type and issue diagnostics if they don't.
1904f4a2713aSLionel Sambuc /// Also synthesize a getter/setter method if none exist (and update the
1905f4a2713aSLionel Sambuc /// appropriate lookup tables. FIXME: Should reconsider if adding synthesized
1906f4a2713aSLionel Sambuc /// methods is the "right" thing to do.
ProcessPropertyDecl(ObjCPropertyDecl * property,ObjCContainerDecl * CD,ObjCPropertyDecl * redeclaredProperty,ObjCContainerDecl * lexicalDC)1907f4a2713aSLionel Sambuc void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
1908f4a2713aSLionel Sambuc ObjCContainerDecl *CD,
1909f4a2713aSLionel Sambuc ObjCPropertyDecl *redeclaredProperty,
1910f4a2713aSLionel Sambuc ObjCContainerDecl *lexicalDC) {
1911f4a2713aSLionel Sambuc
1912f4a2713aSLionel Sambuc ObjCMethodDecl *GetterMethod, *SetterMethod;
1913f4a2713aSLionel Sambuc
1914*0a6a1f1dSLionel Sambuc if (CD->isInvalidDecl())
1915*0a6a1f1dSLionel Sambuc return;
1916*0a6a1f1dSLionel Sambuc
1917f4a2713aSLionel Sambuc GetterMethod = CD->getInstanceMethod(property->getGetterName());
1918f4a2713aSLionel Sambuc SetterMethod = CD->getInstanceMethod(property->getSetterName());
1919f4a2713aSLionel Sambuc DiagnosePropertyAccessorMismatch(property, GetterMethod,
1920f4a2713aSLionel Sambuc property->getLocation());
1921f4a2713aSLionel Sambuc
1922f4a2713aSLionel Sambuc if (SetterMethod) {
1923f4a2713aSLionel Sambuc ObjCPropertyDecl::PropertyAttributeKind CAttr =
1924f4a2713aSLionel Sambuc property->getPropertyAttributes();
1925f4a2713aSLionel Sambuc if ((!(CAttr & ObjCPropertyDecl::OBJC_PR_readonly)) &&
1926*0a6a1f1dSLionel Sambuc Context.getCanonicalType(SetterMethod->getReturnType()) !=
1927f4a2713aSLionel Sambuc Context.VoidTy)
1928f4a2713aSLionel Sambuc Diag(SetterMethod->getLocation(), diag::err_setter_type_void);
1929f4a2713aSLionel Sambuc if (SetterMethod->param_size() != 1 ||
1930f4a2713aSLionel Sambuc !Context.hasSameUnqualifiedType(
1931f4a2713aSLionel Sambuc (*SetterMethod->param_begin())->getType().getNonReferenceType(),
1932f4a2713aSLionel Sambuc property->getType().getNonReferenceType())) {
1933f4a2713aSLionel Sambuc Diag(property->getLocation(),
1934f4a2713aSLionel Sambuc diag::warn_accessor_property_type_mismatch)
1935f4a2713aSLionel Sambuc << property->getDeclName()
1936f4a2713aSLionel Sambuc << SetterMethod->getSelector();
1937f4a2713aSLionel Sambuc Diag(SetterMethod->getLocation(), diag::note_declared_at);
1938f4a2713aSLionel Sambuc }
1939f4a2713aSLionel Sambuc }
1940f4a2713aSLionel Sambuc
1941f4a2713aSLionel Sambuc // Synthesize getter/setter methods if none exist.
1942f4a2713aSLionel Sambuc // Find the default getter and if one not found, add one.
1943f4a2713aSLionel Sambuc // FIXME: The synthesized property we set here is misleading. We almost always
1944f4a2713aSLionel Sambuc // synthesize these methods unless the user explicitly provided prototypes
1945f4a2713aSLionel Sambuc // (which is odd, but allowed). Sema should be typechecking that the
1946f4a2713aSLionel Sambuc // declarations jive in that situation (which it is not currently).
1947f4a2713aSLionel Sambuc if (!GetterMethod) {
1948f4a2713aSLionel Sambuc // No instance method of same name as property getter name was found.
1949f4a2713aSLionel Sambuc // Declare a getter method and add it to the list of methods
1950f4a2713aSLionel Sambuc // for this class.
1951f4a2713aSLionel Sambuc SourceLocation Loc = redeclaredProperty ?
1952f4a2713aSLionel Sambuc redeclaredProperty->getLocation() :
1953f4a2713aSLionel Sambuc property->getLocation();
1954f4a2713aSLionel Sambuc
1955f4a2713aSLionel Sambuc GetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc,
1956f4a2713aSLionel Sambuc property->getGetterName(),
1957*0a6a1f1dSLionel Sambuc property->getType(), nullptr, CD,
1958*0a6a1f1dSLionel Sambuc /*isInstance=*/true, /*isVariadic=*/false,
1959*0a6a1f1dSLionel Sambuc /*isPropertyAccessor=*/true,
1960f4a2713aSLionel Sambuc /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
1961f4a2713aSLionel Sambuc (property->getPropertyImplementation() ==
1962f4a2713aSLionel Sambuc ObjCPropertyDecl::Optional) ?
1963f4a2713aSLionel Sambuc ObjCMethodDecl::Optional :
1964f4a2713aSLionel Sambuc ObjCMethodDecl::Required);
1965f4a2713aSLionel Sambuc CD->addDecl(GetterMethod);
1966f4a2713aSLionel Sambuc
1967f4a2713aSLionel Sambuc AddPropertyAttrs(*this, GetterMethod, property);
1968f4a2713aSLionel Sambuc
1969f4a2713aSLionel Sambuc // FIXME: Eventually this shouldn't be needed, as the lexical context
1970f4a2713aSLionel Sambuc // and the real context should be the same.
1971f4a2713aSLionel Sambuc if (lexicalDC)
1972f4a2713aSLionel Sambuc GetterMethod->setLexicalDeclContext(lexicalDC);
1973f4a2713aSLionel Sambuc if (property->hasAttr<NSReturnsNotRetainedAttr>())
1974*0a6a1f1dSLionel Sambuc GetterMethod->addAttr(NSReturnsNotRetainedAttr::CreateImplicit(Context,
1975*0a6a1f1dSLionel Sambuc Loc));
1976f4a2713aSLionel Sambuc
1977f4a2713aSLionel Sambuc if (property->hasAttr<ObjCReturnsInnerPointerAttr>())
1978f4a2713aSLionel Sambuc GetterMethod->addAttr(
1979*0a6a1f1dSLionel Sambuc ObjCReturnsInnerPointerAttr::CreateImplicit(Context, Loc));
1980*0a6a1f1dSLionel Sambuc
1981*0a6a1f1dSLionel Sambuc if (const SectionAttr *SA = property->getAttr<SectionAttr>())
1982*0a6a1f1dSLionel Sambuc GetterMethod->addAttr(
1983*0a6a1f1dSLionel Sambuc SectionAttr::CreateImplicit(Context, SectionAttr::GNU_section,
1984*0a6a1f1dSLionel Sambuc SA->getName(), Loc));
1985f4a2713aSLionel Sambuc
1986f4a2713aSLionel Sambuc if (getLangOpts().ObjCAutoRefCount)
1987f4a2713aSLionel Sambuc CheckARCMethodDecl(GetterMethod);
1988f4a2713aSLionel Sambuc } else
1989f4a2713aSLionel Sambuc // A user declared getter will be synthesize when @synthesize of
1990f4a2713aSLionel Sambuc // the property with the same name is seen in the @implementation
1991f4a2713aSLionel Sambuc GetterMethod->setPropertyAccessor(true);
1992f4a2713aSLionel Sambuc property->setGetterMethodDecl(GetterMethod);
1993f4a2713aSLionel Sambuc
1994f4a2713aSLionel Sambuc // Skip setter if property is read-only.
1995f4a2713aSLionel Sambuc if (!property->isReadOnly()) {
1996f4a2713aSLionel Sambuc // Find the default setter and if one not found, add one.
1997f4a2713aSLionel Sambuc if (!SetterMethod) {
1998f4a2713aSLionel Sambuc // No instance method of same name as property setter name was found.
1999f4a2713aSLionel Sambuc // Declare a setter method and add it to the list of methods
2000f4a2713aSLionel Sambuc // for this class.
2001f4a2713aSLionel Sambuc SourceLocation Loc = redeclaredProperty ?
2002f4a2713aSLionel Sambuc redeclaredProperty->getLocation() :
2003f4a2713aSLionel Sambuc property->getLocation();
2004f4a2713aSLionel Sambuc
2005f4a2713aSLionel Sambuc SetterMethod =
2006f4a2713aSLionel Sambuc ObjCMethodDecl::Create(Context, Loc, Loc,
2007*0a6a1f1dSLionel Sambuc property->getSetterName(), Context.VoidTy,
2008*0a6a1f1dSLionel Sambuc nullptr, CD, /*isInstance=*/true,
2009*0a6a1f1dSLionel Sambuc /*isVariadic=*/false,
2010f4a2713aSLionel Sambuc /*isPropertyAccessor=*/true,
2011f4a2713aSLionel Sambuc /*isImplicitlyDeclared=*/true,
2012f4a2713aSLionel Sambuc /*isDefined=*/false,
2013f4a2713aSLionel Sambuc (property->getPropertyImplementation() ==
2014f4a2713aSLionel Sambuc ObjCPropertyDecl::Optional) ?
2015f4a2713aSLionel Sambuc ObjCMethodDecl::Optional :
2016f4a2713aSLionel Sambuc ObjCMethodDecl::Required);
2017f4a2713aSLionel Sambuc
2018f4a2713aSLionel Sambuc // Invent the arguments for the setter. We don't bother making a
2019f4a2713aSLionel Sambuc // nice name for the argument.
2020f4a2713aSLionel Sambuc ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod,
2021f4a2713aSLionel Sambuc Loc, Loc,
2022f4a2713aSLionel Sambuc property->getIdentifier(),
2023f4a2713aSLionel Sambuc property->getType().getUnqualifiedType(),
2024*0a6a1f1dSLionel Sambuc /*TInfo=*/nullptr,
2025f4a2713aSLionel Sambuc SC_None,
2026*0a6a1f1dSLionel Sambuc nullptr);
2027f4a2713aSLionel Sambuc SetterMethod->setMethodParams(Context, Argument, None);
2028f4a2713aSLionel Sambuc
2029f4a2713aSLionel Sambuc AddPropertyAttrs(*this, SetterMethod, property);
2030f4a2713aSLionel Sambuc
2031f4a2713aSLionel Sambuc CD->addDecl(SetterMethod);
2032f4a2713aSLionel Sambuc // FIXME: Eventually this shouldn't be needed, as the lexical context
2033f4a2713aSLionel Sambuc // and the real context should be the same.
2034f4a2713aSLionel Sambuc if (lexicalDC)
2035f4a2713aSLionel Sambuc SetterMethod->setLexicalDeclContext(lexicalDC);
2036*0a6a1f1dSLionel Sambuc if (const SectionAttr *SA = property->getAttr<SectionAttr>())
2037*0a6a1f1dSLionel Sambuc SetterMethod->addAttr(
2038*0a6a1f1dSLionel Sambuc SectionAttr::CreateImplicit(Context, SectionAttr::GNU_section,
2039*0a6a1f1dSLionel Sambuc SA->getName(), Loc));
2040f4a2713aSLionel Sambuc // It's possible for the user to have set a very odd custom
2041f4a2713aSLionel Sambuc // setter selector that causes it to have a method family.
2042f4a2713aSLionel Sambuc if (getLangOpts().ObjCAutoRefCount)
2043f4a2713aSLionel Sambuc CheckARCMethodDecl(SetterMethod);
2044f4a2713aSLionel Sambuc } else
2045f4a2713aSLionel Sambuc // A user declared setter will be synthesize when @synthesize of
2046f4a2713aSLionel Sambuc // the property with the same name is seen in the @implementation
2047f4a2713aSLionel Sambuc SetterMethod->setPropertyAccessor(true);
2048f4a2713aSLionel Sambuc property->setSetterMethodDecl(SetterMethod);
2049f4a2713aSLionel Sambuc }
2050f4a2713aSLionel Sambuc // Add any synthesized methods to the global pool. This allows us to
2051f4a2713aSLionel Sambuc // handle the following, which is supported by GCC (and part of the design).
2052f4a2713aSLionel Sambuc //
2053f4a2713aSLionel Sambuc // @interface Foo
2054f4a2713aSLionel Sambuc // @property double bar;
2055f4a2713aSLionel Sambuc // @end
2056f4a2713aSLionel Sambuc //
2057f4a2713aSLionel Sambuc // void thisIsUnfortunate() {
2058f4a2713aSLionel Sambuc // id foo;
2059f4a2713aSLionel Sambuc // double bar = [foo bar];
2060f4a2713aSLionel Sambuc // }
2061f4a2713aSLionel Sambuc //
2062f4a2713aSLionel Sambuc if (GetterMethod)
2063f4a2713aSLionel Sambuc AddInstanceMethodToGlobalPool(GetterMethod);
2064f4a2713aSLionel Sambuc if (SetterMethod)
2065f4a2713aSLionel Sambuc AddInstanceMethodToGlobalPool(SetterMethod);
2066f4a2713aSLionel Sambuc
2067f4a2713aSLionel Sambuc ObjCInterfaceDecl *CurrentClass = dyn_cast<ObjCInterfaceDecl>(CD);
2068f4a2713aSLionel Sambuc if (!CurrentClass) {
2069f4a2713aSLionel Sambuc if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(CD))
2070f4a2713aSLionel Sambuc CurrentClass = Cat->getClassInterface();
2071f4a2713aSLionel Sambuc else if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(CD))
2072f4a2713aSLionel Sambuc CurrentClass = Impl->getClassInterface();
2073f4a2713aSLionel Sambuc }
2074f4a2713aSLionel Sambuc if (GetterMethod)
2075f4a2713aSLionel Sambuc CheckObjCMethodOverrides(GetterMethod, CurrentClass, Sema::RTC_Unknown);
2076f4a2713aSLionel Sambuc if (SetterMethod)
2077f4a2713aSLionel Sambuc CheckObjCMethodOverrides(SetterMethod, CurrentClass, Sema::RTC_Unknown);
2078f4a2713aSLionel Sambuc }
2079f4a2713aSLionel Sambuc
CheckObjCPropertyAttributes(Decl * PDecl,SourceLocation Loc,unsigned & Attributes,bool propertyInPrimaryClass)2080f4a2713aSLionel Sambuc void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
2081f4a2713aSLionel Sambuc SourceLocation Loc,
2082f4a2713aSLionel Sambuc unsigned &Attributes,
2083f4a2713aSLionel Sambuc bool propertyInPrimaryClass) {
2084f4a2713aSLionel Sambuc // FIXME: Improve the reported location.
2085f4a2713aSLionel Sambuc if (!PDecl || PDecl->isInvalidDecl())
2086f4a2713aSLionel Sambuc return;
2087f4a2713aSLionel Sambuc
2088f4a2713aSLionel Sambuc if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
2089f4a2713aSLionel Sambuc (Attributes & ObjCDeclSpec::DQ_PR_readwrite))
2090f4a2713aSLionel Sambuc Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
2091f4a2713aSLionel Sambuc << "readonly" << "readwrite";
2092f4a2713aSLionel Sambuc
2093f4a2713aSLionel Sambuc ObjCPropertyDecl *PropertyDecl = cast<ObjCPropertyDecl>(PDecl);
2094f4a2713aSLionel Sambuc QualType PropertyTy = PropertyDecl->getType();
2095f4a2713aSLionel Sambuc unsigned PropertyOwnership = getOwnershipRule(Attributes);
2096f4a2713aSLionel Sambuc
2097f4a2713aSLionel Sambuc // 'readonly' property with no obvious lifetime.
2098f4a2713aSLionel Sambuc // its life time will be determined by its backing ivar.
2099*0a6a1f1dSLionel Sambuc if (getLangOpts().ObjCAutoRefCount &&
2100*0a6a1f1dSLionel Sambuc Attributes & ObjCDeclSpec::DQ_PR_readonly &&
2101*0a6a1f1dSLionel Sambuc PropertyTy->isObjCRetainableType() &&
2102*0a6a1f1dSLionel Sambuc !PropertyOwnership)
2103f4a2713aSLionel Sambuc return;
2104f4a2713aSLionel Sambuc
2105f4a2713aSLionel Sambuc // Check for copy or retain on non-object types.
2106f4a2713aSLionel Sambuc if ((Attributes & (ObjCDeclSpec::DQ_PR_weak | ObjCDeclSpec::DQ_PR_copy |
2107f4a2713aSLionel Sambuc ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong)) &&
2108f4a2713aSLionel Sambuc !PropertyTy->isObjCRetainableType() &&
2109*0a6a1f1dSLionel Sambuc !PropertyDecl->hasAttr<ObjCNSObjectAttr>()) {
2110f4a2713aSLionel Sambuc Diag(Loc, diag::err_objc_property_requires_object)
2111f4a2713aSLionel Sambuc << (Attributes & ObjCDeclSpec::DQ_PR_weak ? "weak" :
2112f4a2713aSLionel Sambuc Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain (or strong)");
2113f4a2713aSLionel Sambuc Attributes &= ~(ObjCDeclSpec::DQ_PR_weak | ObjCDeclSpec::DQ_PR_copy |
2114f4a2713aSLionel Sambuc ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong);
2115f4a2713aSLionel Sambuc PropertyDecl->setInvalidDecl();
2116f4a2713aSLionel Sambuc }
2117f4a2713aSLionel Sambuc
2118f4a2713aSLionel Sambuc // Check for more than one of { assign, copy, retain }.
2119f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_assign) {
2120f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
2121f4a2713aSLionel Sambuc Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
2122f4a2713aSLionel Sambuc << "assign" << "copy";
2123f4a2713aSLionel Sambuc Attributes &= ~ObjCDeclSpec::DQ_PR_copy;
2124f4a2713aSLionel Sambuc }
2125f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
2126f4a2713aSLionel Sambuc Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
2127f4a2713aSLionel Sambuc << "assign" << "retain";
2128f4a2713aSLionel Sambuc Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
2129f4a2713aSLionel Sambuc }
2130f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_strong) {
2131f4a2713aSLionel Sambuc Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
2132f4a2713aSLionel Sambuc << "assign" << "strong";
2133f4a2713aSLionel Sambuc Attributes &= ~ObjCDeclSpec::DQ_PR_strong;
2134f4a2713aSLionel Sambuc }
2135f4a2713aSLionel Sambuc if (getLangOpts().ObjCAutoRefCount &&
2136f4a2713aSLionel Sambuc (Attributes & ObjCDeclSpec::DQ_PR_weak)) {
2137f4a2713aSLionel Sambuc Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
2138f4a2713aSLionel Sambuc << "assign" << "weak";
2139f4a2713aSLionel Sambuc Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
2140f4a2713aSLionel Sambuc }
2141*0a6a1f1dSLionel Sambuc if (PropertyDecl->hasAttr<IBOutletCollectionAttr>())
2142f4a2713aSLionel Sambuc Diag(Loc, diag::warn_iboutletcollection_property_assign);
2143f4a2713aSLionel Sambuc } else if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) {
2144f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
2145f4a2713aSLionel Sambuc Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
2146f4a2713aSLionel Sambuc << "unsafe_unretained" << "copy";
2147f4a2713aSLionel Sambuc Attributes &= ~ObjCDeclSpec::DQ_PR_copy;
2148f4a2713aSLionel Sambuc }
2149f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
2150f4a2713aSLionel Sambuc Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
2151f4a2713aSLionel Sambuc << "unsafe_unretained" << "retain";
2152f4a2713aSLionel Sambuc Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
2153f4a2713aSLionel Sambuc }
2154f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_strong) {
2155f4a2713aSLionel Sambuc Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
2156f4a2713aSLionel Sambuc << "unsafe_unretained" << "strong";
2157f4a2713aSLionel Sambuc Attributes &= ~ObjCDeclSpec::DQ_PR_strong;
2158f4a2713aSLionel Sambuc }
2159f4a2713aSLionel Sambuc if (getLangOpts().ObjCAutoRefCount &&
2160f4a2713aSLionel Sambuc (Attributes & ObjCDeclSpec::DQ_PR_weak)) {
2161f4a2713aSLionel Sambuc Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
2162f4a2713aSLionel Sambuc << "unsafe_unretained" << "weak";
2163f4a2713aSLionel Sambuc Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
2164f4a2713aSLionel Sambuc }
2165f4a2713aSLionel Sambuc } else if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
2166f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
2167f4a2713aSLionel Sambuc Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
2168f4a2713aSLionel Sambuc << "copy" << "retain";
2169f4a2713aSLionel Sambuc Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
2170f4a2713aSLionel Sambuc }
2171f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_strong) {
2172f4a2713aSLionel Sambuc Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
2173f4a2713aSLionel Sambuc << "copy" << "strong";
2174f4a2713aSLionel Sambuc Attributes &= ~ObjCDeclSpec::DQ_PR_strong;
2175f4a2713aSLionel Sambuc }
2176f4a2713aSLionel Sambuc if (Attributes & ObjCDeclSpec::DQ_PR_weak) {
2177f4a2713aSLionel Sambuc Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
2178f4a2713aSLionel Sambuc << "copy" << "weak";
2179f4a2713aSLionel Sambuc Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
2180f4a2713aSLionel Sambuc }
2181f4a2713aSLionel Sambuc }
2182f4a2713aSLionel Sambuc else if ((Attributes & ObjCDeclSpec::DQ_PR_retain) &&
2183f4a2713aSLionel Sambuc (Attributes & ObjCDeclSpec::DQ_PR_weak)) {
2184f4a2713aSLionel Sambuc Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
2185f4a2713aSLionel Sambuc << "retain" << "weak";
2186f4a2713aSLionel Sambuc Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
2187f4a2713aSLionel Sambuc }
2188f4a2713aSLionel Sambuc else if ((Attributes & ObjCDeclSpec::DQ_PR_strong) &&
2189f4a2713aSLionel Sambuc (Attributes & ObjCDeclSpec::DQ_PR_weak)) {
2190f4a2713aSLionel Sambuc Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
2191f4a2713aSLionel Sambuc << "strong" << "weak";
2192f4a2713aSLionel Sambuc Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
2193f4a2713aSLionel Sambuc }
2194f4a2713aSLionel Sambuc
2195f4a2713aSLionel Sambuc if ((Attributes & ObjCDeclSpec::DQ_PR_atomic) &&
2196f4a2713aSLionel Sambuc (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)) {
2197f4a2713aSLionel Sambuc Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
2198f4a2713aSLionel Sambuc << "atomic" << "nonatomic";
2199f4a2713aSLionel Sambuc Attributes &= ~ObjCDeclSpec::DQ_PR_atomic;
2200f4a2713aSLionel Sambuc }
2201f4a2713aSLionel Sambuc
2202f4a2713aSLionel Sambuc // Warn if user supplied no assignment attribute, property is
2203f4a2713aSLionel Sambuc // readwrite, and this is an object type.
2204f4a2713aSLionel Sambuc if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy |
2205f4a2713aSLionel Sambuc ObjCDeclSpec::DQ_PR_unsafe_unretained |
2206f4a2713aSLionel Sambuc ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong |
2207f4a2713aSLionel Sambuc ObjCDeclSpec::DQ_PR_weak)) &&
2208f4a2713aSLionel Sambuc PropertyTy->isObjCObjectPointerType()) {
2209f4a2713aSLionel Sambuc if (getLangOpts().ObjCAutoRefCount)
2210f4a2713aSLionel Sambuc // With arc, @property definitions should default to (strong) when
2211f4a2713aSLionel Sambuc // not specified; including when property is 'readonly'.
2212f4a2713aSLionel Sambuc PropertyDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
2213f4a2713aSLionel Sambuc else if (!(Attributes & ObjCDeclSpec::DQ_PR_readonly)) {
2214f4a2713aSLionel Sambuc bool isAnyClassTy =
2215f4a2713aSLionel Sambuc (PropertyTy->isObjCClassType() ||
2216f4a2713aSLionel Sambuc PropertyTy->isObjCQualifiedClassType());
2217f4a2713aSLionel Sambuc // In non-gc, non-arc mode, 'Class' is treated as a 'void *' no need to
2218f4a2713aSLionel Sambuc // issue any warning.
2219f4a2713aSLionel Sambuc if (isAnyClassTy && getLangOpts().getGC() == LangOptions::NonGC)
2220f4a2713aSLionel Sambuc ;
2221f4a2713aSLionel Sambuc else if (propertyInPrimaryClass) {
2222f4a2713aSLionel Sambuc // Don't issue warning on property with no life time in class
2223f4a2713aSLionel Sambuc // extension as it is inherited from property in primary class.
2224f4a2713aSLionel Sambuc // Skip this warning in gc-only mode.
2225f4a2713aSLionel Sambuc if (getLangOpts().getGC() != LangOptions::GCOnly)
2226f4a2713aSLionel Sambuc Diag(Loc, diag::warn_objc_property_no_assignment_attribute);
2227f4a2713aSLionel Sambuc
2228f4a2713aSLionel Sambuc // If non-gc code warn that this is likely inappropriate.
2229f4a2713aSLionel Sambuc if (getLangOpts().getGC() == LangOptions::NonGC)
2230f4a2713aSLionel Sambuc Diag(Loc, diag::warn_objc_property_default_assign_on_object);
2231f4a2713aSLionel Sambuc }
2232f4a2713aSLionel Sambuc }
2233f4a2713aSLionel Sambuc
2234f4a2713aSLionel Sambuc // FIXME: Implement warning dependent on NSCopying being
2235f4a2713aSLionel Sambuc // implemented. See also:
2236f4a2713aSLionel Sambuc // <rdar://5168496&4855821&5607453&5096644&4947311&5698469&4947014&5168496>
2237f4a2713aSLionel Sambuc // (please trim this list while you are at it).
2238f4a2713aSLionel Sambuc }
2239f4a2713aSLionel Sambuc
2240f4a2713aSLionel Sambuc if (!(Attributes & ObjCDeclSpec::DQ_PR_copy)
2241f4a2713aSLionel Sambuc &&!(Attributes & ObjCDeclSpec::DQ_PR_readonly)
2242f4a2713aSLionel Sambuc && getLangOpts().getGC() == LangOptions::GCOnly
2243f4a2713aSLionel Sambuc && PropertyTy->isBlockPointerType())
2244f4a2713aSLionel Sambuc Diag(Loc, diag::warn_objc_property_copy_missing_on_block);
2245f4a2713aSLionel Sambuc else if ((Attributes & ObjCDeclSpec::DQ_PR_retain) &&
2246f4a2713aSLionel Sambuc !(Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
2247f4a2713aSLionel Sambuc !(Attributes & ObjCDeclSpec::DQ_PR_strong) &&
2248f4a2713aSLionel Sambuc PropertyTy->isBlockPointerType())
2249f4a2713aSLionel Sambuc Diag(Loc, diag::warn_objc_property_retain_of_block);
2250f4a2713aSLionel Sambuc
2251f4a2713aSLionel Sambuc if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
2252f4a2713aSLionel Sambuc (Attributes & ObjCDeclSpec::DQ_PR_setter))
2253f4a2713aSLionel Sambuc Diag(Loc, diag::warn_objc_readonly_property_has_setter);
2254f4a2713aSLionel Sambuc
2255f4a2713aSLionel Sambuc }
2256