106f32e7eSjoerg //===--- SemaObjCProperty.cpp - Semantic Analysis for ObjC @property ------===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg //
906f32e7eSjoerg // This file implements semantic analysis for Objective C @property and
1006f32e7eSjoerg // @synthesize declarations.
1106f32e7eSjoerg //
1206f32e7eSjoerg //===----------------------------------------------------------------------===//
1306f32e7eSjoerg
1406f32e7eSjoerg #include "clang/Sema/SemaInternal.h"
1506f32e7eSjoerg #include "clang/AST/ASTMutationListener.h"
1606f32e7eSjoerg #include "clang/AST/DeclObjC.h"
1706f32e7eSjoerg #include "clang/AST/ExprCXX.h"
1806f32e7eSjoerg #include "clang/AST/ExprObjC.h"
1906f32e7eSjoerg #include "clang/Basic/SourceManager.h"
2006f32e7eSjoerg #include "clang/Lex/Lexer.h"
2106f32e7eSjoerg #include "clang/Lex/Preprocessor.h"
2206f32e7eSjoerg #include "clang/Sema/Initialization.h"
2306f32e7eSjoerg #include "llvm/ADT/DenseSet.h"
2406f32e7eSjoerg #include "llvm/ADT/SmallString.h"
2506f32e7eSjoerg
2606f32e7eSjoerg using namespace clang;
2706f32e7eSjoerg
2806f32e7eSjoerg //===----------------------------------------------------------------------===//
2906f32e7eSjoerg // Grammar actions.
3006f32e7eSjoerg //===----------------------------------------------------------------------===//
3106f32e7eSjoerg
3206f32e7eSjoerg /// getImpliedARCOwnership - Given a set of property attributes and a
3306f32e7eSjoerg /// type, infer an expected lifetime. The type's ownership qualification
3406f32e7eSjoerg /// is not considered.
3506f32e7eSjoerg ///
3606f32e7eSjoerg /// Returns OCL_None if the attributes as stated do not imply an ownership.
3706f32e7eSjoerg /// Never returns OCL_Autoreleasing.
38*13fbcb42Sjoerg static Qualifiers::ObjCLifetime
getImpliedARCOwnership(ObjCPropertyAttribute::Kind attrs,QualType type)39*13fbcb42Sjoerg getImpliedARCOwnership(ObjCPropertyAttribute::Kind attrs, QualType type) {
4006f32e7eSjoerg // retain, strong, copy, weak, and unsafe_unretained are only legal
4106f32e7eSjoerg // on properties of retainable pointer type.
42*13fbcb42Sjoerg if (attrs &
43*13fbcb42Sjoerg (ObjCPropertyAttribute::kind_retain | ObjCPropertyAttribute::kind_strong |
44*13fbcb42Sjoerg ObjCPropertyAttribute::kind_copy)) {
4506f32e7eSjoerg return Qualifiers::OCL_Strong;
46*13fbcb42Sjoerg } else if (attrs & ObjCPropertyAttribute::kind_weak) {
4706f32e7eSjoerg return Qualifiers::OCL_Weak;
48*13fbcb42Sjoerg } else if (attrs & ObjCPropertyAttribute::kind_unsafe_unretained) {
4906f32e7eSjoerg return Qualifiers::OCL_ExplicitNone;
5006f32e7eSjoerg }
5106f32e7eSjoerg
5206f32e7eSjoerg // assign can appear on other types, so we have to check the
5306f32e7eSjoerg // property type.
54*13fbcb42Sjoerg if (attrs & ObjCPropertyAttribute::kind_assign &&
5506f32e7eSjoerg type->isObjCRetainableType()) {
5606f32e7eSjoerg return Qualifiers::OCL_ExplicitNone;
5706f32e7eSjoerg }
5806f32e7eSjoerg
5906f32e7eSjoerg return Qualifiers::OCL_None;
6006f32e7eSjoerg }
6106f32e7eSjoerg
6206f32e7eSjoerg /// Check the internal consistency of a property declaration with
6306f32e7eSjoerg /// an explicit ownership qualifier.
checkPropertyDeclWithOwnership(Sema & S,ObjCPropertyDecl * property)6406f32e7eSjoerg static void checkPropertyDeclWithOwnership(Sema &S,
6506f32e7eSjoerg ObjCPropertyDecl *property) {
6606f32e7eSjoerg if (property->isInvalidDecl()) return;
6706f32e7eSjoerg
68*13fbcb42Sjoerg ObjCPropertyAttribute::Kind propertyKind = property->getPropertyAttributes();
6906f32e7eSjoerg Qualifiers::ObjCLifetime propertyLifetime
7006f32e7eSjoerg = property->getType().getObjCLifetime();
7106f32e7eSjoerg
7206f32e7eSjoerg assert(propertyLifetime != Qualifiers::OCL_None);
7306f32e7eSjoerg
7406f32e7eSjoerg Qualifiers::ObjCLifetime expectedLifetime
7506f32e7eSjoerg = getImpliedARCOwnership(propertyKind, property->getType());
7606f32e7eSjoerg if (!expectedLifetime) {
7706f32e7eSjoerg // We have a lifetime qualifier but no dominating property
7806f32e7eSjoerg // attribute. That's okay, but restore reasonable invariants by
7906f32e7eSjoerg // setting the property attribute according to the lifetime
8006f32e7eSjoerg // qualifier.
81*13fbcb42Sjoerg ObjCPropertyAttribute::Kind attr;
8206f32e7eSjoerg if (propertyLifetime == Qualifiers::OCL_Strong) {
83*13fbcb42Sjoerg attr = ObjCPropertyAttribute::kind_strong;
8406f32e7eSjoerg } else if (propertyLifetime == Qualifiers::OCL_Weak) {
85*13fbcb42Sjoerg attr = ObjCPropertyAttribute::kind_weak;
8606f32e7eSjoerg } else {
8706f32e7eSjoerg assert(propertyLifetime == Qualifiers::OCL_ExplicitNone);
88*13fbcb42Sjoerg attr = ObjCPropertyAttribute::kind_unsafe_unretained;
8906f32e7eSjoerg }
9006f32e7eSjoerg property->setPropertyAttributes(attr);
9106f32e7eSjoerg return;
9206f32e7eSjoerg }
9306f32e7eSjoerg
9406f32e7eSjoerg if (propertyLifetime == expectedLifetime) return;
9506f32e7eSjoerg
9606f32e7eSjoerg property->setInvalidDecl();
9706f32e7eSjoerg S.Diag(property->getLocation(),
9806f32e7eSjoerg diag::err_arc_inconsistent_property_ownership)
9906f32e7eSjoerg << property->getDeclName()
10006f32e7eSjoerg << expectedLifetime
10106f32e7eSjoerg << propertyLifetime;
10206f32e7eSjoerg }
10306f32e7eSjoerg
10406f32e7eSjoerg /// Check this Objective-C property against a property declared in the
10506f32e7eSjoerg /// given protocol.
10606f32e7eSjoerg static void
CheckPropertyAgainstProtocol(Sema & S,ObjCPropertyDecl * Prop,ObjCProtocolDecl * Proto,llvm::SmallPtrSetImpl<ObjCProtocolDecl * > & Known)10706f32e7eSjoerg CheckPropertyAgainstProtocol(Sema &S, ObjCPropertyDecl *Prop,
10806f32e7eSjoerg ObjCProtocolDecl *Proto,
10906f32e7eSjoerg llvm::SmallPtrSetImpl<ObjCProtocolDecl *> &Known) {
11006f32e7eSjoerg // Have we seen this protocol before?
11106f32e7eSjoerg if (!Known.insert(Proto).second)
11206f32e7eSjoerg return;
11306f32e7eSjoerg
11406f32e7eSjoerg // Look for a property with the same name.
115*13fbcb42Sjoerg if (ObjCPropertyDecl *ProtoProp =
116*13fbcb42Sjoerg Proto->lookup(Prop->getDeclName()).find_first<ObjCPropertyDecl>()) {
11706f32e7eSjoerg S.DiagnosePropertyMismatch(Prop, ProtoProp, Proto->getIdentifier(), true);
11806f32e7eSjoerg return;
11906f32e7eSjoerg }
12006f32e7eSjoerg
12106f32e7eSjoerg // Check this property against any protocols we inherit.
12206f32e7eSjoerg for (auto *P : Proto->protocols())
12306f32e7eSjoerg CheckPropertyAgainstProtocol(S, Prop, P, Known);
12406f32e7eSjoerg }
12506f32e7eSjoerg
deducePropertyOwnershipFromType(Sema & S,QualType T)12606f32e7eSjoerg static unsigned deducePropertyOwnershipFromType(Sema &S, QualType T) {
12706f32e7eSjoerg // In GC mode, just look for the __weak qualifier.
12806f32e7eSjoerg if (S.getLangOpts().getGC() != LangOptions::NonGC) {
129*13fbcb42Sjoerg if (T.isObjCGCWeak())
130*13fbcb42Sjoerg return ObjCPropertyAttribute::kind_weak;
13106f32e7eSjoerg
13206f32e7eSjoerg // In ARC/MRC, look for an explicit ownership qualifier.
13306f32e7eSjoerg // For some reason, this only applies to __weak.
13406f32e7eSjoerg } else if (auto ownership = T.getObjCLifetime()) {
13506f32e7eSjoerg switch (ownership) {
13606f32e7eSjoerg case Qualifiers::OCL_Weak:
137*13fbcb42Sjoerg return ObjCPropertyAttribute::kind_weak;
13806f32e7eSjoerg case Qualifiers::OCL_Strong:
139*13fbcb42Sjoerg return ObjCPropertyAttribute::kind_strong;
14006f32e7eSjoerg case Qualifiers::OCL_ExplicitNone:
141*13fbcb42Sjoerg return ObjCPropertyAttribute::kind_unsafe_unretained;
14206f32e7eSjoerg case Qualifiers::OCL_Autoreleasing:
14306f32e7eSjoerg case Qualifiers::OCL_None:
14406f32e7eSjoerg return 0;
14506f32e7eSjoerg }
14606f32e7eSjoerg llvm_unreachable("bad qualifier");
14706f32e7eSjoerg }
14806f32e7eSjoerg
14906f32e7eSjoerg return 0;
15006f32e7eSjoerg }
15106f32e7eSjoerg
15206f32e7eSjoerg static const unsigned OwnershipMask =
153*13fbcb42Sjoerg (ObjCPropertyAttribute::kind_assign | ObjCPropertyAttribute::kind_retain |
154*13fbcb42Sjoerg ObjCPropertyAttribute::kind_copy | ObjCPropertyAttribute::kind_weak |
155*13fbcb42Sjoerg ObjCPropertyAttribute::kind_strong |
156*13fbcb42Sjoerg ObjCPropertyAttribute::kind_unsafe_unretained);
15706f32e7eSjoerg
getOwnershipRule(unsigned attr)15806f32e7eSjoerg static unsigned getOwnershipRule(unsigned attr) {
15906f32e7eSjoerg unsigned result = attr & OwnershipMask;
16006f32e7eSjoerg
16106f32e7eSjoerg // From an ownership perspective, assign and unsafe_unretained are
16206f32e7eSjoerg // identical; make sure one also implies the other.
163*13fbcb42Sjoerg if (result & (ObjCPropertyAttribute::kind_assign |
164*13fbcb42Sjoerg ObjCPropertyAttribute::kind_unsafe_unretained)) {
165*13fbcb42Sjoerg result |= ObjCPropertyAttribute::kind_assign |
166*13fbcb42Sjoerg ObjCPropertyAttribute::kind_unsafe_unretained;
16706f32e7eSjoerg }
16806f32e7eSjoerg
16906f32e7eSjoerg return result;
17006f32e7eSjoerg }
17106f32e7eSjoerg
ActOnProperty(Scope * S,SourceLocation AtLoc,SourceLocation LParenLoc,FieldDeclarator & FD,ObjCDeclSpec & ODS,Selector GetterSel,Selector SetterSel,tok::ObjCKeywordKind MethodImplKind,DeclContext * lexicalDC)17206f32e7eSjoerg Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
17306f32e7eSjoerg SourceLocation LParenLoc,
17406f32e7eSjoerg FieldDeclarator &FD,
17506f32e7eSjoerg ObjCDeclSpec &ODS,
17606f32e7eSjoerg Selector GetterSel,
17706f32e7eSjoerg Selector SetterSel,
17806f32e7eSjoerg tok::ObjCKeywordKind MethodImplKind,
17906f32e7eSjoerg DeclContext *lexicalDC) {
18006f32e7eSjoerg unsigned Attributes = ODS.getPropertyAttributes();
181*13fbcb42Sjoerg FD.D.setObjCWeakProperty((Attributes & ObjCPropertyAttribute::kind_weak) !=
182*13fbcb42Sjoerg 0);
18306f32e7eSjoerg TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S);
18406f32e7eSjoerg QualType T = TSI->getType();
18506f32e7eSjoerg if (!getOwnershipRule(Attributes)) {
18606f32e7eSjoerg Attributes |= deducePropertyOwnershipFromType(*this, T);
18706f32e7eSjoerg }
188*13fbcb42Sjoerg bool isReadWrite = ((Attributes & ObjCPropertyAttribute::kind_readwrite) ||
18906f32e7eSjoerg // default is readwrite!
190*13fbcb42Sjoerg !(Attributes & ObjCPropertyAttribute::kind_readonly));
19106f32e7eSjoerg
19206f32e7eSjoerg // Proceed with constructing the ObjCPropertyDecls.
19306f32e7eSjoerg ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(CurContext);
19406f32e7eSjoerg ObjCPropertyDecl *Res = nullptr;
19506f32e7eSjoerg if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
19606f32e7eSjoerg if (CDecl->IsClassExtension()) {
19706f32e7eSjoerg Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc,
19806f32e7eSjoerg FD,
19906f32e7eSjoerg GetterSel, ODS.getGetterNameLoc(),
20006f32e7eSjoerg SetterSel, ODS.getSetterNameLoc(),
20106f32e7eSjoerg isReadWrite, Attributes,
20206f32e7eSjoerg ODS.getPropertyAttributes(),
20306f32e7eSjoerg T, TSI, MethodImplKind);
20406f32e7eSjoerg if (!Res)
20506f32e7eSjoerg return nullptr;
20606f32e7eSjoerg }
20706f32e7eSjoerg }
20806f32e7eSjoerg
20906f32e7eSjoerg if (!Res) {
21006f32e7eSjoerg Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD,
21106f32e7eSjoerg GetterSel, ODS.getGetterNameLoc(), SetterSel,
21206f32e7eSjoerg ODS.getSetterNameLoc(), isReadWrite, Attributes,
21306f32e7eSjoerg ODS.getPropertyAttributes(), T, TSI,
21406f32e7eSjoerg MethodImplKind);
21506f32e7eSjoerg if (lexicalDC)
21606f32e7eSjoerg Res->setLexicalDeclContext(lexicalDC);
21706f32e7eSjoerg }
21806f32e7eSjoerg
21906f32e7eSjoerg // Validate the attributes on the @property.
22006f32e7eSjoerg CheckObjCPropertyAttributes(Res, AtLoc, Attributes,
22106f32e7eSjoerg (isa<ObjCInterfaceDecl>(ClassDecl) ||
22206f32e7eSjoerg isa<ObjCProtocolDecl>(ClassDecl)));
22306f32e7eSjoerg
22406f32e7eSjoerg // Check consistency if the type has explicit ownership qualification.
22506f32e7eSjoerg if (Res->getType().getObjCLifetime())
22606f32e7eSjoerg checkPropertyDeclWithOwnership(*this, Res);
22706f32e7eSjoerg
22806f32e7eSjoerg llvm::SmallPtrSet<ObjCProtocolDecl *, 16> KnownProtos;
22906f32e7eSjoerg if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
23006f32e7eSjoerg // For a class, compare the property against a property in our superclass.
23106f32e7eSjoerg bool FoundInSuper = false;
23206f32e7eSjoerg ObjCInterfaceDecl *CurrentInterfaceDecl = IFace;
23306f32e7eSjoerg while (ObjCInterfaceDecl *Super = CurrentInterfaceDecl->getSuperClass()) {
234*13fbcb42Sjoerg if (ObjCPropertyDecl *SuperProp =
235*13fbcb42Sjoerg Super->lookup(Res->getDeclName()).find_first<ObjCPropertyDecl>()) {
23606f32e7eSjoerg DiagnosePropertyMismatch(Res, SuperProp, Super->getIdentifier(), false);
23706f32e7eSjoerg FoundInSuper = true;
23806f32e7eSjoerg break;
23906f32e7eSjoerg }
24006f32e7eSjoerg CurrentInterfaceDecl = Super;
24106f32e7eSjoerg }
24206f32e7eSjoerg
24306f32e7eSjoerg if (FoundInSuper) {
24406f32e7eSjoerg // Also compare the property against a property in our protocols.
24506f32e7eSjoerg for (auto *P : CurrentInterfaceDecl->protocols()) {
24606f32e7eSjoerg CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos);
24706f32e7eSjoerg }
24806f32e7eSjoerg } else {
24906f32e7eSjoerg // Slower path: look in all protocols we referenced.
25006f32e7eSjoerg for (auto *P : IFace->all_referenced_protocols()) {
25106f32e7eSjoerg CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos);
25206f32e7eSjoerg }
25306f32e7eSjoerg }
25406f32e7eSjoerg } else if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
25506f32e7eSjoerg // We don't check if class extension. Because properties in class extension
25606f32e7eSjoerg // are meant to override some of the attributes and checking has already done
25706f32e7eSjoerg // when property in class extension is constructed.
25806f32e7eSjoerg if (!Cat->IsClassExtension())
25906f32e7eSjoerg for (auto *P : Cat->protocols())
26006f32e7eSjoerg CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos);
26106f32e7eSjoerg } else {
26206f32e7eSjoerg ObjCProtocolDecl *Proto = cast<ObjCProtocolDecl>(ClassDecl);
26306f32e7eSjoerg for (auto *P : Proto->protocols())
26406f32e7eSjoerg CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos);
26506f32e7eSjoerg }
26606f32e7eSjoerg
26706f32e7eSjoerg ActOnDocumentableDecl(Res);
26806f32e7eSjoerg return Res;
26906f32e7eSjoerg }
27006f32e7eSjoerg
271*13fbcb42Sjoerg static ObjCPropertyAttribute::Kind
makePropertyAttributesAsWritten(unsigned Attributes)27206f32e7eSjoerg makePropertyAttributesAsWritten(unsigned Attributes) {
27306f32e7eSjoerg unsigned attributesAsWritten = 0;
274*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_readonly)
275*13fbcb42Sjoerg attributesAsWritten |= ObjCPropertyAttribute::kind_readonly;
276*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_readwrite)
277*13fbcb42Sjoerg attributesAsWritten |= ObjCPropertyAttribute::kind_readwrite;
278*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_getter)
279*13fbcb42Sjoerg attributesAsWritten |= ObjCPropertyAttribute::kind_getter;
280*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_setter)
281*13fbcb42Sjoerg attributesAsWritten |= ObjCPropertyAttribute::kind_setter;
282*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_assign)
283*13fbcb42Sjoerg attributesAsWritten |= ObjCPropertyAttribute::kind_assign;
284*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_retain)
285*13fbcb42Sjoerg attributesAsWritten |= ObjCPropertyAttribute::kind_retain;
286*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_strong)
287*13fbcb42Sjoerg attributesAsWritten |= ObjCPropertyAttribute::kind_strong;
288*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_weak)
289*13fbcb42Sjoerg attributesAsWritten |= ObjCPropertyAttribute::kind_weak;
290*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_copy)
291*13fbcb42Sjoerg attributesAsWritten |= ObjCPropertyAttribute::kind_copy;
292*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained)
293*13fbcb42Sjoerg attributesAsWritten |= ObjCPropertyAttribute::kind_unsafe_unretained;
294*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_nonatomic)
295*13fbcb42Sjoerg attributesAsWritten |= ObjCPropertyAttribute::kind_nonatomic;
296*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_atomic)
297*13fbcb42Sjoerg attributesAsWritten |= ObjCPropertyAttribute::kind_atomic;
298*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_class)
299*13fbcb42Sjoerg attributesAsWritten |= ObjCPropertyAttribute::kind_class;
300*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_direct)
301*13fbcb42Sjoerg attributesAsWritten |= ObjCPropertyAttribute::kind_direct;
30206f32e7eSjoerg
303*13fbcb42Sjoerg return (ObjCPropertyAttribute::Kind)attributesAsWritten;
30406f32e7eSjoerg }
30506f32e7eSjoerg
LocPropertyAttribute(ASTContext & Context,const char * attrName,SourceLocation LParenLoc,SourceLocation & Loc)30606f32e7eSjoerg static bool LocPropertyAttribute( ASTContext &Context, const char *attrName,
30706f32e7eSjoerg SourceLocation LParenLoc, SourceLocation &Loc) {
30806f32e7eSjoerg if (LParenLoc.isMacroID())
30906f32e7eSjoerg return false;
31006f32e7eSjoerg
31106f32e7eSjoerg SourceManager &SM = Context.getSourceManager();
31206f32e7eSjoerg std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(LParenLoc);
31306f32e7eSjoerg // Try to load the file buffer.
31406f32e7eSjoerg bool invalidTemp = false;
31506f32e7eSjoerg StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
31606f32e7eSjoerg if (invalidTemp)
31706f32e7eSjoerg return false;
31806f32e7eSjoerg const char *tokenBegin = file.data() + locInfo.second;
31906f32e7eSjoerg
32006f32e7eSjoerg // Lex from the start of the given location.
32106f32e7eSjoerg Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
32206f32e7eSjoerg Context.getLangOpts(),
32306f32e7eSjoerg file.begin(), tokenBegin, file.end());
32406f32e7eSjoerg Token Tok;
32506f32e7eSjoerg do {
32606f32e7eSjoerg lexer.LexFromRawLexer(Tok);
32706f32e7eSjoerg if (Tok.is(tok::raw_identifier) && Tok.getRawIdentifier() == attrName) {
32806f32e7eSjoerg Loc = Tok.getLocation();
32906f32e7eSjoerg return true;
33006f32e7eSjoerg }
33106f32e7eSjoerg } while (Tok.isNot(tok::r_paren));
33206f32e7eSjoerg return false;
33306f32e7eSjoerg }
33406f32e7eSjoerg
33506f32e7eSjoerg /// Check for a mismatch in the atomicity of the given properties.
checkAtomicPropertyMismatch(Sema & S,ObjCPropertyDecl * OldProperty,ObjCPropertyDecl * NewProperty,bool PropagateAtomicity)33606f32e7eSjoerg static void checkAtomicPropertyMismatch(Sema &S,
33706f32e7eSjoerg ObjCPropertyDecl *OldProperty,
33806f32e7eSjoerg ObjCPropertyDecl *NewProperty,
33906f32e7eSjoerg bool PropagateAtomicity) {
34006f32e7eSjoerg // If the atomicity of both matches, we're done.
341*13fbcb42Sjoerg bool OldIsAtomic = (OldProperty->getPropertyAttributes() &
342*13fbcb42Sjoerg ObjCPropertyAttribute::kind_nonatomic) == 0;
343*13fbcb42Sjoerg bool NewIsAtomic = (NewProperty->getPropertyAttributes() &
344*13fbcb42Sjoerg ObjCPropertyAttribute::kind_nonatomic) == 0;
34506f32e7eSjoerg if (OldIsAtomic == NewIsAtomic) return;
34606f32e7eSjoerg
34706f32e7eSjoerg // Determine whether the given property is readonly and implicitly
34806f32e7eSjoerg // atomic.
34906f32e7eSjoerg auto isImplicitlyReadonlyAtomic = [](ObjCPropertyDecl *Property) -> bool {
35006f32e7eSjoerg // Is it readonly?
35106f32e7eSjoerg auto Attrs = Property->getPropertyAttributes();
352*13fbcb42Sjoerg if ((Attrs & ObjCPropertyAttribute::kind_readonly) == 0)
353*13fbcb42Sjoerg return false;
35406f32e7eSjoerg
35506f32e7eSjoerg // Is it nonatomic?
356*13fbcb42Sjoerg if (Attrs & ObjCPropertyAttribute::kind_nonatomic)
357*13fbcb42Sjoerg return false;
35806f32e7eSjoerg
35906f32e7eSjoerg // Was 'atomic' specified directly?
36006f32e7eSjoerg if (Property->getPropertyAttributesAsWritten() &
361*13fbcb42Sjoerg ObjCPropertyAttribute::kind_atomic)
36206f32e7eSjoerg return false;
36306f32e7eSjoerg
36406f32e7eSjoerg return true;
36506f32e7eSjoerg };
36606f32e7eSjoerg
36706f32e7eSjoerg // If we're allowed to propagate atomicity, and the new property did
36806f32e7eSjoerg // not specify atomicity at all, propagate.
369*13fbcb42Sjoerg const unsigned AtomicityMask = (ObjCPropertyAttribute::kind_atomic |
370*13fbcb42Sjoerg ObjCPropertyAttribute::kind_nonatomic);
37106f32e7eSjoerg if (PropagateAtomicity &&
37206f32e7eSjoerg ((NewProperty->getPropertyAttributesAsWritten() & AtomicityMask) == 0)) {
37306f32e7eSjoerg unsigned Attrs = NewProperty->getPropertyAttributes();
37406f32e7eSjoerg Attrs = Attrs & ~AtomicityMask;
37506f32e7eSjoerg if (OldIsAtomic)
376*13fbcb42Sjoerg Attrs |= ObjCPropertyAttribute::kind_atomic;
37706f32e7eSjoerg else
378*13fbcb42Sjoerg Attrs |= ObjCPropertyAttribute::kind_nonatomic;
37906f32e7eSjoerg
38006f32e7eSjoerg NewProperty->overwritePropertyAttributes(Attrs);
38106f32e7eSjoerg return;
38206f32e7eSjoerg }
38306f32e7eSjoerg
38406f32e7eSjoerg // One of the properties is atomic; if it's a readonly property, and
38506f32e7eSjoerg // 'atomic' wasn't explicitly specified, we're okay.
38606f32e7eSjoerg if ((OldIsAtomic && isImplicitlyReadonlyAtomic(OldProperty)) ||
38706f32e7eSjoerg (NewIsAtomic && isImplicitlyReadonlyAtomic(NewProperty)))
38806f32e7eSjoerg return;
38906f32e7eSjoerg
39006f32e7eSjoerg // Diagnose the conflict.
39106f32e7eSjoerg const IdentifierInfo *OldContextName;
39206f32e7eSjoerg auto *OldDC = OldProperty->getDeclContext();
39306f32e7eSjoerg if (auto Category = dyn_cast<ObjCCategoryDecl>(OldDC))
39406f32e7eSjoerg OldContextName = Category->getClassInterface()->getIdentifier();
39506f32e7eSjoerg else
39606f32e7eSjoerg OldContextName = cast<ObjCContainerDecl>(OldDC)->getIdentifier();
39706f32e7eSjoerg
39806f32e7eSjoerg S.Diag(NewProperty->getLocation(), diag::warn_property_attribute)
39906f32e7eSjoerg << NewProperty->getDeclName() << "atomic"
40006f32e7eSjoerg << OldContextName;
40106f32e7eSjoerg S.Diag(OldProperty->getLocation(), diag::note_property_declare);
40206f32e7eSjoerg }
40306f32e7eSjoerg
40406f32e7eSjoerg ObjCPropertyDecl *
HandlePropertyInClassExtension(Scope * S,SourceLocation AtLoc,SourceLocation LParenLoc,FieldDeclarator & FD,Selector GetterSel,SourceLocation GetterNameLoc,Selector SetterSel,SourceLocation SetterNameLoc,const bool isReadWrite,unsigned & Attributes,const unsigned AttributesAsWritten,QualType T,TypeSourceInfo * TSI,tok::ObjCKeywordKind MethodImplKind)40506f32e7eSjoerg Sema::HandlePropertyInClassExtension(Scope *S,
40606f32e7eSjoerg SourceLocation AtLoc,
40706f32e7eSjoerg SourceLocation LParenLoc,
40806f32e7eSjoerg FieldDeclarator &FD,
40906f32e7eSjoerg Selector GetterSel,
41006f32e7eSjoerg SourceLocation GetterNameLoc,
41106f32e7eSjoerg Selector SetterSel,
41206f32e7eSjoerg SourceLocation SetterNameLoc,
41306f32e7eSjoerg const bool isReadWrite,
41406f32e7eSjoerg unsigned &Attributes,
41506f32e7eSjoerg const unsigned AttributesAsWritten,
41606f32e7eSjoerg QualType T,
41706f32e7eSjoerg TypeSourceInfo *TSI,
41806f32e7eSjoerg tok::ObjCKeywordKind MethodImplKind) {
41906f32e7eSjoerg ObjCCategoryDecl *CDecl = cast<ObjCCategoryDecl>(CurContext);
42006f32e7eSjoerg // Diagnose if this property is already in continuation class.
42106f32e7eSjoerg DeclContext *DC = CurContext;
42206f32e7eSjoerg IdentifierInfo *PropertyId = FD.D.getIdentifier();
42306f32e7eSjoerg ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface();
42406f32e7eSjoerg
42506f32e7eSjoerg // We need to look in the @interface to see if the @property was
42606f32e7eSjoerg // already declared.
42706f32e7eSjoerg if (!CCPrimary) {
42806f32e7eSjoerg Diag(CDecl->getLocation(), diag::err_continuation_class);
42906f32e7eSjoerg return nullptr;
43006f32e7eSjoerg }
43106f32e7eSjoerg
432*13fbcb42Sjoerg bool isClassProperty =
433*13fbcb42Sjoerg (AttributesAsWritten & ObjCPropertyAttribute::kind_class) ||
434*13fbcb42Sjoerg (Attributes & ObjCPropertyAttribute::kind_class);
43506f32e7eSjoerg
43606f32e7eSjoerg // Find the property in the extended class's primary class or
43706f32e7eSjoerg // extensions.
43806f32e7eSjoerg ObjCPropertyDecl *PIDecl = CCPrimary->FindPropertyVisibleInPrimaryClass(
43906f32e7eSjoerg PropertyId, ObjCPropertyDecl::getQueryKind(isClassProperty));
44006f32e7eSjoerg
44106f32e7eSjoerg // If we found a property in an extension, complain.
44206f32e7eSjoerg if (PIDecl && isa<ObjCCategoryDecl>(PIDecl->getDeclContext())) {
44306f32e7eSjoerg Diag(AtLoc, diag::err_duplicate_property);
44406f32e7eSjoerg Diag(PIDecl->getLocation(), diag::note_property_declare);
44506f32e7eSjoerg return nullptr;
44606f32e7eSjoerg }
44706f32e7eSjoerg
44806f32e7eSjoerg // Check for consistency with the previous declaration, if there is one.
44906f32e7eSjoerg if (PIDecl) {
45006f32e7eSjoerg // A readonly property declared in the primary class can be refined
45106f32e7eSjoerg // by adding a readwrite property within an extension.
45206f32e7eSjoerg // Anything else is an error.
45306f32e7eSjoerg if (!(PIDecl->isReadOnly() && isReadWrite)) {
45406f32e7eSjoerg // Tailor the diagnostics for the common case where a readwrite
45506f32e7eSjoerg // property is declared both in the @interface and the continuation.
45606f32e7eSjoerg // This is a common error where the user often intended the original
45706f32e7eSjoerg // declaration to be readonly.
45806f32e7eSjoerg unsigned diag =
459*13fbcb42Sjoerg (Attributes & ObjCPropertyAttribute::kind_readwrite) &&
46006f32e7eSjoerg (PIDecl->getPropertyAttributesAsWritten() &
461*13fbcb42Sjoerg ObjCPropertyAttribute::kind_readwrite)
46206f32e7eSjoerg ? diag::err_use_continuation_class_redeclaration_readwrite
46306f32e7eSjoerg : diag::err_use_continuation_class;
46406f32e7eSjoerg Diag(AtLoc, diag)
46506f32e7eSjoerg << CCPrimary->getDeclName();
46606f32e7eSjoerg Diag(PIDecl->getLocation(), diag::note_property_declare);
46706f32e7eSjoerg return nullptr;
46806f32e7eSjoerg }
46906f32e7eSjoerg
47006f32e7eSjoerg // Check for consistency of getters.
47106f32e7eSjoerg if (PIDecl->getGetterName() != GetterSel) {
47206f32e7eSjoerg // If the getter was written explicitly, complain.
473*13fbcb42Sjoerg if (AttributesAsWritten & ObjCPropertyAttribute::kind_getter) {
47406f32e7eSjoerg Diag(AtLoc, diag::warn_property_redecl_getter_mismatch)
47506f32e7eSjoerg << PIDecl->getGetterName() << GetterSel;
47606f32e7eSjoerg Diag(PIDecl->getLocation(), diag::note_property_declare);
47706f32e7eSjoerg }
47806f32e7eSjoerg
47906f32e7eSjoerg // Always adopt the getter from the original declaration.
48006f32e7eSjoerg GetterSel = PIDecl->getGetterName();
481*13fbcb42Sjoerg Attributes |= ObjCPropertyAttribute::kind_getter;
48206f32e7eSjoerg }
48306f32e7eSjoerg
48406f32e7eSjoerg // Check consistency of ownership.
48506f32e7eSjoerg unsigned ExistingOwnership
48606f32e7eSjoerg = getOwnershipRule(PIDecl->getPropertyAttributes());
48706f32e7eSjoerg unsigned NewOwnership = getOwnershipRule(Attributes);
48806f32e7eSjoerg if (ExistingOwnership && NewOwnership != ExistingOwnership) {
48906f32e7eSjoerg // If the ownership was written explicitly, complain.
49006f32e7eSjoerg if (getOwnershipRule(AttributesAsWritten)) {
49106f32e7eSjoerg Diag(AtLoc, diag::warn_property_attr_mismatch);
49206f32e7eSjoerg Diag(PIDecl->getLocation(), diag::note_property_declare);
49306f32e7eSjoerg }
49406f32e7eSjoerg
49506f32e7eSjoerg // Take the ownership from the original property.
49606f32e7eSjoerg Attributes = (Attributes & ~OwnershipMask) | ExistingOwnership;
49706f32e7eSjoerg }
49806f32e7eSjoerg
49906f32e7eSjoerg // If the redeclaration is 'weak' but the original property is not,
500*13fbcb42Sjoerg if ((Attributes & ObjCPropertyAttribute::kind_weak) &&
501*13fbcb42Sjoerg !(PIDecl->getPropertyAttributesAsWritten() &
502*13fbcb42Sjoerg ObjCPropertyAttribute::kind_weak) &&
50306f32e7eSjoerg PIDecl->getType()->getAs<ObjCObjectPointerType>() &&
50406f32e7eSjoerg PIDecl->getType().getObjCLifetime() == Qualifiers::OCL_None) {
50506f32e7eSjoerg Diag(AtLoc, diag::warn_property_implicitly_mismatched);
50606f32e7eSjoerg Diag(PIDecl->getLocation(), diag::note_property_declare);
50706f32e7eSjoerg }
50806f32e7eSjoerg }
50906f32e7eSjoerg
51006f32e7eSjoerg // Create a new ObjCPropertyDecl with the DeclContext being
51106f32e7eSjoerg // the class extension.
51206f32e7eSjoerg ObjCPropertyDecl *PDecl = CreatePropertyDecl(S, CDecl, AtLoc, LParenLoc,
51306f32e7eSjoerg FD, GetterSel, GetterNameLoc,
51406f32e7eSjoerg SetterSel, SetterNameLoc,
51506f32e7eSjoerg isReadWrite,
51606f32e7eSjoerg Attributes, AttributesAsWritten,
51706f32e7eSjoerg T, TSI, MethodImplKind, DC);
51806f32e7eSjoerg
51906f32e7eSjoerg // If there was no declaration of a property with the same name in
52006f32e7eSjoerg // the primary class, we're done.
52106f32e7eSjoerg if (!PIDecl) {
52206f32e7eSjoerg ProcessPropertyDecl(PDecl);
52306f32e7eSjoerg return PDecl;
52406f32e7eSjoerg }
52506f32e7eSjoerg
52606f32e7eSjoerg if (!Context.hasSameType(PIDecl->getType(), PDecl->getType())) {
52706f32e7eSjoerg bool IncompatibleObjC = false;
52806f32e7eSjoerg QualType ConvertedType;
52906f32e7eSjoerg // Relax the strict type matching for property type in continuation class.
53006f32e7eSjoerg // Allow property object type of continuation class to be different as long
53106f32e7eSjoerg // as it narrows the object type in its primary class property. Note that
53206f32e7eSjoerg // this conversion is safe only because the wider type is for a 'readonly'
53306f32e7eSjoerg // property in primary class and 'narrowed' type for a 'readwrite' property
53406f32e7eSjoerg // in continuation class.
53506f32e7eSjoerg QualType PrimaryClassPropertyT = Context.getCanonicalType(PIDecl->getType());
53606f32e7eSjoerg QualType ClassExtPropertyT = Context.getCanonicalType(PDecl->getType());
53706f32e7eSjoerg if (!isa<ObjCObjectPointerType>(PrimaryClassPropertyT) ||
53806f32e7eSjoerg !isa<ObjCObjectPointerType>(ClassExtPropertyT) ||
53906f32e7eSjoerg (!isObjCPointerConversion(ClassExtPropertyT, PrimaryClassPropertyT,
54006f32e7eSjoerg ConvertedType, IncompatibleObjC))
54106f32e7eSjoerg || IncompatibleObjC) {
54206f32e7eSjoerg Diag(AtLoc,
54306f32e7eSjoerg diag::err_type_mismatch_continuation_class) << PDecl->getType();
54406f32e7eSjoerg Diag(PIDecl->getLocation(), diag::note_property_declare);
54506f32e7eSjoerg return nullptr;
54606f32e7eSjoerg }
54706f32e7eSjoerg }
54806f32e7eSjoerg
54906f32e7eSjoerg // Check that atomicity of property in class extension matches the previous
55006f32e7eSjoerg // declaration.
55106f32e7eSjoerg checkAtomicPropertyMismatch(*this, PIDecl, PDecl, true);
55206f32e7eSjoerg
55306f32e7eSjoerg // Make sure getter/setter are appropriately synthesized.
55406f32e7eSjoerg ProcessPropertyDecl(PDecl);
55506f32e7eSjoerg return PDecl;
55606f32e7eSjoerg }
55706f32e7eSjoerg
CreatePropertyDecl(Scope * S,ObjCContainerDecl * CDecl,SourceLocation AtLoc,SourceLocation LParenLoc,FieldDeclarator & FD,Selector GetterSel,SourceLocation GetterNameLoc,Selector SetterSel,SourceLocation SetterNameLoc,const bool isReadWrite,const unsigned Attributes,const unsigned AttributesAsWritten,QualType T,TypeSourceInfo * TInfo,tok::ObjCKeywordKind MethodImplKind,DeclContext * lexicalDC)55806f32e7eSjoerg ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
55906f32e7eSjoerg ObjCContainerDecl *CDecl,
56006f32e7eSjoerg SourceLocation AtLoc,
56106f32e7eSjoerg SourceLocation LParenLoc,
56206f32e7eSjoerg FieldDeclarator &FD,
56306f32e7eSjoerg Selector GetterSel,
56406f32e7eSjoerg SourceLocation GetterNameLoc,
56506f32e7eSjoerg Selector SetterSel,
56606f32e7eSjoerg SourceLocation SetterNameLoc,
56706f32e7eSjoerg const bool isReadWrite,
56806f32e7eSjoerg const unsigned Attributes,
56906f32e7eSjoerg const unsigned AttributesAsWritten,
57006f32e7eSjoerg QualType T,
57106f32e7eSjoerg TypeSourceInfo *TInfo,
57206f32e7eSjoerg tok::ObjCKeywordKind MethodImplKind,
57306f32e7eSjoerg DeclContext *lexicalDC){
57406f32e7eSjoerg IdentifierInfo *PropertyId = FD.D.getIdentifier();
57506f32e7eSjoerg
57606f32e7eSjoerg // Property defaults to 'assign' if it is readwrite, unless this is ARC
57706f32e7eSjoerg // and the type is retainable.
57806f32e7eSjoerg bool isAssign;
579*13fbcb42Sjoerg if (Attributes & (ObjCPropertyAttribute::kind_assign |
580*13fbcb42Sjoerg ObjCPropertyAttribute::kind_unsafe_unretained)) {
58106f32e7eSjoerg isAssign = true;
58206f32e7eSjoerg } else if (getOwnershipRule(Attributes) || !isReadWrite) {
58306f32e7eSjoerg isAssign = false;
58406f32e7eSjoerg } else {
58506f32e7eSjoerg isAssign = (!getLangOpts().ObjCAutoRefCount ||
58606f32e7eSjoerg !T->isObjCRetainableType());
58706f32e7eSjoerg }
58806f32e7eSjoerg
58906f32e7eSjoerg // Issue a warning if property is 'assign' as default and its
59006f32e7eSjoerg // object, which is gc'able conforms to NSCopying protocol
591*13fbcb42Sjoerg if (getLangOpts().getGC() != LangOptions::NonGC && isAssign &&
592*13fbcb42Sjoerg !(Attributes & ObjCPropertyAttribute::kind_assign)) {
59306f32e7eSjoerg if (const ObjCObjectPointerType *ObjPtrTy =
59406f32e7eSjoerg T->getAs<ObjCObjectPointerType>()) {
59506f32e7eSjoerg ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
59606f32e7eSjoerg if (IDecl)
59706f32e7eSjoerg if (ObjCProtocolDecl* PNSCopying =
59806f32e7eSjoerg LookupProtocol(&Context.Idents.get("NSCopying"), AtLoc))
59906f32e7eSjoerg if (IDecl->ClassImplementsProtocol(PNSCopying, true))
60006f32e7eSjoerg Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId;
60106f32e7eSjoerg }
60206f32e7eSjoerg }
60306f32e7eSjoerg
60406f32e7eSjoerg if (T->isObjCObjectType()) {
60506f32e7eSjoerg SourceLocation StarLoc = TInfo->getTypeLoc().getEndLoc();
60606f32e7eSjoerg StarLoc = getLocForEndOfToken(StarLoc);
60706f32e7eSjoerg Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object)
60806f32e7eSjoerg << FixItHint::CreateInsertion(StarLoc, "*");
60906f32e7eSjoerg T = Context.getObjCObjectPointerType(T);
61006f32e7eSjoerg SourceLocation TLoc = TInfo->getTypeLoc().getBeginLoc();
61106f32e7eSjoerg TInfo = Context.getTrivialTypeSourceInfo(T, TLoc);
61206f32e7eSjoerg }
61306f32e7eSjoerg
61406f32e7eSjoerg DeclContext *DC = CDecl;
61506f32e7eSjoerg ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
61606f32e7eSjoerg FD.D.getIdentifierLoc(),
61706f32e7eSjoerg PropertyId, AtLoc,
61806f32e7eSjoerg LParenLoc, T, TInfo);
61906f32e7eSjoerg
620*13fbcb42Sjoerg bool isClassProperty =
621*13fbcb42Sjoerg (AttributesAsWritten & ObjCPropertyAttribute::kind_class) ||
622*13fbcb42Sjoerg (Attributes & ObjCPropertyAttribute::kind_class);
62306f32e7eSjoerg // Class property and instance property can have the same name.
62406f32e7eSjoerg if (ObjCPropertyDecl *prevDecl = ObjCPropertyDecl::findPropertyDecl(
62506f32e7eSjoerg DC, PropertyId, ObjCPropertyDecl::getQueryKind(isClassProperty))) {
62606f32e7eSjoerg Diag(PDecl->getLocation(), diag::err_duplicate_property);
62706f32e7eSjoerg Diag(prevDecl->getLocation(), diag::note_property_declare);
62806f32e7eSjoerg PDecl->setInvalidDecl();
62906f32e7eSjoerg }
63006f32e7eSjoerg else {
63106f32e7eSjoerg DC->addDecl(PDecl);
63206f32e7eSjoerg if (lexicalDC)
63306f32e7eSjoerg PDecl->setLexicalDeclContext(lexicalDC);
63406f32e7eSjoerg }
63506f32e7eSjoerg
63606f32e7eSjoerg if (T->isArrayType() || T->isFunctionType()) {
63706f32e7eSjoerg Diag(AtLoc, diag::err_property_type) << T;
63806f32e7eSjoerg PDecl->setInvalidDecl();
63906f32e7eSjoerg }
64006f32e7eSjoerg
64106f32e7eSjoerg ProcessDeclAttributes(S, PDecl, FD.D);
64206f32e7eSjoerg
64306f32e7eSjoerg // Regardless of setter/getter attribute, we save the default getter/setter
64406f32e7eSjoerg // selector names in anticipation of declaration of setter/getter methods.
64506f32e7eSjoerg PDecl->setGetterName(GetterSel, GetterNameLoc);
64606f32e7eSjoerg PDecl->setSetterName(SetterSel, SetterNameLoc);
64706f32e7eSjoerg PDecl->setPropertyAttributesAsWritten(
64806f32e7eSjoerg makePropertyAttributesAsWritten(AttributesAsWritten));
64906f32e7eSjoerg
650*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_readonly)
651*13fbcb42Sjoerg PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_readonly);
65206f32e7eSjoerg
653*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_getter)
654*13fbcb42Sjoerg PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_getter);
65506f32e7eSjoerg
656*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_setter)
657*13fbcb42Sjoerg PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_setter);
65806f32e7eSjoerg
65906f32e7eSjoerg if (isReadWrite)
660*13fbcb42Sjoerg PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_readwrite);
66106f32e7eSjoerg
662*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_retain)
663*13fbcb42Sjoerg PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_retain);
66406f32e7eSjoerg
665*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_strong)
666*13fbcb42Sjoerg PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_strong);
66706f32e7eSjoerg
668*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_weak)
669*13fbcb42Sjoerg PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_weak);
67006f32e7eSjoerg
671*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_copy)
672*13fbcb42Sjoerg PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_copy);
67306f32e7eSjoerg
674*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained)
675*13fbcb42Sjoerg PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_unsafe_unretained);
67606f32e7eSjoerg
67706f32e7eSjoerg if (isAssign)
678*13fbcb42Sjoerg PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_assign);
67906f32e7eSjoerg
68006f32e7eSjoerg // In the semantic attributes, one of nonatomic or atomic is always set.
681*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_nonatomic)
682*13fbcb42Sjoerg PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_nonatomic);
68306f32e7eSjoerg else
684*13fbcb42Sjoerg PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_atomic);
68506f32e7eSjoerg
68606f32e7eSjoerg // 'unsafe_unretained' is alias for 'assign'.
687*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained)
688*13fbcb42Sjoerg PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_assign);
68906f32e7eSjoerg if (isAssign)
690*13fbcb42Sjoerg PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_unsafe_unretained);
69106f32e7eSjoerg
69206f32e7eSjoerg if (MethodImplKind == tok::objc_required)
69306f32e7eSjoerg PDecl->setPropertyImplementation(ObjCPropertyDecl::Required);
69406f32e7eSjoerg else if (MethodImplKind == tok::objc_optional)
69506f32e7eSjoerg PDecl->setPropertyImplementation(ObjCPropertyDecl::Optional);
69606f32e7eSjoerg
697*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_nullability)
698*13fbcb42Sjoerg PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_nullability);
69906f32e7eSjoerg
700*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_null_resettable)
701*13fbcb42Sjoerg PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_null_resettable);
70206f32e7eSjoerg
703*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_class)
704*13fbcb42Sjoerg PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_class);
705*13fbcb42Sjoerg
706*13fbcb42Sjoerg if ((Attributes & ObjCPropertyAttribute::kind_direct) ||
707*13fbcb42Sjoerg CDecl->hasAttr<ObjCDirectMembersAttr>()) {
708*13fbcb42Sjoerg if (isa<ObjCProtocolDecl>(CDecl)) {
709*13fbcb42Sjoerg Diag(PDecl->getLocation(), diag::err_objc_direct_on_protocol) << true;
710*13fbcb42Sjoerg } else if (getLangOpts().ObjCRuntime.allowsDirectDispatch()) {
711*13fbcb42Sjoerg PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_direct);
712*13fbcb42Sjoerg } else {
713*13fbcb42Sjoerg Diag(PDecl->getLocation(), diag::warn_objc_direct_property_ignored)
714*13fbcb42Sjoerg << PDecl->getDeclName();
715*13fbcb42Sjoerg }
716*13fbcb42Sjoerg }
71706f32e7eSjoerg
71806f32e7eSjoerg return PDecl;
71906f32e7eSjoerg }
72006f32e7eSjoerg
checkARCPropertyImpl(Sema & S,SourceLocation propertyImplLoc,ObjCPropertyDecl * property,ObjCIvarDecl * ivar)72106f32e7eSjoerg static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc,
72206f32e7eSjoerg ObjCPropertyDecl *property,
72306f32e7eSjoerg ObjCIvarDecl *ivar) {
72406f32e7eSjoerg if (property->isInvalidDecl() || ivar->isInvalidDecl()) return;
72506f32e7eSjoerg
72606f32e7eSjoerg QualType ivarType = ivar->getType();
72706f32e7eSjoerg Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime();
72806f32e7eSjoerg
72906f32e7eSjoerg // The lifetime implied by the property's attributes.
73006f32e7eSjoerg Qualifiers::ObjCLifetime propertyLifetime =
73106f32e7eSjoerg getImpliedARCOwnership(property->getPropertyAttributes(),
73206f32e7eSjoerg property->getType());
73306f32e7eSjoerg
73406f32e7eSjoerg // We're fine if they match.
73506f32e7eSjoerg if (propertyLifetime == ivarLifetime) return;
73606f32e7eSjoerg
73706f32e7eSjoerg // None isn't a valid lifetime for an object ivar in ARC, and
73806f32e7eSjoerg // __autoreleasing is never valid; don't diagnose twice.
73906f32e7eSjoerg if ((ivarLifetime == Qualifiers::OCL_None &&
74006f32e7eSjoerg S.getLangOpts().ObjCAutoRefCount) ||
74106f32e7eSjoerg ivarLifetime == Qualifiers::OCL_Autoreleasing)
74206f32e7eSjoerg return;
74306f32e7eSjoerg
74406f32e7eSjoerg // If the ivar is private, and it's implicitly __unsafe_unretained
74506f32e7eSjoerg // because of its type, then pretend it was actually implicitly
74606f32e7eSjoerg // __strong. This is only sound because we're processing the
74706f32e7eSjoerg // property implementation before parsing any method bodies.
74806f32e7eSjoerg if (ivarLifetime == Qualifiers::OCL_ExplicitNone &&
74906f32e7eSjoerg propertyLifetime == Qualifiers::OCL_Strong &&
75006f32e7eSjoerg ivar->getAccessControl() == ObjCIvarDecl::Private) {
75106f32e7eSjoerg SplitQualType split = ivarType.split();
75206f32e7eSjoerg if (split.Quals.hasObjCLifetime()) {
75306f32e7eSjoerg assert(ivarType->isObjCARCImplicitlyUnretainedType());
75406f32e7eSjoerg split.Quals.setObjCLifetime(Qualifiers::OCL_Strong);
75506f32e7eSjoerg ivarType = S.Context.getQualifiedType(split);
75606f32e7eSjoerg ivar->setType(ivarType);
75706f32e7eSjoerg return;
75806f32e7eSjoerg }
75906f32e7eSjoerg }
76006f32e7eSjoerg
76106f32e7eSjoerg switch (propertyLifetime) {
76206f32e7eSjoerg case Qualifiers::OCL_Strong:
76306f32e7eSjoerg S.Diag(ivar->getLocation(), diag::err_arc_strong_property_ownership)
76406f32e7eSjoerg << property->getDeclName()
76506f32e7eSjoerg << ivar->getDeclName()
76606f32e7eSjoerg << ivarLifetime;
76706f32e7eSjoerg break;
76806f32e7eSjoerg
76906f32e7eSjoerg case Qualifiers::OCL_Weak:
77006f32e7eSjoerg S.Diag(ivar->getLocation(), diag::err_weak_property)
77106f32e7eSjoerg << property->getDeclName()
77206f32e7eSjoerg << ivar->getDeclName();
77306f32e7eSjoerg break;
77406f32e7eSjoerg
77506f32e7eSjoerg case Qualifiers::OCL_ExplicitNone:
77606f32e7eSjoerg S.Diag(ivar->getLocation(), diag::err_arc_assign_property_ownership)
777*13fbcb42Sjoerg << property->getDeclName() << ivar->getDeclName()
778*13fbcb42Sjoerg << ((property->getPropertyAttributesAsWritten() &
779*13fbcb42Sjoerg ObjCPropertyAttribute::kind_assign) != 0);
78006f32e7eSjoerg break;
78106f32e7eSjoerg
78206f32e7eSjoerg case Qualifiers::OCL_Autoreleasing:
78306f32e7eSjoerg llvm_unreachable("properties cannot be autoreleasing");
78406f32e7eSjoerg
78506f32e7eSjoerg case Qualifiers::OCL_None:
78606f32e7eSjoerg // Any other property should be ignored.
78706f32e7eSjoerg return;
78806f32e7eSjoerg }
78906f32e7eSjoerg
79006f32e7eSjoerg S.Diag(property->getLocation(), diag::note_property_declare);
79106f32e7eSjoerg if (propertyImplLoc.isValid())
79206f32e7eSjoerg S.Diag(propertyImplLoc, diag::note_property_synthesize);
79306f32e7eSjoerg }
79406f32e7eSjoerg
79506f32e7eSjoerg /// setImpliedPropertyAttributeForReadOnlyProperty -
79606f32e7eSjoerg /// This routine evaludates life-time attributes for a 'readonly'
79706f32e7eSjoerg /// property with no known lifetime of its own, using backing
79806f32e7eSjoerg /// 'ivar's attribute, if any. If no backing 'ivar', property's
79906f32e7eSjoerg /// life-time is assumed 'strong'.
setImpliedPropertyAttributeForReadOnlyProperty(ObjCPropertyDecl * property,ObjCIvarDecl * ivar)80006f32e7eSjoerg static void setImpliedPropertyAttributeForReadOnlyProperty(
80106f32e7eSjoerg ObjCPropertyDecl *property, ObjCIvarDecl *ivar) {
80206f32e7eSjoerg Qualifiers::ObjCLifetime propertyLifetime =
80306f32e7eSjoerg getImpliedARCOwnership(property->getPropertyAttributes(),
80406f32e7eSjoerg property->getType());
80506f32e7eSjoerg if (propertyLifetime != Qualifiers::OCL_None)
80606f32e7eSjoerg return;
80706f32e7eSjoerg
80806f32e7eSjoerg if (!ivar) {
80906f32e7eSjoerg // if no backing ivar, make property 'strong'.
810*13fbcb42Sjoerg property->setPropertyAttributes(ObjCPropertyAttribute::kind_strong);
81106f32e7eSjoerg return;
81206f32e7eSjoerg }
81306f32e7eSjoerg // property assumes owenership of backing ivar.
81406f32e7eSjoerg QualType ivarType = ivar->getType();
81506f32e7eSjoerg Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime();
81606f32e7eSjoerg if (ivarLifetime == Qualifiers::OCL_Strong)
817*13fbcb42Sjoerg property->setPropertyAttributes(ObjCPropertyAttribute::kind_strong);
81806f32e7eSjoerg else if (ivarLifetime == Qualifiers::OCL_Weak)
819*13fbcb42Sjoerg property->setPropertyAttributes(ObjCPropertyAttribute::kind_weak);
82006f32e7eSjoerg }
82106f32e7eSjoerg
isIncompatiblePropertyAttribute(unsigned Attr1,unsigned Attr2,ObjCPropertyAttribute::Kind Kind)822*13fbcb42Sjoerg static bool isIncompatiblePropertyAttribute(unsigned Attr1, unsigned Attr2,
823*13fbcb42Sjoerg ObjCPropertyAttribute::Kind Kind) {
82406f32e7eSjoerg return (Attr1 & Kind) != (Attr2 & Kind);
82506f32e7eSjoerg }
82606f32e7eSjoerg
areIncompatiblePropertyAttributes(unsigned Attr1,unsigned Attr2,unsigned Kinds)82706f32e7eSjoerg static bool areIncompatiblePropertyAttributes(unsigned Attr1, unsigned Attr2,
82806f32e7eSjoerg unsigned Kinds) {
82906f32e7eSjoerg return ((Attr1 & Kinds) != 0) != ((Attr2 & Kinds) != 0);
83006f32e7eSjoerg }
83106f32e7eSjoerg
83206f32e7eSjoerg /// SelectPropertyForSynthesisFromProtocols - Finds the most appropriate
83306f32e7eSjoerg /// property declaration that should be synthesised in all of the inherited
83406f32e7eSjoerg /// protocols. It also diagnoses properties declared in inherited protocols with
83506f32e7eSjoerg /// mismatched types or attributes, since any of them can be candidate for
83606f32e7eSjoerg /// synthesis.
83706f32e7eSjoerg static ObjCPropertyDecl *
SelectPropertyForSynthesisFromProtocols(Sema & S,SourceLocation AtLoc,ObjCInterfaceDecl * ClassDecl,ObjCPropertyDecl * Property)83806f32e7eSjoerg SelectPropertyForSynthesisFromProtocols(Sema &S, SourceLocation AtLoc,
83906f32e7eSjoerg ObjCInterfaceDecl *ClassDecl,
84006f32e7eSjoerg ObjCPropertyDecl *Property) {
84106f32e7eSjoerg assert(isa<ObjCProtocolDecl>(Property->getDeclContext()) &&
84206f32e7eSjoerg "Expected a property from a protocol");
84306f32e7eSjoerg ObjCInterfaceDecl::ProtocolPropertySet ProtocolSet;
84406f32e7eSjoerg ObjCInterfaceDecl::PropertyDeclOrder Properties;
84506f32e7eSjoerg for (const auto *PI : ClassDecl->all_referenced_protocols()) {
84606f32e7eSjoerg if (const ObjCProtocolDecl *PDecl = PI->getDefinition())
84706f32e7eSjoerg PDecl->collectInheritedProtocolProperties(Property, ProtocolSet,
84806f32e7eSjoerg Properties);
84906f32e7eSjoerg }
85006f32e7eSjoerg if (ObjCInterfaceDecl *SDecl = ClassDecl->getSuperClass()) {
85106f32e7eSjoerg while (SDecl) {
85206f32e7eSjoerg for (const auto *PI : SDecl->all_referenced_protocols()) {
85306f32e7eSjoerg if (const ObjCProtocolDecl *PDecl = PI->getDefinition())
85406f32e7eSjoerg PDecl->collectInheritedProtocolProperties(Property, ProtocolSet,
85506f32e7eSjoerg Properties);
85606f32e7eSjoerg }
85706f32e7eSjoerg SDecl = SDecl->getSuperClass();
85806f32e7eSjoerg }
85906f32e7eSjoerg }
86006f32e7eSjoerg
86106f32e7eSjoerg if (Properties.empty())
86206f32e7eSjoerg return Property;
86306f32e7eSjoerg
86406f32e7eSjoerg ObjCPropertyDecl *OriginalProperty = Property;
86506f32e7eSjoerg size_t SelectedIndex = 0;
86606f32e7eSjoerg for (const auto &Prop : llvm::enumerate(Properties)) {
86706f32e7eSjoerg // Select the 'readwrite' property if such property exists.
86806f32e7eSjoerg if (Property->isReadOnly() && !Prop.value()->isReadOnly()) {
86906f32e7eSjoerg Property = Prop.value();
87006f32e7eSjoerg SelectedIndex = Prop.index();
87106f32e7eSjoerg }
87206f32e7eSjoerg }
87306f32e7eSjoerg if (Property != OriginalProperty) {
87406f32e7eSjoerg // Check that the old property is compatible with the new one.
87506f32e7eSjoerg Properties[SelectedIndex] = OriginalProperty;
87606f32e7eSjoerg }
87706f32e7eSjoerg
87806f32e7eSjoerg QualType RHSType = S.Context.getCanonicalType(Property->getType());
87906f32e7eSjoerg unsigned OriginalAttributes = Property->getPropertyAttributesAsWritten();
88006f32e7eSjoerg enum MismatchKind {
88106f32e7eSjoerg IncompatibleType = 0,
88206f32e7eSjoerg HasNoExpectedAttribute,
88306f32e7eSjoerg HasUnexpectedAttribute,
88406f32e7eSjoerg DifferentGetter,
88506f32e7eSjoerg DifferentSetter
88606f32e7eSjoerg };
88706f32e7eSjoerg // Represents a property from another protocol that conflicts with the
88806f32e7eSjoerg // selected declaration.
88906f32e7eSjoerg struct MismatchingProperty {
89006f32e7eSjoerg const ObjCPropertyDecl *Prop;
89106f32e7eSjoerg MismatchKind Kind;
89206f32e7eSjoerg StringRef AttributeName;
89306f32e7eSjoerg };
89406f32e7eSjoerg SmallVector<MismatchingProperty, 4> Mismatches;
89506f32e7eSjoerg for (ObjCPropertyDecl *Prop : Properties) {
89606f32e7eSjoerg // Verify the property attributes.
89706f32e7eSjoerg unsigned Attr = Prop->getPropertyAttributesAsWritten();
89806f32e7eSjoerg if (Attr != OriginalAttributes) {
89906f32e7eSjoerg auto Diag = [&](bool OriginalHasAttribute, StringRef AttributeName) {
90006f32e7eSjoerg MismatchKind Kind = OriginalHasAttribute ? HasNoExpectedAttribute
90106f32e7eSjoerg : HasUnexpectedAttribute;
90206f32e7eSjoerg Mismatches.push_back({Prop, Kind, AttributeName});
90306f32e7eSjoerg };
90406f32e7eSjoerg // The ownership might be incompatible unless the property has no explicit
90506f32e7eSjoerg // ownership.
906*13fbcb42Sjoerg bool HasOwnership =
907*13fbcb42Sjoerg (Attr & (ObjCPropertyAttribute::kind_retain |
908*13fbcb42Sjoerg ObjCPropertyAttribute::kind_strong |
909*13fbcb42Sjoerg ObjCPropertyAttribute::kind_copy |
910*13fbcb42Sjoerg ObjCPropertyAttribute::kind_assign |
911*13fbcb42Sjoerg ObjCPropertyAttribute::kind_unsafe_unretained |
912*13fbcb42Sjoerg ObjCPropertyAttribute::kind_weak)) != 0;
91306f32e7eSjoerg if (HasOwnership &&
91406f32e7eSjoerg isIncompatiblePropertyAttribute(OriginalAttributes, Attr,
915*13fbcb42Sjoerg ObjCPropertyAttribute::kind_copy)) {
916*13fbcb42Sjoerg Diag(OriginalAttributes & ObjCPropertyAttribute::kind_copy, "copy");
91706f32e7eSjoerg continue;
91806f32e7eSjoerg }
91906f32e7eSjoerg if (HasOwnership && areIncompatiblePropertyAttributes(
92006f32e7eSjoerg OriginalAttributes, Attr,
921*13fbcb42Sjoerg ObjCPropertyAttribute::kind_retain |
922*13fbcb42Sjoerg ObjCPropertyAttribute::kind_strong)) {
923*13fbcb42Sjoerg Diag(OriginalAttributes & (ObjCPropertyAttribute::kind_retain |
924*13fbcb42Sjoerg ObjCPropertyAttribute::kind_strong),
92506f32e7eSjoerg "retain (or strong)");
92606f32e7eSjoerg continue;
92706f32e7eSjoerg }
92806f32e7eSjoerg if (isIncompatiblePropertyAttribute(OriginalAttributes, Attr,
929*13fbcb42Sjoerg ObjCPropertyAttribute::kind_atomic)) {
930*13fbcb42Sjoerg Diag(OriginalAttributes & ObjCPropertyAttribute::kind_atomic, "atomic");
93106f32e7eSjoerg continue;
93206f32e7eSjoerg }
93306f32e7eSjoerg }
93406f32e7eSjoerg if (Property->getGetterName() != Prop->getGetterName()) {
93506f32e7eSjoerg Mismatches.push_back({Prop, DifferentGetter, ""});
93606f32e7eSjoerg continue;
93706f32e7eSjoerg }
93806f32e7eSjoerg if (!Property->isReadOnly() && !Prop->isReadOnly() &&
93906f32e7eSjoerg Property->getSetterName() != Prop->getSetterName()) {
94006f32e7eSjoerg Mismatches.push_back({Prop, DifferentSetter, ""});
94106f32e7eSjoerg continue;
94206f32e7eSjoerg }
94306f32e7eSjoerg QualType LHSType = S.Context.getCanonicalType(Prop->getType());
94406f32e7eSjoerg if (!S.Context.propertyTypesAreCompatible(LHSType, RHSType)) {
94506f32e7eSjoerg bool IncompatibleObjC = false;
94606f32e7eSjoerg QualType ConvertedType;
94706f32e7eSjoerg if (!S.isObjCPointerConversion(RHSType, LHSType, ConvertedType, IncompatibleObjC)
94806f32e7eSjoerg || IncompatibleObjC) {
94906f32e7eSjoerg Mismatches.push_back({Prop, IncompatibleType, ""});
95006f32e7eSjoerg continue;
95106f32e7eSjoerg }
95206f32e7eSjoerg }
95306f32e7eSjoerg }
95406f32e7eSjoerg
95506f32e7eSjoerg if (Mismatches.empty())
95606f32e7eSjoerg return Property;
95706f32e7eSjoerg
95806f32e7eSjoerg // Diagnose incompability.
95906f32e7eSjoerg {
96006f32e7eSjoerg bool HasIncompatibleAttributes = false;
96106f32e7eSjoerg for (const auto &Note : Mismatches)
96206f32e7eSjoerg HasIncompatibleAttributes =
96306f32e7eSjoerg Note.Kind != IncompatibleType ? true : HasIncompatibleAttributes;
96406f32e7eSjoerg // Promote the warning to an error if there are incompatible attributes or
96506f32e7eSjoerg // incompatible types together with readwrite/readonly incompatibility.
96606f32e7eSjoerg auto Diag = S.Diag(Property->getLocation(),
96706f32e7eSjoerg Property != OriginalProperty || HasIncompatibleAttributes
96806f32e7eSjoerg ? diag::err_protocol_property_mismatch
96906f32e7eSjoerg : diag::warn_protocol_property_mismatch);
97006f32e7eSjoerg Diag << Mismatches[0].Kind;
97106f32e7eSjoerg switch (Mismatches[0].Kind) {
97206f32e7eSjoerg case IncompatibleType:
97306f32e7eSjoerg Diag << Property->getType();
97406f32e7eSjoerg break;
97506f32e7eSjoerg case HasNoExpectedAttribute:
97606f32e7eSjoerg case HasUnexpectedAttribute:
97706f32e7eSjoerg Diag << Mismatches[0].AttributeName;
97806f32e7eSjoerg break;
97906f32e7eSjoerg case DifferentGetter:
98006f32e7eSjoerg Diag << Property->getGetterName();
98106f32e7eSjoerg break;
98206f32e7eSjoerg case DifferentSetter:
98306f32e7eSjoerg Diag << Property->getSetterName();
98406f32e7eSjoerg break;
98506f32e7eSjoerg }
98606f32e7eSjoerg }
98706f32e7eSjoerg for (const auto &Note : Mismatches) {
98806f32e7eSjoerg auto Diag =
98906f32e7eSjoerg S.Diag(Note.Prop->getLocation(), diag::note_protocol_property_declare)
99006f32e7eSjoerg << Note.Kind;
99106f32e7eSjoerg switch (Note.Kind) {
99206f32e7eSjoerg case IncompatibleType:
99306f32e7eSjoerg Diag << Note.Prop->getType();
99406f32e7eSjoerg break;
99506f32e7eSjoerg case HasNoExpectedAttribute:
99606f32e7eSjoerg case HasUnexpectedAttribute:
99706f32e7eSjoerg Diag << Note.AttributeName;
99806f32e7eSjoerg break;
99906f32e7eSjoerg case DifferentGetter:
100006f32e7eSjoerg Diag << Note.Prop->getGetterName();
100106f32e7eSjoerg break;
100206f32e7eSjoerg case DifferentSetter:
100306f32e7eSjoerg Diag << Note.Prop->getSetterName();
100406f32e7eSjoerg break;
100506f32e7eSjoerg }
100606f32e7eSjoerg }
100706f32e7eSjoerg if (AtLoc.isValid())
100806f32e7eSjoerg S.Diag(AtLoc, diag::note_property_synthesize);
100906f32e7eSjoerg
101006f32e7eSjoerg return Property;
101106f32e7eSjoerg }
101206f32e7eSjoerg
101306f32e7eSjoerg /// Determine whether any storage attributes were written on the property.
hasWrittenStorageAttribute(ObjCPropertyDecl * Prop,ObjCPropertyQueryKind QueryKind)101406f32e7eSjoerg static bool hasWrittenStorageAttribute(ObjCPropertyDecl *Prop,
101506f32e7eSjoerg ObjCPropertyQueryKind QueryKind) {
101606f32e7eSjoerg if (Prop->getPropertyAttributesAsWritten() & OwnershipMask) return true;
101706f32e7eSjoerg
101806f32e7eSjoerg // If this is a readwrite property in a class extension that refines
101906f32e7eSjoerg // a readonly property in the original class definition, check it as
102006f32e7eSjoerg // well.
102106f32e7eSjoerg
102206f32e7eSjoerg // If it's a readonly property, we're not interested.
102306f32e7eSjoerg if (Prop->isReadOnly()) return false;
102406f32e7eSjoerg
102506f32e7eSjoerg // Is it declared in an extension?
102606f32e7eSjoerg auto Category = dyn_cast<ObjCCategoryDecl>(Prop->getDeclContext());
102706f32e7eSjoerg if (!Category || !Category->IsClassExtension()) return false;
102806f32e7eSjoerg
102906f32e7eSjoerg // Find the corresponding property in the primary class definition.
103006f32e7eSjoerg auto OrigClass = Category->getClassInterface();
103106f32e7eSjoerg for (auto Found : OrigClass->lookup(Prop->getDeclName())) {
103206f32e7eSjoerg if (ObjCPropertyDecl *OrigProp = dyn_cast<ObjCPropertyDecl>(Found))
103306f32e7eSjoerg return OrigProp->getPropertyAttributesAsWritten() & OwnershipMask;
103406f32e7eSjoerg }
103506f32e7eSjoerg
103606f32e7eSjoerg // Look through all of the protocols.
103706f32e7eSjoerg for (const auto *Proto : OrigClass->all_referenced_protocols()) {
103806f32e7eSjoerg if (ObjCPropertyDecl *OrigProp = Proto->FindPropertyDeclaration(
103906f32e7eSjoerg Prop->getIdentifier(), QueryKind))
104006f32e7eSjoerg return OrigProp->getPropertyAttributesAsWritten() & OwnershipMask;
104106f32e7eSjoerg }
104206f32e7eSjoerg
104306f32e7eSjoerg return false;
104406f32e7eSjoerg }
104506f32e7eSjoerg
1046*13fbcb42Sjoerg /// Create a synthesized property accessor stub inside the \@implementation.
1047*13fbcb42Sjoerg static ObjCMethodDecl *
RedeclarePropertyAccessor(ASTContext & Context,ObjCImplementationDecl * Impl,ObjCMethodDecl * AccessorDecl,SourceLocation AtLoc,SourceLocation PropertyLoc)1048*13fbcb42Sjoerg RedeclarePropertyAccessor(ASTContext &Context, ObjCImplementationDecl *Impl,
1049*13fbcb42Sjoerg ObjCMethodDecl *AccessorDecl, SourceLocation AtLoc,
1050*13fbcb42Sjoerg SourceLocation PropertyLoc) {
1051*13fbcb42Sjoerg ObjCMethodDecl *Decl = AccessorDecl;
1052*13fbcb42Sjoerg ObjCMethodDecl *ImplDecl = ObjCMethodDecl::Create(
1053*13fbcb42Sjoerg Context, AtLoc.isValid() ? AtLoc : Decl->getBeginLoc(),
1054*13fbcb42Sjoerg PropertyLoc.isValid() ? PropertyLoc : Decl->getEndLoc(),
1055*13fbcb42Sjoerg Decl->getSelector(), Decl->getReturnType(),
1056*13fbcb42Sjoerg Decl->getReturnTypeSourceInfo(), Impl, Decl->isInstanceMethod(),
1057*13fbcb42Sjoerg Decl->isVariadic(), Decl->isPropertyAccessor(),
1058*13fbcb42Sjoerg /* isSynthesized*/ true, Decl->isImplicit(), Decl->isDefined(),
1059*13fbcb42Sjoerg Decl->getImplementationControl(), Decl->hasRelatedResultType());
1060*13fbcb42Sjoerg ImplDecl->getMethodFamily();
1061*13fbcb42Sjoerg if (Decl->hasAttrs())
1062*13fbcb42Sjoerg ImplDecl->setAttrs(Decl->getAttrs());
1063*13fbcb42Sjoerg ImplDecl->setSelfDecl(Decl->getSelfDecl());
1064*13fbcb42Sjoerg ImplDecl->setCmdDecl(Decl->getCmdDecl());
1065*13fbcb42Sjoerg SmallVector<SourceLocation, 1> SelLocs;
1066*13fbcb42Sjoerg Decl->getSelectorLocs(SelLocs);
1067*13fbcb42Sjoerg ImplDecl->setMethodParams(Context, Decl->parameters(), SelLocs);
1068*13fbcb42Sjoerg ImplDecl->setLexicalDeclContext(Impl);
1069*13fbcb42Sjoerg ImplDecl->setDefined(false);
1070*13fbcb42Sjoerg return ImplDecl;
1071*13fbcb42Sjoerg }
1072*13fbcb42Sjoerg
107306f32e7eSjoerg /// ActOnPropertyImplDecl - This routine performs semantic checks and
107406f32e7eSjoerg /// builds the AST node for a property implementation declaration; declared
107506f32e7eSjoerg /// as \@synthesize or \@dynamic.
107606f32e7eSjoerg ///
ActOnPropertyImplDecl(Scope * S,SourceLocation AtLoc,SourceLocation PropertyLoc,bool Synthesize,IdentifierInfo * PropertyId,IdentifierInfo * PropertyIvar,SourceLocation PropertyIvarLoc,ObjCPropertyQueryKind QueryKind)107706f32e7eSjoerg Decl *Sema::ActOnPropertyImplDecl(Scope *S,
107806f32e7eSjoerg SourceLocation AtLoc,
107906f32e7eSjoerg SourceLocation PropertyLoc,
108006f32e7eSjoerg bool Synthesize,
108106f32e7eSjoerg IdentifierInfo *PropertyId,
108206f32e7eSjoerg IdentifierInfo *PropertyIvar,
108306f32e7eSjoerg SourceLocation PropertyIvarLoc,
108406f32e7eSjoerg ObjCPropertyQueryKind QueryKind) {
108506f32e7eSjoerg ObjCContainerDecl *ClassImpDecl =
108606f32e7eSjoerg dyn_cast<ObjCContainerDecl>(CurContext);
108706f32e7eSjoerg // Make sure we have a context for the property implementation declaration.
108806f32e7eSjoerg if (!ClassImpDecl) {
108906f32e7eSjoerg Diag(AtLoc, diag::err_missing_property_context);
109006f32e7eSjoerg return nullptr;
109106f32e7eSjoerg }
109206f32e7eSjoerg if (PropertyIvarLoc.isInvalid())
109306f32e7eSjoerg PropertyIvarLoc = PropertyLoc;
109406f32e7eSjoerg SourceLocation PropertyDiagLoc = PropertyLoc;
109506f32e7eSjoerg if (PropertyDiagLoc.isInvalid())
109606f32e7eSjoerg PropertyDiagLoc = ClassImpDecl->getBeginLoc();
109706f32e7eSjoerg ObjCPropertyDecl *property = nullptr;
109806f32e7eSjoerg ObjCInterfaceDecl *IDecl = nullptr;
109906f32e7eSjoerg // Find the class or category class where this property must have
110006f32e7eSjoerg // a declaration.
110106f32e7eSjoerg ObjCImplementationDecl *IC = nullptr;
110206f32e7eSjoerg ObjCCategoryImplDecl *CatImplClass = nullptr;
110306f32e7eSjoerg if ((IC = dyn_cast<ObjCImplementationDecl>(ClassImpDecl))) {
110406f32e7eSjoerg IDecl = IC->getClassInterface();
110506f32e7eSjoerg // We always synthesize an interface for an implementation
110606f32e7eSjoerg // without an interface decl. So, IDecl is always non-zero.
110706f32e7eSjoerg assert(IDecl &&
110806f32e7eSjoerg "ActOnPropertyImplDecl - @implementation without @interface");
110906f32e7eSjoerg
111006f32e7eSjoerg // Look for this property declaration in the @implementation's @interface
111106f32e7eSjoerg property = IDecl->FindPropertyDeclaration(PropertyId, QueryKind);
111206f32e7eSjoerg if (!property) {
111306f32e7eSjoerg Diag(PropertyLoc, diag::err_bad_property_decl) << IDecl->getDeclName();
111406f32e7eSjoerg return nullptr;
111506f32e7eSjoerg }
111606f32e7eSjoerg if (property->isClassProperty() && Synthesize) {
111706f32e7eSjoerg Diag(PropertyLoc, diag::err_synthesize_on_class_property) << PropertyId;
111806f32e7eSjoerg return nullptr;
111906f32e7eSjoerg }
112006f32e7eSjoerg unsigned PIkind = property->getPropertyAttributesAsWritten();
1121*13fbcb42Sjoerg if ((PIkind & (ObjCPropertyAttribute::kind_atomic |
1122*13fbcb42Sjoerg ObjCPropertyAttribute::kind_nonatomic)) == 0) {
112306f32e7eSjoerg if (AtLoc.isValid())
112406f32e7eSjoerg Diag(AtLoc, diag::warn_implicit_atomic_property);
112506f32e7eSjoerg else
112606f32e7eSjoerg Diag(IC->getLocation(), diag::warn_auto_implicit_atomic_property);
112706f32e7eSjoerg Diag(property->getLocation(), diag::note_property_declare);
112806f32e7eSjoerg }
112906f32e7eSjoerg
113006f32e7eSjoerg if (const ObjCCategoryDecl *CD =
113106f32e7eSjoerg dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) {
113206f32e7eSjoerg if (!CD->IsClassExtension()) {
113306f32e7eSjoerg Diag(PropertyLoc, diag::err_category_property) << CD->getDeclName();
113406f32e7eSjoerg Diag(property->getLocation(), diag::note_property_declare);
113506f32e7eSjoerg return nullptr;
113606f32e7eSjoerg }
113706f32e7eSjoerg }
1138*13fbcb42Sjoerg if (Synthesize && (PIkind & ObjCPropertyAttribute::kind_readonly) &&
1139*13fbcb42Sjoerg property->hasAttr<IBOutletAttr>() && !AtLoc.isValid()) {
114006f32e7eSjoerg bool ReadWriteProperty = false;
114106f32e7eSjoerg // Search into the class extensions and see if 'readonly property is
114206f32e7eSjoerg // redeclared 'readwrite', then no warning is to be issued.
114306f32e7eSjoerg for (auto *Ext : IDecl->known_extensions()) {
114406f32e7eSjoerg DeclContext::lookup_result R = Ext->lookup(property->getDeclName());
1145*13fbcb42Sjoerg if (auto *ExtProp = R.find_first<ObjCPropertyDecl>()) {
114606f32e7eSjoerg PIkind = ExtProp->getPropertyAttributesAsWritten();
1147*13fbcb42Sjoerg if (PIkind & ObjCPropertyAttribute::kind_readwrite) {
114806f32e7eSjoerg ReadWriteProperty = true;
114906f32e7eSjoerg break;
115006f32e7eSjoerg }
115106f32e7eSjoerg }
115206f32e7eSjoerg }
115306f32e7eSjoerg
115406f32e7eSjoerg if (!ReadWriteProperty) {
115506f32e7eSjoerg Diag(property->getLocation(), diag::warn_auto_readonly_iboutlet_property)
115606f32e7eSjoerg << property;
115706f32e7eSjoerg SourceLocation readonlyLoc;
115806f32e7eSjoerg if (LocPropertyAttribute(Context, "readonly",
115906f32e7eSjoerg property->getLParenLoc(), readonlyLoc)) {
116006f32e7eSjoerg SourceLocation endLoc =
116106f32e7eSjoerg readonlyLoc.getLocWithOffset(strlen("readonly")-1);
116206f32e7eSjoerg SourceRange ReadonlySourceRange(readonlyLoc, endLoc);
116306f32e7eSjoerg Diag(property->getLocation(),
116406f32e7eSjoerg diag::note_auto_readonly_iboutlet_fixup_suggest) <<
116506f32e7eSjoerg FixItHint::CreateReplacement(ReadonlySourceRange, "readwrite");
116606f32e7eSjoerg }
116706f32e7eSjoerg }
116806f32e7eSjoerg }
116906f32e7eSjoerg if (Synthesize && isa<ObjCProtocolDecl>(property->getDeclContext()))
117006f32e7eSjoerg property = SelectPropertyForSynthesisFromProtocols(*this, AtLoc, IDecl,
117106f32e7eSjoerg property);
117206f32e7eSjoerg
117306f32e7eSjoerg } else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) {
117406f32e7eSjoerg if (Synthesize) {
117506f32e7eSjoerg Diag(AtLoc, diag::err_synthesize_category_decl);
117606f32e7eSjoerg return nullptr;
117706f32e7eSjoerg }
117806f32e7eSjoerg IDecl = CatImplClass->getClassInterface();
117906f32e7eSjoerg if (!IDecl) {
118006f32e7eSjoerg Diag(AtLoc, diag::err_missing_property_interface);
118106f32e7eSjoerg return nullptr;
118206f32e7eSjoerg }
118306f32e7eSjoerg ObjCCategoryDecl *Category =
118406f32e7eSjoerg IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier());
118506f32e7eSjoerg
118606f32e7eSjoerg // If category for this implementation not found, it is an error which
118706f32e7eSjoerg // has already been reported eralier.
118806f32e7eSjoerg if (!Category)
118906f32e7eSjoerg return nullptr;
119006f32e7eSjoerg // Look for this property declaration in @implementation's category
119106f32e7eSjoerg property = Category->FindPropertyDeclaration(PropertyId, QueryKind);
119206f32e7eSjoerg if (!property) {
119306f32e7eSjoerg Diag(PropertyLoc, diag::err_bad_category_property_decl)
119406f32e7eSjoerg << Category->getDeclName();
119506f32e7eSjoerg return nullptr;
119606f32e7eSjoerg }
119706f32e7eSjoerg } else {
119806f32e7eSjoerg Diag(AtLoc, diag::err_bad_property_context);
119906f32e7eSjoerg return nullptr;
120006f32e7eSjoerg }
120106f32e7eSjoerg ObjCIvarDecl *Ivar = nullptr;
120206f32e7eSjoerg bool CompleteTypeErr = false;
120306f32e7eSjoerg bool compat = true;
120406f32e7eSjoerg // Check that we have a valid, previously declared ivar for @synthesize
120506f32e7eSjoerg if (Synthesize) {
120606f32e7eSjoerg // @synthesize
120706f32e7eSjoerg if (!PropertyIvar)
120806f32e7eSjoerg PropertyIvar = PropertyId;
120906f32e7eSjoerg // Check that this is a previously declared 'ivar' in 'IDecl' interface
121006f32e7eSjoerg ObjCInterfaceDecl *ClassDeclared;
121106f32e7eSjoerg Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared);
121206f32e7eSjoerg QualType PropType = property->getType();
121306f32e7eSjoerg QualType PropertyIvarType = PropType.getNonReferenceType();
121406f32e7eSjoerg
121506f32e7eSjoerg if (RequireCompleteType(PropertyDiagLoc, PropertyIvarType,
121606f32e7eSjoerg diag::err_incomplete_synthesized_property,
121706f32e7eSjoerg property->getDeclName())) {
121806f32e7eSjoerg Diag(property->getLocation(), diag::note_property_declare);
121906f32e7eSjoerg CompleteTypeErr = true;
122006f32e7eSjoerg }
122106f32e7eSjoerg
122206f32e7eSjoerg if (getLangOpts().ObjCAutoRefCount &&
122306f32e7eSjoerg (property->getPropertyAttributesAsWritten() &
1224*13fbcb42Sjoerg ObjCPropertyAttribute::kind_readonly) &&
122506f32e7eSjoerg PropertyIvarType->isObjCRetainableType()) {
122606f32e7eSjoerg setImpliedPropertyAttributeForReadOnlyProperty(property, Ivar);
122706f32e7eSjoerg }
122806f32e7eSjoerg
1229*13fbcb42Sjoerg ObjCPropertyAttribute::Kind kind = property->getPropertyAttributes();
123006f32e7eSjoerg
123106f32e7eSjoerg bool isARCWeak = false;
1232*13fbcb42Sjoerg if (kind & ObjCPropertyAttribute::kind_weak) {
123306f32e7eSjoerg // Add GC __weak to the ivar type if the property is weak.
123406f32e7eSjoerg if (getLangOpts().getGC() != LangOptions::NonGC) {
123506f32e7eSjoerg assert(!getLangOpts().ObjCAutoRefCount);
123606f32e7eSjoerg if (PropertyIvarType.isObjCGCStrong()) {
123706f32e7eSjoerg Diag(PropertyDiagLoc, diag::err_gc_weak_property_strong_type);
123806f32e7eSjoerg Diag(property->getLocation(), diag::note_property_declare);
123906f32e7eSjoerg } else {
124006f32e7eSjoerg PropertyIvarType =
124106f32e7eSjoerg Context.getObjCGCQualType(PropertyIvarType, Qualifiers::Weak);
124206f32e7eSjoerg }
124306f32e7eSjoerg
124406f32e7eSjoerg // Otherwise, check whether ARC __weak is enabled and works with
124506f32e7eSjoerg // the property type.
124606f32e7eSjoerg } else {
124706f32e7eSjoerg if (!getLangOpts().ObjCWeak) {
124806f32e7eSjoerg // Only complain here when synthesizing an ivar.
124906f32e7eSjoerg if (!Ivar) {
125006f32e7eSjoerg Diag(PropertyDiagLoc,
125106f32e7eSjoerg getLangOpts().ObjCWeakRuntime
125206f32e7eSjoerg ? diag::err_synthesizing_arc_weak_property_disabled
125306f32e7eSjoerg : diag::err_synthesizing_arc_weak_property_no_runtime);
125406f32e7eSjoerg Diag(property->getLocation(), diag::note_property_declare);
125506f32e7eSjoerg }
125606f32e7eSjoerg CompleteTypeErr = true; // suppress later diagnostics about the ivar
125706f32e7eSjoerg } else {
125806f32e7eSjoerg isARCWeak = true;
125906f32e7eSjoerg if (const ObjCObjectPointerType *ObjT =
126006f32e7eSjoerg PropertyIvarType->getAs<ObjCObjectPointerType>()) {
126106f32e7eSjoerg const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl();
126206f32e7eSjoerg if (ObjI && ObjI->isArcWeakrefUnavailable()) {
126306f32e7eSjoerg Diag(property->getLocation(),
126406f32e7eSjoerg diag::err_arc_weak_unavailable_property)
126506f32e7eSjoerg << PropertyIvarType;
126606f32e7eSjoerg Diag(ClassImpDecl->getLocation(), diag::note_implemented_by_class)
126706f32e7eSjoerg << ClassImpDecl->getName();
126806f32e7eSjoerg }
126906f32e7eSjoerg }
127006f32e7eSjoerg }
127106f32e7eSjoerg }
127206f32e7eSjoerg }
127306f32e7eSjoerg
127406f32e7eSjoerg if (AtLoc.isInvalid()) {
127506f32e7eSjoerg // Check when default synthesizing a property that there is
127606f32e7eSjoerg // an ivar matching property name and issue warning; since this
127706f32e7eSjoerg // is the most common case of not using an ivar used for backing
127806f32e7eSjoerg // property in non-default synthesis case.
127906f32e7eSjoerg ObjCInterfaceDecl *ClassDeclared=nullptr;
128006f32e7eSjoerg ObjCIvarDecl *originalIvar =
128106f32e7eSjoerg IDecl->lookupInstanceVariable(property->getIdentifier(),
128206f32e7eSjoerg ClassDeclared);
128306f32e7eSjoerg if (originalIvar) {
128406f32e7eSjoerg Diag(PropertyDiagLoc,
128506f32e7eSjoerg diag::warn_autosynthesis_property_ivar_match)
128606f32e7eSjoerg << PropertyId << (Ivar == nullptr) << PropertyIvar
128706f32e7eSjoerg << originalIvar->getIdentifier();
128806f32e7eSjoerg Diag(property->getLocation(), diag::note_property_declare);
128906f32e7eSjoerg Diag(originalIvar->getLocation(), diag::note_ivar_decl);
129006f32e7eSjoerg }
129106f32e7eSjoerg }
129206f32e7eSjoerg
129306f32e7eSjoerg if (!Ivar) {
129406f32e7eSjoerg // In ARC, give the ivar a lifetime qualifier based on the
129506f32e7eSjoerg // property attributes.
129606f32e7eSjoerg if ((getLangOpts().ObjCAutoRefCount || isARCWeak) &&
129706f32e7eSjoerg !PropertyIvarType.getObjCLifetime() &&
129806f32e7eSjoerg PropertyIvarType->isObjCRetainableType()) {
129906f32e7eSjoerg
130006f32e7eSjoerg // It's an error if we have to do this and the user didn't
130106f32e7eSjoerg // explicitly write an ownership attribute on the property.
130206f32e7eSjoerg if (!hasWrittenStorageAttribute(property, QueryKind) &&
1303*13fbcb42Sjoerg !(kind & ObjCPropertyAttribute::kind_strong)) {
130406f32e7eSjoerg Diag(PropertyDiagLoc,
130506f32e7eSjoerg diag::err_arc_objc_property_default_assign_on_object);
130606f32e7eSjoerg Diag(property->getLocation(), diag::note_property_declare);
130706f32e7eSjoerg } else {
130806f32e7eSjoerg Qualifiers::ObjCLifetime lifetime =
130906f32e7eSjoerg getImpliedARCOwnership(kind, PropertyIvarType);
131006f32e7eSjoerg assert(lifetime && "no lifetime for property?");
131106f32e7eSjoerg
131206f32e7eSjoerg Qualifiers qs;
131306f32e7eSjoerg qs.addObjCLifetime(lifetime);
131406f32e7eSjoerg PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs);
131506f32e7eSjoerg }
131606f32e7eSjoerg }
131706f32e7eSjoerg
131806f32e7eSjoerg Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl,
131906f32e7eSjoerg PropertyIvarLoc,PropertyIvarLoc, PropertyIvar,
132006f32e7eSjoerg PropertyIvarType, /*TInfo=*/nullptr,
132106f32e7eSjoerg ObjCIvarDecl::Private,
132206f32e7eSjoerg (Expr *)nullptr, true);
132306f32e7eSjoerg if (RequireNonAbstractType(PropertyIvarLoc,
132406f32e7eSjoerg PropertyIvarType,
132506f32e7eSjoerg diag::err_abstract_type_in_decl,
132606f32e7eSjoerg AbstractSynthesizedIvarType)) {
132706f32e7eSjoerg Diag(property->getLocation(), diag::note_property_declare);
132806f32e7eSjoerg // An abstract type is as bad as an incomplete type.
132906f32e7eSjoerg CompleteTypeErr = true;
133006f32e7eSjoerg }
133106f32e7eSjoerg if (!CompleteTypeErr) {
133206f32e7eSjoerg const RecordType *RecordTy = PropertyIvarType->getAs<RecordType>();
133306f32e7eSjoerg if (RecordTy && RecordTy->getDecl()->hasFlexibleArrayMember()) {
133406f32e7eSjoerg Diag(PropertyIvarLoc, diag::err_synthesize_variable_sized_ivar)
133506f32e7eSjoerg << PropertyIvarType;
133606f32e7eSjoerg CompleteTypeErr = true; // suppress later diagnostics about the ivar
133706f32e7eSjoerg }
133806f32e7eSjoerg }
133906f32e7eSjoerg if (CompleteTypeErr)
134006f32e7eSjoerg Ivar->setInvalidDecl();
134106f32e7eSjoerg ClassImpDecl->addDecl(Ivar);
134206f32e7eSjoerg IDecl->makeDeclVisibleInContext(Ivar);
134306f32e7eSjoerg
134406f32e7eSjoerg if (getLangOpts().ObjCRuntime.isFragile())
134506f32e7eSjoerg Diag(PropertyDiagLoc, diag::err_missing_property_ivar_decl)
134606f32e7eSjoerg << PropertyId;
134706f32e7eSjoerg // Note! I deliberately want it to fall thru so, we have a
134806f32e7eSjoerg // a property implementation and to avoid future warnings.
134906f32e7eSjoerg } else if (getLangOpts().ObjCRuntime.isNonFragile() &&
135006f32e7eSjoerg !declaresSameEntity(ClassDeclared, IDecl)) {
135106f32e7eSjoerg Diag(PropertyDiagLoc, diag::err_ivar_in_superclass_use)
135206f32e7eSjoerg << property->getDeclName() << Ivar->getDeclName()
135306f32e7eSjoerg << ClassDeclared->getDeclName();
135406f32e7eSjoerg Diag(Ivar->getLocation(), diag::note_previous_access_declaration)
135506f32e7eSjoerg << Ivar << Ivar->getName();
135606f32e7eSjoerg // Note! I deliberately want it to fall thru so more errors are caught.
135706f32e7eSjoerg }
135806f32e7eSjoerg property->setPropertyIvarDecl(Ivar);
135906f32e7eSjoerg
136006f32e7eSjoerg QualType IvarType = Context.getCanonicalType(Ivar->getType());
136106f32e7eSjoerg
136206f32e7eSjoerg // Check that type of property and its ivar are type compatible.
136306f32e7eSjoerg if (!Context.hasSameType(PropertyIvarType, IvarType)) {
136406f32e7eSjoerg if (isa<ObjCObjectPointerType>(PropertyIvarType)
136506f32e7eSjoerg && isa<ObjCObjectPointerType>(IvarType))
136606f32e7eSjoerg compat =
136706f32e7eSjoerg Context.canAssignObjCInterfaces(
136806f32e7eSjoerg PropertyIvarType->getAs<ObjCObjectPointerType>(),
136906f32e7eSjoerg IvarType->getAs<ObjCObjectPointerType>());
137006f32e7eSjoerg else {
137106f32e7eSjoerg compat = (CheckAssignmentConstraints(PropertyIvarLoc, PropertyIvarType,
137206f32e7eSjoerg IvarType)
137306f32e7eSjoerg == Compatible);
137406f32e7eSjoerg }
137506f32e7eSjoerg if (!compat) {
137606f32e7eSjoerg Diag(PropertyDiagLoc, diag::err_property_ivar_type)
137706f32e7eSjoerg << property->getDeclName() << PropType
137806f32e7eSjoerg << Ivar->getDeclName() << IvarType;
137906f32e7eSjoerg Diag(Ivar->getLocation(), diag::note_ivar_decl);
138006f32e7eSjoerg // Note! I deliberately want it to fall thru so, we have a
138106f32e7eSjoerg // a property implementation and to avoid future warnings.
138206f32e7eSjoerg }
138306f32e7eSjoerg else {
138406f32e7eSjoerg // FIXME! Rules for properties are somewhat different that those
138506f32e7eSjoerg // for assignments. Use a new routine to consolidate all cases;
138606f32e7eSjoerg // specifically for property redeclarations as well as for ivars.
138706f32e7eSjoerg QualType lhsType =Context.getCanonicalType(PropertyIvarType).getUnqualifiedType();
138806f32e7eSjoerg QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType();
138906f32e7eSjoerg if (lhsType != rhsType &&
139006f32e7eSjoerg lhsType->isArithmeticType()) {
139106f32e7eSjoerg Diag(PropertyDiagLoc, diag::err_property_ivar_type)
139206f32e7eSjoerg << property->getDeclName() << PropType
139306f32e7eSjoerg << Ivar->getDeclName() << IvarType;
139406f32e7eSjoerg Diag(Ivar->getLocation(), diag::note_ivar_decl);
139506f32e7eSjoerg // Fall thru - see previous comment
139606f32e7eSjoerg }
139706f32e7eSjoerg }
139806f32e7eSjoerg // __weak is explicit. So it works on Canonical type.
139906f32e7eSjoerg if ((PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() &&
140006f32e7eSjoerg getLangOpts().getGC() != LangOptions::NonGC)) {
140106f32e7eSjoerg Diag(PropertyDiagLoc, diag::err_weak_property)
140206f32e7eSjoerg << property->getDeclName() << Ivar->getDeclName();
140306f32e7eSjoerg Diag(Ivar->getLocation(), diag::note_ivar_decl);
140406f32e7eSjoerg // Fall thru - see previous comment
140506f32e7eSjoerg }
140606f32e7eSjoerg // Fall thru - see previous comment
140706f32e7eSjoerg if ((property->getType()->isObjCObjectPointerType() ||
140806f32e7eSjoerg PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&
140906f32e7eSjoerg getLangOpts().getGC() != LangOptions::NonGC) {
141006f32e7eSjoerg Diag(PropertyDiagLoc, diag::err_strong_property)
141106f32e7eSjoerg << property->getDeclName() << Ivar->getDeclName();
141206f32e7eSjoerg // Fall thru - see previous comment
141306f32e7eSjoerg }
141406f32e7eSjoerg }
141506f32e7eSjoerg if (getLangOpts().ObjCAutoRefCount || isARCWeak ||
141606f32e7eSjoerg Ivar->getType().getObjCLifetime())
141706f32e7eSjoerg checkARCPropertyImpl(*this, PropertyLoc, property, Ivar);
141806f32e7eSjoerg } else if (PropertyIvar)
141906f32e7eSjoerg // @dynamic
142006f32e7eSjoerg Diag(PropertyDiagLoc, diag::err_dynamic_property_ivar_decl);
142106f32e7eSjoerg
142206f32e7eSjoerg assert (property && "ActOnPropertyImplDecl - property declaration missing");
142306f32e7eSjoerg ObjCPropertyImplDecl *PIDecl =
142406f32e7eSjoerg ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc,
142506f32e7eSjoerg property,
142606f32e7eSjoerg (Synthesize ?
142706f32e7eSjoerg ObjCPropertyImplDecl::Synthesize
142806f32e7eSjoerg : ObjCPropertyImplDecl::Dynamic),
142906f32e7eSjoerg Ivar, PropertyIvarLoc);
143006f32e7eSjoerg
143106f32e7eSjoerg if (CompleteTypeErr || !compat)
143206f32e7eSjoerg PIDecl->setInvalidDecl();
143306f32e7eSjoerg
143406f32e7eSjoerg if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) {
143506f32e7eSjoerg getterMethod->createImplicitParams(Context, IDecl);
1436*13fbcb42Sjoerg
1437*13fbcb42Sjoerg // Redeclare the getter within the implementation as DeclContext.
1438*13fbcb42Sjoerg if (Synthesize) {
1439*13fbcb42Sjoerg // If the method hasn't been overridden, create a synthesized implementation.
1440*13fbcb42Sjoerg ObjCMethodDecl *OMD = ClassImpDecl->getMethod(
1441*13fbcb42Sjoerg getterMethod->getSelector(), getterMethod->isInstanceMethod());
1442*13fbcb42Sjoerg if (!OMD)
1443*13fbcb42Sjoerg OMD = RedeclarePropertyAccessor(Context, IC, getterMethod, AtLoc,
1444*13fbcb42Sjoerg PropertyLoc);
1445*13fbcb42Sjoerg PIDecl->setGetterMethodDecl(OMD);
1446*13fbcb42Sjoerg }
1447*13fbcb42Sjoerg
144806f32e7eSjoerg if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr &&
144906f32e7eSjoerg Ivar->getType()->isRecordType()) {
145006f32e7eSjoerg // For Objective-C++, need to synthesize the AST for the IVAR object to be
145106f32e7eSjoerg // returned by the getter as it must conform to C++'s copy-return rules.
145206f32e7eSjoerg // FIXME. Eventually we want to do this for Objective-C as well.
145306f32e7eSjoerg SynthesizedFunctionScope Scope(*this, getterMethod);
145406f32e7eSjoerg ImplicitParamDecl *SelfDecl = getterMethod->getSelfDecl();
145506f32e7eSjoerg DeclRefExpr *SelfExpr = new (Context)
145606f32e7eSjoerg DeclRefExpr(Context, SelfDecl, false, SelfDecl->getType(), VK_LValue,
145706f32e7eSjoerg PropertyDiagLoc);
145806f32e7eSjoerg MarkDeclRefReferenced(SelfExpr);
1459*13fbcb42Sjoerg Expr *LoadSelfExpr = ImplicitCastExpr::Create(
1460*13fbcb42Sjoerg Context, SelfDecl->getType(), CK_LValueToRValue, SelfExpr, nullptr,
1461*13fbcb42Sjoerg VK_RValue, FPOptionsOverride());
146206f32e7eSjoerg Expr *IvarRefExpr =
146306f32e7eSjoerg new (Context) ObjCIvarRefExpr(Ivar,
146406f32e7eSjoerg Ivar->getUsageType(SelfDecl->getType()),
146506f32e7eSjoerg PropertyDiagLoc,
146606f32e7eSjoerg Ivar->getLocation(),
146706f32e7eSjoerg LoadSelfExpr, true, true);
146806f32e7eSjoerg ExprResult Res = PerformCopyInitialization(
146906f32e7eSjoerg InitializedEntity::InitializeResult(PropertyDiagLoc,
147006f32e7eSjoerg getterMethod->getReturnType(),
147106f32e7eSjoerg /*NRVO=*/false),
147206f32e7eSjoerg PropertyDiagLoc, IvarRefExpr);
147306f32e7eSjoerg if (!Res.isInvalid()) {
147406f32e7eSjoerg Expr *ResExpr = Res.getAs<Expr>();
147506f32e7eSjoerg if (ResExpr)
147606f32e7eSjoerg ResExpr = MaybeCreateExprWithCleanups(ResExpr);
147706f32e7eSjoerg PIDecl->setGetterCXXConstructor(ResExpr);
147806f32e7eSjoerg }
147906f32e7eSjoerg }
148006f32e7eSjoerg if (property->hasAttr<NSReturnsNotRetainedAttr>() &&
148106f32e7eSjoerg !getterMethod->hasAttr<NSReturnsNotRetainedAttr>()) {
148206f32e7eSjoerg Diag(getterMethod->getLocation(),
148306f32e7eSjoerg diag::warn_property_getter_owning_mismatch);
148406f32e7eSjoerg Diag(property->getLocation(), diag::note_property_declare);
148506f32e7eSjoerg }
148606f32e7eSjoerg if (getLangOpts().ObjCAutoRefCount && Synthesize)
148706f32e7eSjoerg switch (getterMethod->getMethodFamily()) {
148806f32e7eSjoerg case OMF_retain:
148906f32e7eSjoerg case OMF_retainCount:
149006f32e7eSjoerg case OMF_release:
149106f32e7eSjoerg case OMF_autorelease:
149206f32e7eSjoerg Diag(getterMethod->getLocation(), diag::err_arc_illegal_method_def)
149306f32e7eSjoerg << 1 << getterMethod->getSelector();
149406f32e7eSjoerg break;
149506f32e7eSjoerg default:
149606f32e7eSjoerg break;
149706f32e7eSjoerg }
149806f32e7eSjoerg }
1499*13fbcb42Sjoerg
150006f32e7eSjoerg if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) {
150106f32e7eSjoerg setterMethod->createImplicitParams(Context, IDecl);
1502*13fbcb42Sjoerg
1503*13fbcb42Sjoerg // Redeclare the setter within the implementation as DeclContext.
1504*13fbcb42Sjoerg if (Synthesize) {
1505*13fbcb42Sjoerg ObjCMethodDecl *OMD = ClassImpDecl->getMethod(
1506*13fbcb42Sjoerg setterMethod->getSelector(), setterMethod->isInstanceMethod());
1507*13fbcb42Sjoerg if (!OMD)
1508*13fbcb42Sjoerg OMD = RedeclarePropertyAccessor(Context, IC, setterMethod,
1509*13fbcb42Sjoerg AtLoc, PropertyLoc);
1510*13fbcb42Sjoerg PIDecl->setSetterMethodDecl(OMD);
1511*13fbcb42Sjoerg }
1512*13fbcb42Sjoerg
151306f32e7eSjoerg if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr &&
151406f32e7eSjoerg Ivar->getType()->isRecordType()) {
151506f32e7eSjoerg // FIXME. Eventually we want to do this for Objective-C as well.
151606f32e7eSjoerg SynthesizedFunctionScope Scope(*this, setterMethod);
151706f32e7eSjoerg ImplicitParamDecl *SelfDecl = setterMethod->getSelfDecl();
151806f32e7eSjoerg DeclRefExpr *SelfExpr = new (Context)
151906f32e7eSjoerg DeclRefExpr(Context, SelfDecl, false, SelfDecl->getType(), VK_LValue,
152006f32e7eSjoerg PropertyDiagLoc);
152106f32e7eSjoerg MarkDeclRefReferenced(SelfExpr);
1522*13fbcb42Sjoerg Expr *LoadSelfExpr = ImplicitCastExpr::Create(
1523*13fbcb42Sjoerg Context, SelfDecl->getType(), CK_LValueToRValue, SelfExpr, nullptr,
1524*13fbcb42Sjoerg VK_RValue, FPOptionsOverride());
152506f32e7eSjoerg Expr *lhs =
152606f32e7eSjoerg new (Context) ObjCIvarRefExpr(Ivar,
152706f32e7eSjoerg Ivar->getUsageType(SelfDecl->getType()),
152806f32e7eSjoerg PropertyDiagLoc,
152906f32e7eSjoerg Ivar->getLocation(),
153006f32e7eSjoerg LoadSelfExpr, true, true);
153106f32e7eSjoerg ObjCMethodDecl::param_iterator P = setterMethod->param_begin();
153206f32e7eSjoerg ParmVarDecl *Param = (*P);
153306f32e7eSjoerg QualType T = Param->getType().getNonReferenceType();
153406f32e7eSjoerg DeclRefExpr *rhs = new (Context)
153506f32e7eSjoerg DeclRefExpr(Context, Param, false, T, VK_LValue, PropertyDiagLoc);
153606f32e7eSjoerg MarkDeclRefReferenced(rhs);
153706f32e7eSjoerg ExprResult Res = BuildBinOp(S, PropertyDiagLoc,
153806f32e7eSjoerg BO_Assign, lhs, rhs);
153906f32e7eSjoerg if (property->getPropertyAttributes() &
1540*13fbcb42Sjoerg ObjCPropertyAttribute::kind_atomic) {
154106f32e7eSjoerg Expr *callExpr = Res.getAs<Expr>();
154206f32e7eSjoerg if (const CXXOperatorCallExpr *CXXCE =
154306f32e7eSjoerg dyn_cast_or_null<CXXOperatorCallExpr>(callExpr))
154406f32e7eSjoerg if (const FunctionDecl *FuncDecl = CXXCE->getDirectCallee())
154506f32e7eSjoerg if (!FuncDecl->isTrivial())
154606f32e7eSjoerg if (property->getType()->isReferenceType()) {
154706f32e7eSjoerg Diag(PropertyDiagLoc,
154806f32e7eSjoerg diag::err_atomic_property_nontrivial_assign_op)
154906f32e7eSjoerg << property->getType();
155006f32e7eSjoerg Diag(FuncDecl->getBeginLoc(), diag::note_callee_decl)
155106f32e7eSjoerg << FuncDecl;
155206f32e7eSjoerg }
155306f32e7eSjoerg }
155406f32e7eSjoerg PIDecl->setSetterCXXAssignment(Res.getAs<Expr>());
155506f32e7eSjoerg }
155606f32e7eSjoerg }
155706f32e7eSjoerg
155806f32e7eSjoerg if (IC) {
155906f32e7eSjoerg if (Synthesize)
156006f32e7eSjoerg if (ObjCPropertyImplDecl *PPIDecl =
156106f32e7eSjoerg IC->FindPropertyImplIvarDecl(PropertyIvar)) {
156206f32e7eSjoerg Diag(PropertyLoc, diag::err_duplicate_ivar_use)
156306f32e7eSjoerg << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
156406f32e7eSjoerg << PropertyIvar;
156506f32e7eSjoerg Diag(PPIDecl->getLocation(), diag::note_previous_use);
156606f32e7eSjoerg }
156706f32e7eSjoerg
156806f32e7eSjoerg if (ObjCPropertyImplDecl *PPIDecl
156906f32e7eSjoerg = IC->FindPropertyImplDecl(PropertyId, QueryKind)) {
157006f32e7eSjoerg Diag(PropertyLoc, diag::err_property_implemented) << PropertyId;
157106f32e7eSjoerg Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
157206f32e7eSjoerg return nullptr;
157306f32e7eSjoerg }
157406f32e7eSjoerg IC->addPropertyImplementation(PIDecl);
157506f32e7eSjoerg if (getLangOpts().ObjCDefaultSynthProperties &&
157606f32e7eSjoerg getLangOpts().ObjCRuntime.isNonFragile() &&
157706f32e7eSjoerg !IDecl->isObjCRequiresPropertyDefs()) {
157806f32e7eSjoerg // Diagnose if an ivar was lazily synthesdized due to a previous
157906f32e7eSjoerg // use and if 1) property is @dynamic or 2) property is synthesized
158006f32e7eSjoerg // but it requires an ivar of different name.
158106f32e7eSjoerg ObjCInterfaceDecl *ClassDeclared=nullptr;
158206f32e7eSjoerg ObjCIvarDecl *Ivar = nullptr;
158306f32e7eSjoerg if (!Synthesize)
158406f32e7eSjoerg Ivar = IDecl->lookupInstanceVariable(PropertyId, ClassDeclared);
158506f32e7eSjoerg else {
158606f32e7eSjoerg if (PropertyIvar && PropertyIvar != PropertyId)
158706f32e7eSjoerg Ivar = IDecl->lookupInstanceVariable(PropertyId, ClassDeclared);
158806f32e7eSjoerg }
158906f32e7eSjoerg // Issue diagnostics only if Ivar belongs to current class.
159006f32e7eSjoerg if (Ivar && Ivar->getSynthesize() &&
159106f32e7eSjoerg declaresSameEntity(IC->getClassInterface(), ClassDeclared)) {
159206f32e7eSjoerg Diag(Ivar->getLocation(), diag::err_undeclared_var_use)
159306f32e7eSjoerg << PropertyId;
159406f32e7eSjoerg Ivar->setInvalidDecl();
159506f32e7eSjoerg }
159606f32e7eSjoerg }
159706f32e7eSjoerg } else {
159806f32e7eSjoerg if (Synthesize)
159906f32e7eSjoerg if (ObjCPropertyImplDecl *PPIDecl =
160006f32e7eSjoerg CatImplClass->FindPropertyImplIvarDecl(PropertyIvar)) {
160106f32e7eSjoerg Diag(PropertyDiagLoc, diag::err_duplicate_ivar_use)
160206f32e7eSjoerg << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
160306f32e7eSjoerg << PropertyIvar;
160406f32e7eSjoerg Diag(PPIDecl->getLocation(), diag::note_previous_use);
160506f32e7eSjoerg }
160606f32e7eSjoerg
160706f32e7eSjoerg if (ObjCPropertyImplDecl *PPIDecl =
160806f32e7eSjoerg CatImplClass->FindPropertyImplDecl(PropertyId, QueryKind)) {
160906f32e7eSjoerg Diag(PropertyDiagLoc, diag::err_property_implemented) << PropertyId;
161006f32e7eSjoerg Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
161106f32e7eSjoerg return nullptr;
161206f32e7eSjoerg }
161306f32e7eSjoerg CatImplClass->addPropertyImplementation(PIDecl);
161406f32e7eSjoerg }
161506f32e7eSjoerg
1616*13fbcb42Sjoerg if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic &&
1617*13fbcb42Sjoerg PIDecl->getPropertyDecl() &&
1618*13fbcb42Sjoerg PIDecl->getPropertyDecl()->isDirectProperty()) {
1619*13fbcb42Sjoerg Diag(PropertyLoc, diag::err_objc_direct_dynamic_property);
1620*13fbcb42Sjoerg Diag(PIDecl->getPropertyDecl()->getLocation(),
1621*13fbcb42Sjoerg diag::note_previous_declaration);
1622*13fbcb42Sjoerg return nullptr;
1623*13fbcb42Sjoerg }
1624*13fbcb42Sjoerg
162506f32e7eSjoerg return PIDecl;
162606f32e7eSjoerg }
162706f32e7eSjoerg
162806f32e7eSjoerg //===----------------------------------------------------------------------===//
162906f32e7eSjoerg // Helper methods.
163006f32e7eSjoerg //===----------------------------------------------------------------------===//
163106f32e7eSjoerg
163206f32e7eSjoerg /// DiagnosePropertyMismatch - Compares two properties for their
163306f32e7eSjoerg /// attributes and types and warns on a variety of inconsistencies.
163406f32e7eSjoerg ///
163506f32e7eSjoerg void
DiagnosePropertyMismatch(ObjCPropertyDecl * Property,ObjCPropertyDecl * SuperProperty,const IdentifierInfo * inheritedName,bool OverridingProtocolProperty)163606f32e7eSjoerg Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
163706f32e7eSjoerg ObjCPropertyDecl *SuperProperty,
163806f32e7eSjoerg const IdentifierInfo *inheritedName,
163906f32e7eSjoerg bool OverridingProtocolProperty) {
1640*13fbcb42Sjoerg ObjCPropertyAttribute::Kind CAttr = Property->getPropertyAttributes();
1641*13fbcb42Sjoerg ObjCPropertyAttribute::Kind SAttr = SuperProperty->getPropertyAttributes();
164206f32e7eSjoerg
164306f32e7eSjoerg // We allow readonly properties without an explicit ownership
164406f32e7eSjoerg // (assign/unsafe_unretained/weak/retain/strong/copy) in super class
164506f32e7eSjoerg // to be overridden by a property with any explicit ownership in the subclass.
164606f32e7eSjoerg if (!OverridingProtocolProperty &&
164706f32e7eSjoerg !getOwnershipRule(SAttr) && getOwnershipRule(CAttr))
164806f32e7eSjoerg ;
164906f32e7eSjoerg else {
1650*13fbcb42Sjoerg if ((CAttr & ObjCPropertyAttribute::kind_readonly) &&
1651*13fbcb42Sjoerg (SAttr & ObjCPropertyAttribute::kind_readwrite))
165206f32e7eSjoerg Diag(Property->getLocation(), diag::warn_readonly_property)
165306f32e7eSjoerg << Property->getDeclName() << inheritedName;
1654*13fbcb42Sjoerg if ((CAttr & ObjCPropertyAttribute::kind_copy) !=
1655*13fbcb42Sjoerg (SAttr & ObjCPropertyAttribute::kind_copy))
165606f32e7eSjoerg Diag(Property->getLocation(), diag::warn_property_attribute)
165706f32e7eSjoerg << Property->getDeclName() << "copy" << inheritedName;
1658*13fbcb42Sjoerg else if (!(SAttr & ObjCPropertyAttribute::kind_readonly)) {
1659*13fbcb42Sjoerg unsigned CAttrRetain = (CAttr & (ObjCPropertyAttribute::kind_retain |
1660*13fbcb42Sjoerg ObjCPropertyAttribute::kind_strong));
1661*13fbcb42Sjoerg unsigned SAttrRetain = (SAttr & (ObjCPropertyAttribute::kind_retain |
1662*13fbcb42Sjoerg ObjCPropertyAttribute::kind_strong));
166306f32e7eSjoerg bool CStrong = (CAttrRetain != 0);
166406f32e7eSjoerg bool SStrong = (SAttrRetain != 0);
166506f32e7eSjoerg if (CStrong != SStrong)
166606f32e7eSjoerg Diag(Property->getLocation(), diag::warn_property_attribute)
166706f32e7eSjoerg << Property->getDeclName() << "retain (or strong)" << inheritedName;
166806f32e7eSjoerg }
166906f32e7eSjoerg }
167006f32e7eSjoerg
167106f32e7eSjoerg // Check for nonatomic; note that nonatomic is effectively
167206f32e7eSjoerg // meaningless for readonly properties, so don't diagnose if the
167306f32e7eSjoerg // atomic property is 'readonly'.
167406f32e7eSjoerg checkAtomicPropertyMismatch(*this, SuperProperty, Property, false);
167506f32e7eSjoerg // Readonly properties from protocols can be implemented as "readwrite"
167606f32e7eSjoerg // with a custom setter name.
167706f32e7eSjoerg if (Property->getSetterName() != SuperProperty->getSetterName() &&
167806f32e7eSjoerg !(SuperProperty->isReadOnly() &&
167906f32e7eSjoerg isa<ObjCProtocolDecl>(SuperProperty->getDeclContext()))) {
168006f32e7eSjoerg Diag(Property->getLocation(), diag::warn_property_attribute)
168106f32e7eSjoerg << Property->getDeclName() << "setter" << inheritedName;
168206f32e7eSjoerg Diag(SuperProperty->getLocation(), diag::note_property_declare);
168306f32e7eSjoerg }
168406f32e7eSjoerg if (Property->getGetterName() != SuperProperty->getGetterName()) {
168506f32e7eSjoerg Diag(Property->getLocation(), diag::warn_property_attribute)
168606f32e7eSjoerg << Property->getDeclName() << "getter" << inheritedName;
168706f32e7eSjoerg Diag(SuperProperty->getLocation(), diag::note_property_declare);
168806f32e7eSjoerg }
168906f32e7eSjoerg
169006f32e7eSjoerg QualType LHSType =
169106f32e7eSjoerg Context.getCanonicalType(SuperProperty->getType());
169206f32e7eSjoerg QualType RHSType =
169306f32e7eSjoerg Context.getCanonicalType(Property->getType());
169406f32e7eSjoerg
169506f32e7eSjoerg if (!Context.propertyTypesAreCompatible(LHSType, RHSType)) {
169606f32e7eSjoerg // Do cases not handled in above.
169706f32e7eSjoerg // FIXME. For future support of covariant property types, revisit this.
169806f32e7eSjoerg bool IncompatibleObjC = false;
169906f32e7eSjoerg QualType ConvertedType;
170006f32e7eSjoerg if (!isObjCPointerConversion(RHSType, LHSType,
170106f32e7eSjoerg ConvertedType, IncompatibleObjC) ||
170206f32e7eSjoerg IncompatibleObjC) {
170306f32e7eSjoerg Diag(Property->getLocation(), diag::warn_property_types_are_incompatible)
170406f32e7eSjoerg << Property->getType() << SuperProperty->getType() << inheritedName;
170506f32e7eSjoerg Diag(SuperProperty->getLocation(), diag::note_property_declare);
170606f32e7eSjoerg }
170706f32e7eSjoerg }
170806f32e7eSjoerg }
170906f32e7eSjoerg
DiagnosePropertyAccessorMismatch(ObjCPropertyDecl * property,ObjCMethodDecl * GetterMethod,SourceLocation Loc)171006f32e7eSjoerg bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
171106f32e7eSjoerg ObjCMethodDecl *GetterMethod,
171206f32e7eSjoerg SourceLocation Loc) {
171306f32e7eSjoerg if (!GetterMethod)
171406f32e7eSjoerg return false;
171506f32e7eSjoerg QualType GetterType = GetterMethod->getReturnType().getNonReferenceType();
171606f32e7eSjoerg QualType PropertyRValueType =
171706f32e7eSjoerg property->getType().getNonReferenceType().getAtomicUnqualifiedType();
171806f32e7eSjoerg bool compat = Context.hasSameType(PropertyRValueType, GetterType);
171906f32e7eSjoerg if (!compat) {
172006f32e7eSjoerg const ObjCObjectPointerType *propertyObjCPtr = nullptr;
172106f32e7eSjoerg const ObjCObjectPointerType *getterObjCPtr = nullptr;
172206f32e7eSjoerg if ((propertyObjCPtr =
172306f32e7eSjoerg PropertyRValueType->getAs<ObjCObjectPointerType>()) &&
172406f32e7eSjoerg (getterObjCPtr = GetterType->getAs<ObjCObjectPointerType>()))
172506f32e7eSjoerg compat = Context.canAssignObjCInterfaces(getterObjCPtr, propertyObjCPtr);
172606f32e7eSjoerg else if (CheckAssignmentConstraints(Loc, GetterType, PropertyRValueType)
172706f32e7eSjoerg != Compatible) {
172806f32e7eSjoerg Diag(Loc, diag::err_property_accessor_type)
172906f32e7eSjoerg << property->getDeclName() << PropertyRValueType
173006f32e7eSjoerg << GetterMethod->getSelector() << GetterType;
173106f32e7eSjoerg Diag(GetterMethod->getLocation(), diag::note_declared_at);
173206f32e7eSjoerg return true;
173306f32e7eSjoerg } else {
173406f32e7eSjoerg compat = true;
173506f32e7eSjoerg QualType lhsType = Context.getCanonicalType(PropertyRValueType);
173606f32e7eSjoerg QualType rhsType =Context.getCanonicalType(GetterType).getUnqualifiedType();
173706f32e7eSjoerg if (lhsType != rhsType && lhsType->isArithmeticType())
173806f32e7eSjoerg compat = false;
173906f32e7eSjoerg }
174006f32e7eSjoerg }
174106f32e7eSjoerg
174206f32e7eSjoerg if (!compat) {
174306f32e7eSjoerg Diag(Loc, diag::warn_accessor_property_type_mismatch)
174406f32e7eSjoerg << property->getDeclName()
174506f32e7eSjoerg << GetterMethod->getSelector();
174606f32e7eSjoerg Diag(GetterMethod->getLocation(), diag::note_declared_at);
174706f32e7eSjoerg return true;
174806f32e7eSjoerg }
174906f32e7eSjoerg
175006f32e7eSjoerg return false;
175106f32e7eSjoerg }
175206f32e7eSjoerg
175306f32e7eSjoerg /// CollectImmediateProperties - This routine collects all properties in
175406f32e7eSjoerg /// the class and its conforming protocols; but not those in its super class.
175506f32e7eSjoerg static void
CollectImmediateProperties(ObjCContainerDecl * CDecl,ObjCContainerDecl::PropertyMap & PropMap,ObjCContainerDecl::PropertyMap & SuperPropMap,bool CollectClassPropsOnly=false,bool IncludeProtocols=true)175606f32e7eSjoerg CollectImmediateProperties(ObjCContainerDecl *CDecl,
175706f32e7eSjoerg ObjCContainerDecl::PropertyMap &PropMap,
175806f32e7eSjoerg ObjCContainerDecl::PropertyMap &SuperPropMap,
175906f32e7eSjoerg bool CollectClassPropsOnly = false,
176006f32e7eSjoerg bool IncludeProtocols = true) {
176106f32e7eSjoerg if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
176206f32e7eSjoerg for (auto *Prop : IDecl->properties()) {
176306f32e7eSjoerg if (CollectClassPropsOnly && !Prop->isClassProperty())
176406f32e7eSjoerg continue;
176506f32e7eSjoerg PropMap[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] =
176606f32e7eSjoerg Prop;
176706f32e7eSjoerg }
176806f32e7eSjoerg
176906f32e7eSjoerg // Collect the properties from visible extensions.
177006f32e7eSjoerg for (auto *Ext : IDecl->visible_extensions())
177106f32e7eSjoerg CollectImmediateProperties(Ext, PropMap, SuperPropMap,
177206f32e7eSjoerg CollectClassPropsOnly, IncludeProtocols);
177306f32e7eSjoerg
177406f32e7eSjoerg if (IncludeProtocols) {
177506f32e7eSjoerg // Scan through class's protocols.
177606f32e7eSjoerg for (auto *PI : IDecl->all_referenced_protocols())
177706f32e7eSjoerg CollectImmediateProperties(PI, PropMap, SuperPropMap,
177806f32e7eSjoerg CollectClassPropsOnly);
177906f32e7eSjoerg }
178006f32e7eSjoerg }
178106f32e7eSjoerg if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
178206f32e7eSjoerg for (auto *Prop : CATDecl->properties()) {
178306f32e7eSjoerg if (CollectClassPropsOnly && !Prop->isClassProperty())
178406f32e7eSjoerg continue;
178506f32e7eSjoerg PropMap[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] =
178606f32e7eSjoerg Prop;
178706f32e7eSjoerg }
178806f32e7eSjoerg if (IncludeProtocols) {
178906f32e7eSjoerg // Scan through class's protocols.
179006f32e7eSjoerg for (auto *PI : CATDecl->protocols())
179106f32e7eSjoerg CollectImmediateProperties(PI, PropMap, SuperPropMap,
179206f32e7eSjoerg CollectClassPropsOnly);
179306f32e7eSjoerg }
179406f32e7eSjoerg }
179506f32e7eSjoerg else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) {
179606f32e7eSjoerg for (auto *Prop : PDecl->properties()) {
179706f32e7eSjoerg if (CollectClassPropsOnly && !Prop->isClassProperty())
179806f32e7eSjoerg continue;
179906f32e7eSjoerg ObjCPropertyDecl *PropertyFromSuper =
180006f32e7eSjoerg SuperPropMap[std::make_pair(Prop->getIdentifier(),
180106f32e7eSjoerg Prop->isClassProperty())];
180206f32e7eSjoerg // Exclude property for protocols which conform to class's super-class,
180306f32e7eSjoerg // as super-class has to implement the property.
180406f32e7eSjoerg if (!PropertyFromSuper ||
180506f32e7eSjoerg PropertyFromSuper->getIdentifier() != Prop->getIdentifier()) {
180606f32e7eSjoerg ObjCPropertyDecl *&PropEntry =
180706f32e7eSjoerg PropMap[std::make_pair(Prop->getIdentifier(),
180806f32e7eSjoerg Prop->isClassProperty())];
180906f32e7eSjoerg if (!PropEntry)
181006f32e7eSjoerg PropEntry = Prop;
181106f32e7eSjoerg }
181206f32e7eSjoerg }
181306f32e7eSjoerg // Scan through protocol's protocols.
181406f32e7eSjoerg for (auto *PI : PDecl->protocols())
181506f32e7eSjoerg CollectImmediateProperties(PI, PropMap, SuperPropMap,
181606f32e7eSjoerg CollectClassPropsOnly);
181706f32e7eSjoerg }
181806f32e7eSjoerg }
181906f32e7eSjoerg
182006f32e7eSjoerg /// CollectSuperClassPropertyImplementations - This routine collects list of
182106f32e7eSjoerg /// properties to be implemented in super class(s) and also coming from their
182206f32e7eSjoerg /// conforming protocols.
CollectSuperClassPropertyImplementations(ObjCInterfaceDecl * CDecl,ObjCInterfaceDecl::PropertyMap & PropMap)182306f32e7eSjoerg static void CollectSuperClassPropertyImplementations(ObjCInterfaceDecl *CDecl,
182406f32e7eSjoerg ObjCInterfaceDecl::PropertyMap &PropMap) {
182506f32e7eSjoerg if (ObjCInterfaceDecl *SDecl = CDecl->getSuperClass()) {
182606f32e7eSjoerg ObjCInterfaceDecl::PropertyDeclOrder PO;
182706f32e7eSjoerg while (SDecl) {
182806f32e7eSjoerg SDecl->collectPropertiesToImplement(PropMap, PO);
182906f32e7eSjoerg SDecl = SDecl->getSuperClass();
183006f32e7eSjoerg }
183106f32e7eSjoerg }
183206f32e7eSjoerg }
183306f32e7eSjoerg
183406f32e7eSjoerg /// IvarBacksCurrentMethodAccessor - This routine returns 'true' if 'IV' is
183506f32e7eSjoerg /// an ivar synthesized for 'Method' and 'Method' is a property accessor
183606f32e7eSjoerg /// declared in class 'IFace'.
183706f32e7eSjoerg bool
IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl * IFace,ObjCMethodDecl * Method,ObjCIvarDecl * IV)183806f32e7eSjoerg Sema::IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace,
183906f32e7eSjoerg ObjCMethodDecl *Method, ObjCIvarDecl *IV) {
184006f32e7eSjoerg if (!IV->getSynthesize())
184106f32e7eSjoerg return false;
184206f32e7eSjoerg ObjCMethodDecl *IMD = IFace->lookupMethod(Method->getSelector(),
184306f32e7eSjoerg Method->isInstanceMethod());
184406f32e7eSjoerg if (!IMD || !IMD->isPropertyAccessor())
184506f32e7eSjoerg return false;
184606f32e7eSjoerg
184706f32e7eSjoerg // look up a property declaration whose one of its accessors is implemented
184806f32e7eSjoerg // by this method.
184906f32e7eSjoerg for (const auto *Property : IFace->instance_properties()) {
185006f32e7eSjoerg if ((Property->getGetterName() == IMD->getSelector() ||
185106f32e7eSjoerg Property->getSetterName() == IMD->getSelector()) &&
185206f32e7eSjoerg (Property->getPropertyIvarDecl() == IV))
185306f32e7eSjoerg return true;
185406f32e7eSjoerg }
185506f32e7eSjoerg // Also look up property declaration in class extension whose one of its
185606f32e7eSjoerg // accessors is implemented by this method.
185706f32e7eSjoerg for (const auto *Ext : IFace->known_extensions())
185806f32e7eSjoerg for (const auto *Property : Ext->instance_properties())
185906f32e7eSjoerg if ((Property->getGetterName() == IMD->getSelector() ||
186006f32e7eSjoerg Property->getSetterName() == IMD->getSelector()) &&
186106f32e7eSjoerg (Property->getPropertyIvarDecl() == IV))
186206f32e7eSjoerg return true;
186306f32e7eSjoerg return false;
186406f32e7eSjoerg }
186506f32e7eSjoerg
SuperClassImplementsProperty(ObjCInterfaceDecl * IDecl,ObjCPropertyDecl * Prop)186606f32e7eSjoerg static bool SuperClassImplementsProperty(ObjCInterfaceDecl *IDecl,
186706f32e7eSjoerg ObjCPropertyDecl *Prop) {
186806f32e7eSjoerg bool SuperClassImplementsGetter = false;
186906f32e7eSjoerg bool SuperClassImplementsSetter = false;
1870*13fbcb42Sjoerg if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_readonly)
187106f32e7eSjoerg SuperClassImplementsSetter = true;
187206f32e7eSjoerg
187306f32e7eSjoerg while (IDecl->getSuperClass()) {
187406f32e7eSjoerg ObjCInterfaceDecl *SDecl = IDecl->getSuperClass();
187506f32e7eSjoerg if (!SuperClassImplementsGetter && SDecl->getInstanceMethod(Prop->getGetterName()))
187606f32e7eSjoerg SuperClassImplementsGetter = true;
187706f32e7eSjoerg
187806f32e7eSjoerg if (!SuperClassImplementsSetter && SDecl->getInstanceMethod(Prop->getSetterName()))
187906f32e7eSjoerg SuperClassImplementsSetter = true;
188006f32e7eSjoerg if (SuperClassImplementsGetter && SuperClassImplementsSetter)
188106f32e7eSjoerg return true;
188206f32e7eSjoerg IDecl = IDecl->getSuperClass();
188306f32e7eSjoerg }
188406f32e7eSjoerg return false;
188506f32e7eSjoerg }
188606f32e7eSjoerg
188706f32e7eSjoerg /// Default synthesizes all properties which must be synthesized
188806f32e7eSjoerg /// in class's \@implementation.
DefaultSynthesizeProperties(Scope * S,ObjCImplDecl * IMPDecl,ObjCInterfaceDecl * IDecl,SourceLocation AtEnd)188906f32e7eSjoerg void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl,
189006f32e7eSjoerg ObjCInterfaceDecl *IDecl,
189106f32e7eSjoerg SourceLocation AtEnd) {
189206f32e7eSjoerg ObjCInterfaceDecl::PropertyMap PropMap;
189306f32e7eSjoerg ObjCInterfaceDecl::PropertyDeclOrder PropertyOrder;
189406f32e7eSjoerg IDecl->collectPropertiesToImplement(PropMap, PropertyOrder);
189506f32e7eSjoerg if (PropMap.empty())
189606f32e7eSjoerg return;
189706f32e7eSjoerg ObjCInterfaceDecl::PropertyMap SuperPropMap;
189806f32e7eSjoerg CollectSuperClassPropertyImplementations(IDecl, SuperPropMap);
189906f32e7eSjoerg
190006f32e7eSjoerg for (unsigned i = 0, e = PropertyOrder.size(); i != e; i++) {
190106f32e7eSjoerg ObjCPropertyDecl *Prop = PropertyOrder[i];
190206f32e7eSjoerg // Is there a matching property synthesize/dynamic?
190306f32e7eSjoerg if (Prop->isInvalidDecl() ||
190406f32e7eSjoerg Prop->isClassProperty() ||
190506f32e7eSjoerg Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional)
190606f32e7eSjoerg continue;
190706f32e7eSjoerg // Property may have been synthesized by user.
190806f32e7eSjoerg if (IMPDecl->FindPropertyImplDecl(
190906f32e7eSjoerg Prop->getIdentifier(), Prop->getQueryKind()))
191006f32e7eSjoerg continue;
1911*13fbcb42Sjoerg ObjCMethodDecl *ImpMethod = IMPDecl->getInstanceMethod(Prop->getGetterName());
1912*13fbcb42Sjoerg if (ImpMethod && !ImpMethod->getBody()) {
1913*13fbcb42Sjoerg if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_readonly)
191406f32e7eSjoerg continue;
1915*13fbcb42Sjoerg ImpMethod = IMPDecl->getInstanceMethod(Prop->getSetterName());
1916*13fbcb42Sjoerg if (ImpMethod && !ImpMethod->getBody())
191706f32e7eSjoerg continue;
191806f32e7eSjoerg }
191906f32e7eSjoerg if (ObjCPropertyImplDecl *PID =
192006f32e7eSjoerg IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier())) {
192106f32e7eSjoerg Diag(Prop->getLocation(), diag::warn_no_autosynthesis_shared_ivar_property)
192206f32e7eSjoerg << Prop->getIdentifier();
192306f32e7eSjoerg if (PID->getLocation().isValid())
192406f32e7eSjoerg Diag(PID->getLocation(), diag::note_property_synthesize);
192506f32e7eSjoerg continue;
192606f32e7eSjoerg }
192706f32e7eSjoerg ObjCPropertyDecl *PropInSuperClass =
192806f32e7eSjoerg SuperPropMap[std::make_pair(Prop->getIdentifier(),
192906f32e7eSjoerg Prop->isClassProperty())];
193006f32e7eSjoerg if (ObjCProtocolDecl *Proto =
193106f32e7eSjoerg dyn_cast<ObjCProtocolDecl>(Prop->getDeclContext())) {
193206f32e7eSjoerg // We won't auto-synthesize properties declared in protocols.
193306f32e7eSjoerg // Suppress the warning if class's superclass implements property's
193406f32e7eSjoerg // getter and implements property's setter (if readwrite property).
193506f32e7eSjoerg // Or, if property is going to be implemented in its super class.
193606f32e7eSjoerg if (!SuperClassImplementsProperty(IDecl, Prop) && !PropInSuperClass) {
193706f32e7eSjoerg Diag(IMPDecl->getLocation(),
193806f32e7eSjoerg diag::warn_auto_synthesizing_protocol_property)
193906f32e7eSjoerg << Prop << Proto;
194006f32e7eSjoerg Diag(Prop->getLocation(), diag::note_property_declare);
194106f32e7eSjoerg std::string FixIt =
194206f32e7eSjoerg (Twine("@synthesize ") + Prop->getName() + ";\n\n").str();
194306f32e7eSjoerg Diag(AtEnd, diag::note_add_synthesize_directive)
194406f32e7eSjoerg << FixItHint::CreateInsertion(AtEnd, FixIt);
194506f32e7eSjoerg }
194606f32e7eSjoerg continue;
194706f32e7eSjoerg }
194806f32e7eSjoerg // If property to be implemented in the super class, ignore.
194906f32e7eSjoerg if (PropInSuperClass) {
1950*13fbcb42Sjoerg if ((Prop->getPropertyAttributes() &
1951*13fbcb42Sjoerg ObjCPropertyAttribute::kind_readwrite) &&
195206f32e7eSjoerg (PropInSuperClass->getPropertyAttributes() &
1953*13fbcb42Sjoerg ObjCPropertyAttribute::kind_readonly) &&
195406f32e7eSjoerg !IMPDecl->getInstanceMethod(Prop->getSetterName()) &&
195506f32e7eSjoerg !IDecl->HasUserDeclaredSetterMethod(Prop)) {
195606f32e7eSjoerg Diag(Prop->getLocation(), diag::warn_no_autosynthesis_property)
195706f32e7eSjoerg << Prop->getIdentifier();
195806f32e7eSjoerg Diag(PropInSuperClass->getLocation(), diag::note_property_declare);
1959*13fbcb42Sjoerg } else {
196006f32e7eSjoerg Diag(Prop->getLocation(), diag::warn_autosynthesis_property_in_superclass)
196106f32e7eSjoerg << Prop->getIdentifier();
196206f32e7eSjoerg Diag(PropInSuperClass->getLocation(), diag::note_property_declare);
196306f32e7eSjoerg Diag(IMPDecl->getLocation(), diag::note_while_in_implementation);
196406f32e7eSjoerg }
196506f32e7eSjoerg continue;
196606f32e7eSjoerg }
196706f32e7eSjoerg // We use invalid SourceLocations for the synthesized ivars since they
196806f32e7eSjoerg // aren't really synthesized at a particular location; they just exist.
196906f32e7eSjoerg // Saying that they are located at the @implementation isn't really going
197006f32e7eSjoerg // to help users.
197106f32e7eSjoerg ObjCPropertyImplDecl *PIDecl = dyn_cast_or_null<ObjCPropertyImplDecl>(
197206f32e7eSjoerg ActOnPropertyImplDecl(S, SourceLocation(), SourceLocation(),
197306f32e7eSjoerg true,
197406f32e7eSjoerg /* property = */ Prop->getIdentifier(),
197506f32e7eSjoerg /* ivar = */ Prop->getDefaultSynthIvarName(Context),
197606f32e7eSjoerg Prop->getLocation(), Prop->getQueryKind()));
197706f32e7eSjoerg if (PIDecl && !Prop->isUnavailable()) {
197806f32e7eSjoerg Diag(Prop->getLocation(), diag::warn_missing_explicit_synthesis);
197906f32e7eSjoerg Diag(IMPDecl->getLocation(), diag::note_while_in_implementation);
198006f32e7eSjoerg }
198106f32e7eSjoerg }
198206f32e7eSjoerg }
198306f32e7eSjoerg
DefaultSynthesizeProperties(Scope * S,Decl * D,SourceLocation AtEnd)198406f32e7eSjoerg void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D,
198506f32e7eSjoerg SourceLocation AtEnd) {
198606f32e7eSjoerg if (!LangOpts.ObjCDefaultSynthProperties || LangOpts.ObjCRuntime.isFragile())
198706f32e7eSjoerg return;
198806f32e7eSjoerg ObjCImplementationDecl *IC=dyn_cast_or_null<ObjCImplementationDecl>(D);
198906f32e7eSjoerg if (!IC)
199006f32e7eSjoerg return;
199106f32e7eSjoerg if (ObjCInterfaceDecl* IDecl = IC->getClassInterface())
199206f32e7eSjoerg if (!IDecl->isObjCRequiresPropertyDefs())
199306f32e7eSjoerg DefaultSynthesizeProperties(S, IC, IDecl, AtEnd);
199406f32e7eSjoerg }
199506f32e7eSjoerg
DiagnoseUnimplementedAccessor(Sema & S,ObjCInterfaceDecl * PrimaryClass,Selector Method,ObjCImplDecl * IMPDecl,ObjCContainerDecl * CDecl,ObjCCategoryDecl * C,ObjCPropertyDecl * Prop,llvm::SmallPtrSet<const ObjCMethodDecl *,8> & SMap)199606f32e7eSjoerg static void DiagnoseUnimplementedAccessor(
199706f32e7eSjoerg Sema &S, ObjCInterfaceDecl *PrimaryClass, Selector Method,
199806f32e7eSjoerg ObjCImplDecl *IMPDecl, ObjCContainerDecl *CDecl, ObjCCategoryDecl *C,
199906f32e7eSjoerg ObjCPropertyDecl *Prop,
200006f32e7eSjoerg llvm::SmallPtrSet<const ObjCMethodDecl *, 8> &SMap) {
200106f32e7eSjoerg // Check to see if we have a corresponding selector in SMap and with the
200206f32e7eSjoerg // right method type.
200306f32e7eSjoerg auto I = llvm::find_if(SMap, [&](const ObjCMethodDecl *x) {
200406f32e7eSjoerg return x->getSelector() == Method &&
200506f32e7eSjoerg x->isClassMethod() == Prop->isClassProperty();
200606f32e7eSjoerg });
200706f32e7eSjoerg // When reporting on missing property setter/getter implementation in
200806f32e7eSjoerg // categories, do not report when they are declared in primary class,
200906f32e7eSjoerg // class's protocol, or one of it super classes. This is because,
201006f32e7eSjoerg // the class is going to implement them.
201106f32e7eSjoerg if (I == SMap.end() &&
201206f32e7eSjoerg (PrimaryClass == nullptr ||
201306f32e7eSjoerg !PrimaryClass->lookupPropertyAccessor(Method, C,
201406f32e7eSjoerg Prop->isClassProperty()))) {
201506f32e7eSjoerg unsigned diag =
201606f32e7eSjoerg isa<ObjCCategoryDecl>(CDecl)
201706f32e7eSjoerg ? (Prop->isClassProperty()
201806f32e7eSjoerg ? diag::warn_impl_required_in_category_for_class_property
201906f32e7eSjoerg : diag::warn_setter_getter_impl_required_in_category)
202006f32e7eSjoerg : (Prop->isClassProperty()
202106f32e7eSjoerg ? diag::warn_impl_required_for_class_property
202206f32e7eSjoerg : diag::warn_setter_getter_impl_required);
202306f32e7eSjoerg S.Diag(IMPDecl->getLocation(), diag) << Prop->getDeclName() << Method;
202406f32e7eSjoerg S.Diag(Prop->getLocation(), diag::note_property_declare);
202506f32e7eSjoerg if (S.LangOpts.ObjCDefaultSynthProperties &&
202606f32e7eSjoerg S.LangOpts.ObjCRuntime.isNonFragile())
202706f32e7eSjoerg if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl))
202806f32e7eSjoerg if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs())
202906f32e7eSjoerg S.Diag(RID->getLocation(), diag::note_suppressed_class_declare);
203006f32e7eSjoerg }
203106f32e7eSjoerg }
203206f32e7eSjoerg
DiagnoseUnimplementedProperties(Scope * S,ObjCImplDecl * IMPDecl,ObjCContainerDecl * CDecl,bool SynthesizeProperties)203306f32e7eSjoerg void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
203406f32e7eSjoerg ObjCContainerDecl *CDecl,
203506f32e7eSjoerg bool SynthesizeProperties) {
203606f32e7eSjoerg ObjCContainerDecl::PropertyMap PropMap;
203706f32e7eSjoerg ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
203806f32e7eSjoerg
203906f32e7eSjoerg // Since we don't synthesize class properties, we should emit diagnose even
204006f32e7eSjoerg // if SynthesizeProperties is true.
204106f32e7eSjoerg ObjCContainerDecl::PropertyMap NoNeedToImplPropMap;
204206f32e7eSjoerg // Gather properties which need not be implemented in this class
204306f32e7eSjoerg // or category.
204406f32e7eSjoerg if (!IDecl)
204506f32e7eSjoerg if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
204606f32e7eSjoerg // For categories, no need to implement properties declared in
204706f32e7eSjoerg // its primary class (and its super classes) if property is
204806f32e7eSjoerg // declared in one of those containers.
204906f32e7eSjoerg if ((IDecl = C->getClassInterface())) {
205006f32e7eSjoerg ObjCInterfaceDecl::PropertyDeclOrder PO;
205106f32e7eSjoerg IDecl->collectPropertiesToImplement(NoNeedToImplPropMap, PO);
205206f32e7eSjoerg }
205306f32e7eSjoerg }
205406f32e7eSjoerg if (IDecl)
205506f32e7eSjoerg CollectSuperClassPropertyImplementations(IDecl, NoNeedToImplPropMap);
205606f32e7eSjoerg
205706f32e7eSjoerg // When SynthesizeProperties is true, we only check class properties.
205806f32e7eSjoerg CollectImmediateProperties(CDecl, PropMap, NoNeedToImplPropMap,
205906f32e7eSjoerg SynthesizeProperties/*CollectClassPropsOnly*/);
206006f32e7eSjoerg
206106f32e7eSjoerg // Scan the @interface to see if any of the protocols it adopts
206206f32e7eSjoerg // require an explicit implementation, via attribute
206306f32e7eSjoerg // 'objc_protocol_requires_explicit_implementation'.
206406f32e7eSjoerg if (IDecl) {
206506f32e7eSjoerg std::unique_ptr<ObjCContainerDecl::PropertyMap> LazyMap;
206606f32e7eSjoerg
206706f32e7eSjoerg for (auto *PDecl : IDecl->all_referenced_protocols()) {
206806f32e7eSjoerg if (!PDecl->hasAttr<ObjCExplicitProtocolImplAttr>())
206906f32e7eSjoerg continue;
207006f32e7eSjoerg // Lazily construct a set of all the properties in the @interface
207106f32e7eSjoerg // of the class, without looking at the superclass. We cannot
207206f32e7eSjoerg // use the call to CollectImmediateProperties() above as that
207306f32e7eSjoerg // utilizes information from the super class's properties as well
207406f32e7eSjoerg // as scans the adopted protocols. This work only triggers for protocols
207506f32e7eSjoerg // with the attribute, which is very rare, and only occurs when
207606f32e7eSjoerg // analyzing the @implementation.
207706f32e7eSjoerg if (!LazyMap) {
207806f32e7eSjoerg ObjCContainerDecl::PropertyMap NoNeedToImplPropMap;
207906f32e7eSjoerg LazyMap.reset(new ObjCContainerDecl::PropertyMap());
208006f32e7eSjoerg CollectImmediateProperties(CDecl, *LazyMap, NoNeedToImplPropMap,
208106f32e7eSjoerg /* CollectClassPropsOnly */ false,
208206f32e7eSjoerg /* IncludeProtocols */ false);
208306f32e7eSjoerg }
208406f32e7eSjoerg // Add the properties of 'PDecl' to the list of properties that
208506f32e7eSjoerg // need to be implemented.
208606f32e7eSjoerg for (auto *PropDecl : PDecl->properties()) {
208706f32e7eSjoerg if ((*LazyMap)[std::make_pair(PropDecl->getIdentifier(),
208806f32e7eSjoerg PropDecl->isClassProperty())])
208906f32e7eSjoerg continue;
209006f32e7eSjoerg PropMap[std::make_pair(PropDecl->getIdentifier(),
209106f32e7eSjoerg PropDecl->isClassProperty())] = PropDecl;
209206f32e7eSjoerg }
209306f32e7eSjoerg }
209406f32e7eSjoerg }
209506f32e7eSjoerg
209606f32e7eSjoerg if (PropMap.empty())
209706f32e7eSjoerg return;
209806f32e7eSjoerg
209906f32e7eSjoerg llvm::DenseSet<ObjCPropertyDecl *> PropImplMap;
210006f32e7eSjoerg for (const auto *I : IMPDecl->property_impls())
210106f32e7eSjoerg PropImplMap.insert(I->getPropertyDecl());
210206f32e7eSjoerg
210306f32e7eSjoerg llvm::SmallPtrSet<const ObjCMethodDecl *, 8> InsMap;
210406f32e7eSjoerg // Collect property accessors implemented in current implementation.
210506f32e7eSjoerg for (const auto *I : IMPDecl->methods())
210606f32e7eSjoerg InsMap.insert(I);
210706f32e7eSjoerg
210806f32e7eSjoerg ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl);
210906f32e7eSjoerg ObjCInterfaceDecl *PrimaryClass = nullptr;
211006f32e7eSjoerg if (C && !C->IsClassExtension())
211106f32e7eSjoerg if ((PrimaryClass = C->getClassInterface()))
211206f32e7eSjoerg // Report unimplemented properties in the category as well.
211306f32e7eSjoerg if (ObjCImplDecl *IMP = PrimaryClass->getImplementation()) {
211406f32e7eSjoerg // When reporting on missing setter/getters, do not report when
211506f32e7eSjoerg // setter/getter is implemented in category's primary class
211606f32e7eSjoerg // implementation.
211706f32e7eSjoerg for (const auto *I : IMP->methods())
211806f32e7eSjoerg InsMap.insert(I);
211906f32e7eSjoerg }
212006f32e7eSjoerg
212106f32e7eSjoerg for (ObjCContainerDecl::PropertyMap::iterator
212206f32e7eSjoerg P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
212306f32e7eSjoerg ObjCPropertyDecl *Prop = P->second;
212406f32e7eSjoerg // Is there a matching property synthesize/dynamic?
212506f32e7eSjoerg if (Prop->isInvalidDecl() ||
212606f32e7eSjoerg Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
212706f32e7eSjoerg PropImplMap.count(Prop) ||
212806f32e7eSjoerg Prop->getAvailability() == AR_Unavailable)
212906f32e7eSjoerg continue;
213006f32e7eSjoerg
213106f32e7eSjoerg // Diagnose unimplemented getters and setters.
213206f32e7eSjoerg DiagnoseUnimplementedAccessor(*this,
213306f32e7eSjoerg PrimaryClass, Prop->getGetterName(), IMPDecl, CDecl, C, Prop, InsMap);
213406f32e7eSjoerg if (!Prop->isReadOnly())
213506f32e7eSjoerg DiagnoseUnimplementedAccessor(*this,
213606f32e7eSjoerg PrimaryClass, Prop->getSetterName(),
213706f32e7eSjoerg IMPDecl, CDecl, C, Prop, InsMap);
213806f32e7eSjoerg }
213906f32e7eSjoerg }
214006f32e7eSjoerg
diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl * impDecl)214106f32e7eSjoerg void Sema::diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl) {
214206f32e7eSjoerg for (const auto *propertyImpl : impDecl->property_impls()) {
214306f32e7eSjoerg const auto *property = propertyImpl->getPropertyDecl();
214406f32e7eSjoerg // Warn about null_resettable properties with synthesized setters,
214506f32e7eSjoerg // because the setter won't properly handle nil.
2146*13fbcb42Sjoerg if (propertyImpl->getPropertyImplementation() ==
2147*13fbcb42Sjoerg ObjCPropertyImplDecl::Synthesize &&
214806f32e7eSjoerg (property->getPropertyAttributes() &
2149*13fbcb42Sjoerg ObjCPropertyAttribute::kind_null_resettable) &&
2150*13fbcb42Sjoerg property->getGetterMethodDecl() && property->getSetterMethodDecl()) {
2151*13fbcb42Sjoerg auto *getterImpl = propertyImpl->getGetterMethodDecl();
2152*13fbcb42Sjoerg auto *setterImpl = propertyImpl->getSetterMethodDecl();
2153*13fbcb42Sjoerg if ((!getterImpl || getterImpl->isSynthesizedAccessorStub()) &&
2154*13fbcb42Sjoerg (!setterImpl || setterImpl->isSynthesizedAccessorStub())) {
215506f32e7eSjoerg SourceLocation loc = propertyImpl->getLocation();
215606f32e7eSjoerg if (loc.isInvalid())
215706f32e7eSjoerg loc = impDecl->getBeginLoc();
215806f32e7eSjoerg
215906f32e7eSjoerg Diag(loc, diag::warn_null_resettable_setter)
2160*13fbcb42Sjoerg << setterImpl->getSelector() << property->getDeclName();
216106f32e7eSjoerg }
216206f32e7eSjoerg }
216306f32e7eSjoerg }
216406f32e7eSjoerg }
216506f32e7eSjoerg
216606f32e7eSjoerg void
AtomicPropertySetterGetterRules(ObjCImplDecl * IMPDecl,ObjCInterfaceDecl * IDecl)216706f32e7eSjoerg Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
216806f32e7eSjoerg ObjCInterfaceDecl* IDecl) {
216906f32e7eSjoerg // Rules apply in non-GC mode only
217006f32e7eSjoerg if (getLangOpts().getGC() != LangOptions::NonGC)
217106f32e7eSjoerg return;
217206f32e7eSjoerg ObjCContainerDecl::PropertyMap PM;
217306f32e7eSjoerg for (auto *Prop : IDecl->properties())
217406f32e7eSjoerg PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop;
217506f32e7eSjoerg for (const auto *Ext : IDecl->known_extensions())
217606f32e7eSjoerg for (auto *Prop : Ext->properties())
217706f32e7eSjoerg PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop;
217806f32e7eSjoerg
217906f32e7eSjoerg for (ObjCContainerDecl::PropertyMap::iterator I = PM.begin(), E = PM.end();
218006f32e7eSjoerg I != E; ++I) {
218106f32e7eSjoerg const ObjCPropertyDecl *Property = I->second;
218206f32e7eSjoerg ObjCMethodDecl *GetterMethod = nullptr;
218306f32e7eSjoerg ObjCMethodDecl *SetterMethod = nullptr;
218406f32e7eSjoerg
218506f32e7eSjoerg unsigned Attributes = Property->getPropertyAttributes();
218606f32e7eSjoerg unsigned AttributesAsWritten = Property->getPropertyAttributesAsWritten();
218706f32e7eSjoerg
2188*13fbcb42Sjoerg if (!(AttributesAsWritten & ObjCPropertyAttribute::kind_atomic) &&
2189*13fbcb42Sjoerg !(AttributesAsWritten & ObjCPropertyAttribute::kind_nonatomic)) {
219006f32e7eSjoerg GetterMethod = Property->isClassProperty() ?
219106f32e7eSjoerg IMPDecl->getClassMethod(Property->getGetterName()) :
219206f32e7eSjoerg IMPDecl->getInstanceMethod(Property->getGetterName());
219306f32e7eSjoerg SetterMethod = Property->isClassProperty() ?
219406f32e7eSjoerg IMPDecl->getClassMethod(Property->getSetterName()) :
219506f32e7eSjoerg IMPDecl->getInstanceMethod(Property->getSetterName());
2196*13fbcb42Sjoerg if (GetterMethod && GetterMethod->isSynthesizedAccessorStub())
2197*13fbcb42Sjoerg GetterMethod = nullptr;
2198*13fbcb42Sjoerg if (SetterMethod && SetterMethod->isSynthesizedAccessorStub())
2199*13fbcb42Sjoerg SetterMethod = nullptr;
220006f32e7eSjoerg if (GetterMethod) {
220106f32e7eSjoerg Diag(GetterMethod->getLocation(),
220206f32e7eSjoerg diag::warn_default_atomic_custom_getter_setter)
220306f32e7eSjoerg << Property->getIdentifier() << 0;
220406f32e7eSjoerg Diag(Property->getLocation(), diag::note_property_declare);
220506f32e7eSjoerg }
220606f32e7eSjoerg if (SetterMethod) {
220706f32e7eSjoerg Diag(SetterMethod->getLocation(),
220806f32e7eSjoerg diag::warn_default_atomic_custom_getter_setter)
220906f32e7eSjoerg << Property->getIdentifier() << 1;
221006f32e7eSjoerg Diag(Property->getLocation(), diag::note_property_declare);
221106f32e7eSjoerg }
221206f32e7eSjoerg }
221306f32e7eSjoerg
221406f32e7eSjoerg // We only care about readwrite atomic property.
2215*13fbcb42Sjoerg if ((Attributes & ObjCPropertyAttribute::kind_nonatomic) ||
2216*13fbcb42Sjoerg !(Attributes & ObjCPropertyAttribute::kind_readwrite))
221706f32e7eSjoerg continue;
221806f32e7eSjoerg if (const ObjCPropertyImplDecl *PIDecl = IMPDecl->FindPropertyImplDecl(
221906f32e7eSjoerg Property->getIdentifier(), Property->getQueryKind())) {
222006f32e7eSjoerg if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
222106f32e7eSjoerg continue;
2222*13fbcb42Sjoerg GetterMethod = PIDecl->getGetterMethodDecl();
2223*13fbcb42Sjoerg SetterMethod = PIDecl->getSetterMethodDecl();
2224*13fbcb42Sjoerg if (GetterMethod && GetterMethod->isSynthesizedAccessorStub())
2225*13fbcb42Sjoerg GetterMethod = nullptr;
2226*13fbcb42Sjoerg if (SetterMethod && SetterMethod->isSynthesizedAccessorStub())
2227*13fbcb42Sjoerg SetterMethod = nullptr;
2228*13fbcb42Sjoerg if ((bool)GetterMethod ^ (bool)SetterMethod) {
222906f32e7eSjoerg SourceLocation MethodLoc =
223006f32e7eSjoerg (GetterMethod ? GetterMethod->getLocation()
223106f32e7eSjoerg : SetterMethod->getLocation());
223206f32e7eSjoerg Diag(MethodLoc, diag::warn_atomic_property_rule)
223306f32e7eSjoerg << Property->getIdentifier() << (GetterMethod != nullptr)
223406f32e7eSjoerg << (SetterMethod != nullptr);
223506f32e7eSjoerg // fixit stuff.
223606f32e7eSjoerg if (Property->getLParenLoc().isValid() &&
2237*13fbcb42Sjoerg !(AttributesAsWritten & ObjCPropertyAttribute::kind_atomic)) {
223806f32e7eSjoerg // @property () ... case.
223906f32e7eSjoerg SourceLocation AfterLParen =
224006f32e7eSjoerg getLocForEndOfToken(Property->getLParenLoc());
224106f32e7eSjoerg StringRef NonatomicStr = AttributesAsWritten? "nonatomic, "
224206f32e7eSjoerg : "nonatomic";
224306f32e7eSjoerg Diag(Property->getLocation(),
224406f32e7eSjoerg diag::note_atomic_property_fixup_suggest)
224506f32e7eSjoerg << FixItHint::CreateInsertion(AfterLParen, NonatomicStr);
224606f32e7eSjoerg } else if (Property->getLParenLoc().isInvalid()) {
224706f32e7eSjoerg //@property id etc.
224806f32e7eSjoerg SourceLocation startLoc =
224906f32e7eSjoerg Property->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
225006f32e7eSjoerg Diag(Property->getLocation(),
225106f32e7eSjoerg diag::note_atomic_property_fixup_suggest)
225206f32e7eSjoerg << FixItHint::CreateInsertion(startLoc, "(nonatomic) ");
2253*13fbcb42Sjoerg } else
225406f32e7eSjoerg Diag(MethodLoc, diag::note_atomic_property_fixup_suggest);
225506f32e7eSjoerg Diag(Property->getLocation(), diag::note_property_declare);
225606f32e7eSjoerg }
225706f32e7eSjoerg }
225806f32e7eSjoerg }
225906f32e7eSjoerg }
226006f32e7eSjoerg
DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl * D)226106f32e7eSjoerg void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D) {
226206f32e7eSjoerg if (getLangOpts().getGC() == LangOptions::GCOnly)
226306f32e7eSjoerg return;
226406f32e7eSjoerg
226506f32e7eSjoerg for (const auto *PID : D->property_impls()) {
226606f32e7eSjoerg const ObjCPropertyDecl *PD = PID->getPropertyDecl();
226706f32e7eSjoerg if (PD && !PD->hasAttr<NSReturnsNotRetainedAttr>() &&
2268*13fbcb42Sjoerg !PD->isClassProperty()) {
2269*13fbcb42Sjoerg ObjCMethodDecl *IM = PID->getGetterMethodDecl();
2270*13fbcb42Sjoerg if (IM && !IM->isSynthesizedAccessorStub())
2271*13fbcb42Sjoerg continue;
227206f32e7eSjoerg ObjCMethodDecl *method = PD->getGetterMethodDecl();
227306f32e7eSjoerg if (!method)
227406f32e7eSjoerg continue;
227506f32e7eSjoerg ObjCMethodFamily family = method->getMethodFamily();
227606f32e7eSjoerg if (family == OMF_alloc || family == OMF_copy ||
227706f32e7eSjoerg family == OMF_mutableCopy || family == OMF_new) {
227806f32e7eSjoerg if (getLangOpts().ObjCAutoRefCount)
227906f32e7eSjoerg Diag(PD->getLocation(), diag::err_cocoa_naming_owned_rule);
228006f32e7eSjoerg else
228106f32e7eSjoerg Diag(PD->getLocation(), diag::warn_cocoa_naming_owned_rule);
228206f32e7eSjoerg
228306f32e7eSjoerg // Look for a getter explicitly declared alongside the property.
228406f32e7eSjoerg // If we find one, use its location for the note.
228506f32e7eSjoerg SourceLocation noteLoc = PD->getLocation();
228606f32e7eSjoerg SourceLocation fixItLoc;
228706f32e7eSjoerg for (auto *getterRedecl : method->redecls()) {
228806f32e7eSjoerg if (getterRedecl->isImplicit())
228906f32e7eSjoerg continue;
229006f32e7eSjoerg if (getterRedecl->getDeclContext() != PD->getDeclContext())
229106f32e7eSjoerg continue;
229206f32e7eSjoerg noteLoc = getterRedecl->getLocation();
229306f32e7eSjoerg fixItLoc = getterRedecl->getEndLoc();
229406f32e7eSjoerg }
229506f32e7eSjoerg
229606f32e7eSjoerg Preprocessor &PP = getPreprocessor();
229706f32e7eSjoerg TokenValue tokens[] = {
229806f32e7eSjoerg tok::kw___attribute, tok::l_paren, tok::l_paren,
229906f32e7eSjoerg PP.getIdentifierInfo("objc_method_family"), tok::l_paren,
230006f32e7eSjoerg PP.getIdentifierInfo("none"), tok::r_paren,
230106f32e7eSjoerg tok::r_paren, tok::r_paren
230206f32e7eSjoerg };
230306f32e7eSjoerg StringRef spelling = "__attribute__((objc_method_family(none)))";
230406f32e7eSjoerg StringRef macroName = PP.getLastMacroWithSpelling(noteLoc, tokens);
230506f32e7eSjoerg if (!macroName.empty())
230606f32e7eSjoerg spelling = macroName;
230706f32e7eSjoerg
230806f32e7eSjoerg auto noteDiag = Diag(noteLoc, diag::note_cocoa_naming_declare_family)
230906f32e7eSjoerg << method->getDeclName() << spelling;
231006f32e7eSjoerg if (fixItLoc.isValid()) {
231106f32e7eSjoerg SmallString<64> fixItText(" ");
231206f32e7eSjoerg fixItText += spelling;
231306f32e7eSjoerg noteDiag << FixItHint::CreateInsertion(fixItLoc, fixItText);
231406f32e7eSjoerg }
231506f32e7eSjoerg }
231606f32e7eSjoerg }
231706f32e7eSjoerg }
231806f32e7eSjoerg }
231906f32e7eSjoerg
DiagnoseMissingDesignatedInitOverrides(const ObjCImplementationDecl * ImplD,const ObjCInterfaceDecl * IFD)232006f32e7eSjoerg void Sema::DiagnoseMissingDesignatedInitOverrides(
232106f32e7eSjoerg const ObjCImplementationDecl *ImplD,
232206f32e7eSjoerg const ObjCInterfaceDecl *IFD) {
232306f32e7eSjoerg assert(IFD->hasDesignatedInitializers());
232406f32e7eSjoerg const ObjCInterfaceDecl *SuperD = IFD->getSuperClass();
232506f32e7eSjoerg if (!SuperD)
232606f32e7eSjoerg return;
232706f32e7eSjoerg
232806f32e7eSjoerg SelectorSet InitSelSet;
232906f32e7eSjoerg for (const auto *I : ImplD->instance_methods())
233006f32e7eSjoerg if (I->getMethodFamily() == OMF_init)
233106f32e7eSjoerg InitSelSet.insert(I->getSelector());
233206f32e7eSjoerg
233306f32e7eSjoerg SmallVector<const ObjCMethodDecl *, 8> DesignatedInits;
233406f32e7eSjoerg SuperD->getDesignatedInitializers(DesignatedInits);
233506f32e7eSjoerg for (SmallVector<const ObjCMethodDecl *, 8>::iterator
233606f32e7eSjoerg I = DesignatedInits.begin(), E = DesignatedInits.end(); I != E; ++I) {
233706f32e7eSjoerg const ObjCMethodDecl *MD = *I;
233806f32e7eSjoerg if (!InitSelSet.count(MD->getSelector())) {
233906f32e7eSjoerg // Don't emit a diagnostic if the overriding method in the subclass is
234006f32e7eSjoerg // marked as unavailable.
234106f32e7eSjoerg bool Ignore = false;
234206f32e7eSjoerg if (auto *IMD = IFD->getInstanceMethod(MD->getSelector())) {
234306f32e7eSjoerg Ignore = IMD->isUnavailable();
234406f32e7eSjoerg } else {
234506f32e7eSjoerg // Check the methods declared in the class extensions too.
234606f32e7eSjoerg for (auto *Ext : IFD->visible_extensions())
234706f32e7eSjoerg if (auto *IMD = Ext->getInstanceMethod(MD->getSelector())) {
234806f32e7eSjoerg Ignore = IMD->isUnavailable();
234906f32e7eSjoerg break;
235006f32e7eSjoerg }
235106f32e7eSjoerg }
235206f32e7eSjoerg if (!Ignore) {
235306f32e7eSjoerg Diag(ImplD->getLocation(),
235406f32e7eSjoerg diag::warn_objc_implementation_missing_designated_init_override)
235506f32e7eSjoerg << MD->getSelector();
235606f32e7eSjoerg Diag(MD->getLocation(), diag::note_objc_designated_init_marked_here);
235706f32e7eSjoerg }
235806f32e7eSjoerg }
235906f32e7eSjoerg }
236006f32e7eSjoerg }
236106f32e7eSjoerg
236206f32e7eSjoerg /// AddPropertyAttrs - Propagates attributes from a property to the
236306f32e7eSjoerg /// implicitly-declared getter or setter for that property.
AddPropertyAttrs(Sema & S,ObjCMethodDecl * PropertyMethod,ObjCPropertyDecl * Property)236406f32e7eSjoerg static void AddPropertyAttrs(Sema &S, ObjCMethodDecl *PropertyMethod,
236506f32e7eSjoerg ObjCPropertyDecl *Property) {
236606f32e7eSjoerg // Should we just clone all attributes over?
236706f32e7eSjoerg for (const auto *A : Property->attrs()) {
236806f32e7eSjoerg if (isa<DeprecatedAttr>(A) ||
236906f32e7eSjoerg isa<UnavailableAttr>(A) ||
237006f32e7eSjoerg isa<AvailabilityAttr>(A))
237106f32e7eSjoerg PropertyMethod->addAttr(A->clone(S.Context));
237206f32e7eSjoerg }
237306f32e7eSjoerg }
237406f32e7eSjoerg
237506f32e7eSjoerg /// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods
237606f32e7eSjoerg /// have the property type and issue diagnostics if they don't.
237706f32e7eSjoerg /// Also synthesize a getter/setter method if none exist (and update the
237806f32e7eSjoerg /// appropriate lookup tables.
ProcessPropertyDecl(ObjCPropertyDecl * property)237906f32e7eSjoerg void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
238006f32e7eSjoerg ObjCMethodDecl *GetterMethod, *SetterMethod;
238106f32e7eSjoerg ObjCContainerDecl *CD = cast<ObjCContainerDecl>(property->getDeclContext());
238206f32e7eSjoerg if (CD->isInvalidDecl())
238306f32e7eSjoerg return;
238406f32e7eSjoerg
238506f32e7eSjoerg bool IsClassProperty = property->isClassProperty();
238606f32e7eSjoerg GetterMethod = IsClassProperty ?
238706f32e7eSjoerg CD->getClassMethod(property->getGetterName()) :
238806f32e7eSjoerg CD->getInstanceMethod(property->getGetterName());
238906f32e7eSjoerg
239006f32e7eSjoerg // if setter or getter is not found in class extension, it might be
239106f32e7eSjoerg // in the primary class.
239206f32e7eSjoerg if (!GetterMethod)
239306f32e7eSjoerg if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD))
239406f32e7eSjoerg if (CatDecl->IsClassExtension())
239506f32e7eSjoerg GetterMethod = IsClassProperty ? CatDecl->getClassInterface()->
239606f32e7eSjoerg getClassMethod(property->getGetterName()) :
239706f32e7eSjoerg CatDecl->getClassInterface()->
239806f32e7eSjoerg getInstanceMethod(property->getGetterName());
239906f32e7eSjoerg
240006f32e7eSjoerg SetterMethod = IsClassProperty ?
240106f32e7eSjoerg CD->getClassMethod(property->getSetterName()) :
240206f32e7eSjoerg CD->getInstanceMethod(property->getSetterName());
240306f32e7eSjoerg if (!SetterMethod)
240406f32e7eSjoerg if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD))
240506f32e7eSjoerg if (CatDecl->IsClassExtension())
240606f32e7eSjoerg SetterMethod = IsClassProperty ? CatDecl->getClassInterface()->
240706f32e7eSjoerg getClassMethod(property->getSetterName()) :
240806f32e7eSjoerg CatDecl->getClassInterface()->
240906f32e7eSjoerg getInstanceMethod(property->getSetterName());
241006f32e7eSjoerg DiagnosePropertyAccessorMismatch(property, GetterMethod,
241106f32e7eSjoerg property->getLocation());
241206f32e7eSjoerg
2413*13fbcb42Sjoerg // synthesizing accessors must not result in a direct method that is not
2414*13fbcb42Sjoerg // monomorphic
2415*13fbcb42Sjoerg if (!GetterMethod) {
2416*13fbcb42Sjoerg if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD)) {
2417*13fbcb42Sjoerg auto *ExistingGetter = CatDecl->getClassInterface()->lookupMethod(
2418*13fbcb42Sjoerg property->getGetterName(), !IsClassProperty, true, false, CatDecl);
2419*13fbcb42Sjoerg if (ExistingGetter) {
2420*13fbcb42Sjoerg if (ExistingGetter->isDirectMethod() || property->isDirectProperty()) {
2421*13fbcb42Sjoerg Diag(property->getLocation(), diag::err_objc_direct_duplicate_decl)
2422*13fbcb42Sjoerg << property->isDirectProperty() << 1 /* property */
2423*13fbcb42Sjoerg << ExistingGetter->isDirectMethod()
2424*13fbcb42Sjoerg << ExistingGetter->getDeclName();
2425*13fbcb42Sjoerg Diag(ExistingGetter->getLocation(), diag::note_previous_declaration);
2426*13fbcb42Sjoerg }
2427*13fbcb42Sjoerg }
2428*13fbcb42Sjoerg }
2429*13fbcb42Sjoerg }
2430*13fbcb42Sjoerg
2431*13fbcb42Sjoerg if (!property->isReadOnly() && !SetterMethod) {
2432*13fbcb42Sjoerg if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD)) {
2433*13fbcb42Sjoerg auto *ExistingSetter = CatDecl->getClassInterface()->lookupMethod(
2434*13fbcb42Sjoerg property->getSetterName(), !IsClassProperty, true, false, CatDecl);
2435*13fbcb42Sjoerg if (ExistingSetter) {
2436*13fbcb42Sjoerg if (ExistingSetter->isDirectMethod() || property->isDirectProperty()) {
2437*13fbcb42Sjoerg Diag(property->getLocation(), diag::err_objc_direct_duplicate_decl)
2438*13fbcb42Sjoerg << property->isDirectProperty() << 1 /* property */
2439*13fbcb42Sjoerg << ExistingSetter->isDirectMethod()
2440*13fbcb42Sjoerg << ExistingSetter->getDeclName();
2441*13fbcb42Sjoerg Diag(ExistingSetter->getLocation(), diag::note_previous_declaration);
2442*13fbcb42Sjoerg }
2443*13fbcb42Sjoerg }
2444*13fbcb42Sjoerg }
2445*13fbcb42Sjoerg }
2446*13fbcb42Sjoerg
244706f32e7eSjoerg if (!property->isReadOnly() && SetterMethod) {
244806f32e7eSjoerg if (Context.getCanonicalType(SetterMethod->getReturnType()) !=
244906f32e7eSjoerg Context.VoidTy)
245006f32e7eSjoerg Diag(SetterMethod->getLocation(), diag::err_setter_type_void);
245106f32e7eSjoerg if (SetterMethod->param_size() != 1 ||
245206f32e7eSjoerg !Context.hasSameUnqualifiedType(
245306f32e7eSjoerg (*SetterMethod->param_begin())->getType().getNonReferenceType(),
245406f32e7eSjoerg property->getType().getNonReferenceType())) {
245506f32e7eSjoerg Diag(property->getLocation(),
245606f32e7eSjoerg diag::warn_accessor_property_type_mismatch)
245706f32e7eSjoerg << property->getDeclName()
245806f32e7eSjoerg << SetterMethod->getSelector();
245906f32e7eSjoerg Diag(SetterMethod->getLocation(), diag::note_declared_at);
246006f32e7eSjoerg }
246106f32e7eSjoerg }
246206f32e7eSjoerg
246306f32e7eSjoerg // Synthesize getter/setter methods if none exist.
246406f32e7eSjoerg // Find the default getter and if one not found, add one.
246506f32e7eSjoerg // FIXME: The synthesized property we set here is misleading. We almost always
246606f32e7eSjoerg // synthesize these methods unless the user explicitly provided prototypes
246706f32e7eSjoerg // (which is odd, but allowed). Sema should be typechecking that the
246806f32e7eSjoerg // declarations jive in that situation (which it is not currently).
246906f32e7eSjoerg if (!GetterMethod) {
247006f32e7eSjoerg // No instance/class method of same name as property getter name was found.
247106f32e7eSjoerg // Declare a getter method and add it to the list of methods
247206f32e7eSjoerg // for this class.
247306f32e7eSjoerg SourceLocation Loc = property->getLocation();
247406f32e7eSjoerg
247506f32e7eSjoerg // The getter returns the declared property type with all qualifiers
247606f32e7eSjoerg // removed.
247706f32e7eSjoerg QualType resultTy = property->getType().getAtomicUnqualifiedType();
247806f32e7eSjoerg
247906f32e7eSjoerg // If the property is null_resettable, the getter returns nonnull.
248006f32e7eSjoerg if (property->getPropertyAttributes() &
2481*13fbcb42Sjoerg ObjCPropertyAttribute::kind_null_resettable) {
248206f32e7eSjoerg QualType modifiedTy = resultTy;
248306f32e7eSjoerg if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)) {
248406f32e7eSjoerg if (*nullability == NullabilityKind::Unspecified)
248506f32e7eSjoerg resultTy = Context.getAttributedType(attr::TypeNonNull,
248606f32e7eSjoerg modifiedTy, modifiedTy);
248706f32e7eSjoerg }
248806f32e7eSjoerg }
248906f32e7eSjoerg
2490*13fbcb42Sjoerg GetterMethod = ObjCMethodDecl::Create(
2491*13fbcb42Sjoerg Context, Loc, Loc, property->getGetterName(), resultTy, nullptr, CD,
249206f32e7eSjoerg !IsClassProperty, /*isVariadic=*/false,
2493*13fbcb42Sjoerg /*isPropertyAccessor=*/true, /*isSynthesizedAccessorStub=*/false,
249406f32e7eSjoerg /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
2495*13fbcb42Sjoerg (property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
2496*13fbcb42Sjoerg ? ObjCMethodDecl::Optional
2497*13fbcb42Sjoerg : ObjCMethodDecl::Required);
249806f32e7eSjoerg CD->addDecl(GetterMethod);
249906f32e7eSjoerg
250006f32e7eSjoerg AddPropertyAttrs(*this, GetterMethod, property);
250106f32e7eSjoerg
2502*13fbcb42Sjoerg if (property->isDirectProperty())
2503*13fbcb42Sjoerg GetterMethod->addAttr(ObjCDirectAttr::CreateImplicit(Context, Loc));
2504*13fbcb42Sjoerg
250506f32e7eSjoerg if (property->hasAttr<NSReturnsNotRetainedAttr>())
250606f32e7eSjoerg GetterMethod->addAttr(NSReturnsNotRetainedAttr::CreateImplicit(Context,
250706f32e7eSjoerg Loc));
250806f32e7eSjoerg
250906f32e7eSjoerg if (property->hasAttr<ObjCReturnsInnerPointerAttr>())
251006f32e7eSjoerg GetterMethod->addAttr(
251106f32e7eSjoerg ObjCReturnsInnerPointerAttr::CreateImplicit(Context, Loc));
251206f32e7eSjoerg
251306f32e7eSjoerg if (const SectionAttr *SA = property->getAttr<SectionAttr>())
251406f32e7eSjoerg GetterMethod->addAttr(SectionAttr::CreateImplicit(
251506f32e7eSjoerg Context, SA->getName(), Loc, AttributeCommonInfo::AS_GNU,
251606f32e7eSjoerg SectionAttr::GNU_section));
251706f32e7eSjoerg
251806f32e7eSjoerg if (getLangOpts().ObjCAutoRefCount)
251906f32e7eSjoerg CheckARCMethodDecl(GetterMethod);
252006f32e7eSjoerg } else
252106f32e7eSjoerg // A user declared getter will be synthesize when @synthesize of
252206f32e7eSjoerg // the property with the same name is seen in the @implementation
252306f32e7eSjoerg GetterMethod->setPropertyAccessor(true);
2524*13fbcb42Sjoerg
2525*13fbcb42Sjoerg GetterMethod->createImplicitParams(Context,
2526*13fbcb42Sjoerg GetterMethod->getClassInterface());
252706f32e7eSjoerg property->setGetterMethodDecl(GetterMethod);
252806f32e7eSjoerg
252906f32e7eSjoerg // Skip setter if property is read-only.
253006f32e7eSjoerg if (!property->isReadOnly()) {
253106f32e7eSjoerg // Find the default setter and if one not found, add one.
253206f32e7eSjoerg if (!SetterMethod) {
253306f32e7eSjoerg // No instance/class method of same name as property setter name was
253406f32e7eSjoerg // found.
253506f32e7eSjoerg // Declare a setter method and add it to the list of methods
253606f32e7eSjoerg // for this class.
253706f32e7eSjoerg SourceLocation Loc = property->getLocation();
253806f32e7eSjoerg
253906f32e7eSjoerg SetterMethod =
254006f32e7eSjoerg ObjCMethodDecl::Create(Context, Loc, Loc,
254106f32e7eSjoerg property->getSetterName(), Context.VoidTy,
254206f32e7eSjoerg nullptr, CD, !IsClassProperty,
254306f32e7eSjoerg /*isVariadic=*/false,
254406f32e7eSjoerg /*isPropertyAccessor=*/true,
2545*13fbcb42Sjoerg /*isSynthesizedAccessorStub=*/false,
254606f32e7eSjoerg /*isImplicitlyDeclared=*/true,
254706f32e7eSjoerg /*isDefined=*/false,
254806f32e7eSjoerg (property->getPropertyImplementation() ==
254906f32e7eSjoerg ObjCPropertyDecl::Optional) ?
255006f32e7eSjoerg ObjCMethodDecl::Optional :
255106f32e7eSjoerg ObjCMethodDecl::Required);
255206f32e7eSjoerg
255306f32e7eSjoerg // Remove all qualifiers from the setter's parameter type.
255406f32e7eSjoerg QualType paramTy =
255506f32e7eSjoerg property->getType().getUnqualifiedType().getAtomicUnqualifiedType();
255606f32e7eSjoerg
255706f32e7eSjoerg // If the property is null_resettable, the setter accepts a
255806f32e7eSjoerg // nullable value.
255906f32e7eSjoerg if (property->getPropertyAttributes() &
2560*13fbcb42Sjoerg ObjCPropertyAttribute::kind_null_resettable) {
256106f32e7eSjoerg QualType modifiedTy = paramTy;
256206f32e7eSjoerg if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)){
256306f32e7eSjoerg if (*nullability == NullabilityKind::Unspecified)
256406f32e7eSjoerg paramTy = Context.getAttributedType(attr::TypeNullable,
256506f32e7eSjoerg modifiedTy, modifiedTy);
256606f32e7eSjoerg }
256706f32e7eSjoerg }
256806f32e7eSjoerg
256906f32e7eSjoerg // Invent the arguments for the setter. We don't bother making a
257006f32e7eSjoerg // nice name for the argument.
257106f32e7eSjoerg ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod,
257206f32e7eSjoerg Loc, Loc,
257306f32e7eSjoerg property->getIdentifier(),
257406f32e7eSjoerg paramTy,
257506f32e7eSjoerg /*TInfo=*/nullptr,
257606f32e7eSjoerg SC_None,
257706f32e7eSjoerg nullptr);
257806f32e7eSjoerg SetterMethod->setMethodParams(Context, Argument, None);
257906f32e7eSjoerg
258006f32e7eSjoerg AddPropertyAttrs(*this, SetterMethod, property);
258106f32e7eSjoerg
2582*13fbcb42Sjoerg if (property->isDirectProperty())
2583*13fbcb42Sjoerg SetterMethod->addAttr(ObjCDirectAttr::CreateImplicit(Context, Loc));
2584*13fbcb42Sjoerg
258506f32e7eSjoerg CD->addDecl(SetterMethod);
258606f32e7eSjoerg if (const SectionAttr *SA = property->getAttr<SectionAttr>())
258706f32e7eSjoerg SetterMethod->addAttr(SectionAttr::CreateImplicit(
258806f32e7eSjoerg Context, SA->getName(), Loc, AttributeCommonInfo::AS_GNU,
258906f32e7eSjoerg SectionAttr::GNU_section));
259006f32e7eSjoerg // It's possible for the user to have set a very odd custom
259106f32e7eSjoerg // setter selector that causes it to have a method family.
259206f32e7eSjoerg if (getLangOpts().ObjCAutoRefCount)
259306f32e7eSjoerg CheckARCMethodDecl(SetterMethod);
259406f32e7eSjoerg } else
259506f32e7eSjoerg // A user declared setter will be synthesize when @synthesize of
259606f32e7eSjoerg // the property with the same name is seen in the @implementation
259706f32e7eSjoerg SetterMethod->setPropertyAccessor(true);
2598*13fbcb42Sjoerg
2599*13fbcb42Sjoerg SetterMethod->createImplicitParams(Context,
2600*13fbcb42Sjoerg SetterMethod->getClassInterface());
260106f32e7eSjoerg property->setSetterMethodDecl(SetterMethod);
260206f32e7eSjoerg }
260306f32e7eSjoerg // Add any synthesized methods to the global pool. This allows us to
260406f32e7eSjoerg // handle the following, which is supported by GCC (and part of the design).
260506f32e7eSjoerg //
260606f32e7eSjoerg // @interface Foo
260706f32e7eSjoerg // @property double bar;
260806f32e7eSjoerg // @end
260906f32e7eSjoerg //
261006f32e7eSjoerg // void thisIsUnfortunate() {
261106f32e7eSjoerg // id foo;
261206f32e7eSjoerg // double bar = [foo bar];
261306f32e7eSjoerg // }
261406f32e7eSjoerg //
261506f32e7eSjoerg if (!IsClassProperty) {
261606f32e7eSjoerg if (GetterMethod)
261706f32e7eSjoerg AddInstanceMethodToGlobalPool(GetterMethod);
261806f32e7eSjoerg if (SetterMethod)
261906f32e7eSjoerg AddInstanceMethodToGlobalPool(SetterMethod);
262006f32e7eSjoerg } else {
262106f32e7eSjoerg if (GetterMethod)
262206f32e7eSjoerg AddFactoryMethodToGlobalPool(GetterMethod);
262306f32e7eSjoerg if (SetterMethod)
262406f32e7eSjoerg AddFactoryMethodToGlobalPool(SetterMethod);
262506f32e7eSjoerg }
262606f32e7eSjoerg
262706f32e7eSjoerg ObjCInterfaceDecl *CurrentClass = dyn_cast<ObjCInterfaceDecl>(CD);
262806f32e7eSjoerg if (!CurrentClass) {
262906f32e7eSjoerg if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(CD))
263006f32e7eSjoerg CurrentClass = Cat->getClassInterface();
263106f32e7eSjoerg else if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(CD))
263206f32e7eSjoerg CurrentClass = Impl->getClassInterface();
263306f32e7eSjoerg }
263406f32e7eSjoerg if (GetterMethod)
263506f32e7eSjoerg CheckObjCMethodOverrides(GetterMethod, CurrentClass, Sema::RTC_Unknown);
263606f32e7eSjoerg if (SetterMethod)
263706f32e7eSjoerg CheckObjCMethodOverrides(SetterMethod, CurrentClass, Sema::RTC_Unknown);
263806f32e7eSjoerg }
263906f32e7eSjoerg
CheckObjCPropertyAttributes(Decl * PDecl,SourceLocation Loc,unsigned & Attributes,bool propertyInPrimaryClass)264006f32e7eSjoerg void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
264106f32e7eSjoerg SourceLocation Loc,
264206f32e7eSjoerg unsigned &Attributes,
264306f32e7eSjoerg bool propertyInPrimaryClass) {
264406f32e7eSjoerg // FIXME: Improve the reported location.
264506f32e7eSjoerg if (!PDecl || PDecl->isInvalidDecl())
264606f32e7eSjoerg return;
264706f32e7eSjoerg
2648*13fbcb42Sjoerg if ((Attributes & ObjCPropertyAttribute::kind_readonly) &&
2649*13fbcb42Sjoerg (Attributes & ObjCPropertyAttribute::kind_readwrite))
265006f32e7eSjoerg Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
265106f32e7eSjoerg << "readonly" << "readwrite";
265206f32e7eSjoerg
265306f32e7eSjoerg ObjCPropertyDecl *PropertyDecl = cast<ObjCPropertyDecl>(PDecl);
265406f32e7eSjoerg QualType PropertyTy = PropertyDecl->getType();
265506f32e7eSjoerg
265606f32e7eSjoerg // Check for copy or retain on non-object types.
2657*13fbcb42Sjoerg if ((Attributes &
2658*13fbcb42Sjoerg (ObjCPropertyAttribute::kind_weak | ObjCPropertyAttribute::kind_copy |
2659*13fbcb42Sjoerg ObjCPropertyAttribute::kind_retain |
2660*13fbcb42Sjoerg ObjCPropertyAttribute::kind_strong)) &&
266106f32e7eSjoerg !PropertyTy->isObjCRetainableType() &&
266206f32e7eSjoerg !PropertyDecl->hasAttr<ObjCNSObjectAttr>()) {
266306f32e7eSjoerg Diag(Loc, diag::err_objc_property_requires_object)
2664*13fbcb42Sjoerg << (Attributes & ObjCPropertyAttribute::kind_weak
2665*13fbcb42Sjoerg ? "weak"
2666*13fbcb42Sjoerg : Attributes & ObjCPropertyAttribute::kind_copy
2667*13fbcb42Sjoerg ? "copy"
2668*13fbcb42Sjoerg : "retain (or strong)");
2669*13fbcb42Sjoerg Attributes &=
2670*13fbcb42Sjoerg ~(ObjCPropertyAttribute::kind_weak | ObjCPropertyAttribute::kind_copy |
2671*13fbcb42Sjoerg ObjCPropertyAttribute::kind_retain |
2672*13fbcb42Sjoerg ObjCPropertyAttribute::kind_strong);
267306f32e7eSjoerg PropertyDecl->setInvalidDecl();
267406f32e7eSjoerg }
267506f32e7eSjoerg
267606f32e7eSjoerg // Check for assign on object types.
2677*13fbcb42Sjoerg if ((Attributes & ObjCPropertyAttribute::kind_assign) &&
2678*13fbcb42Sjoerg !(Attributes & ObjCPropertyAttribute::kind_unsafe_unretained) &&
267906f32e7eSjoerg PropertyTy->isObjCRetainableType() &&
268006f32e7eSjoerg !PropertyTy->isObjCARCImplicitlyUnretainedType()) {
268106f32e7eSjoerg Diag(Loc, diag::warn_objc_property_assign_on_object);
268206f32e7eSjoerg }
268306f32e7eSjoerg
268406f32e7eSjoerg // Check for more than one of { assign, copy, retain }.
2685*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_assign) {
2686*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_copy) {
268706f32e7eSjoerg Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
268806f32e7eSjoerg << "assign" << "copy";
2689*13fbcb42Sjoerg Attributes &= ~ObjCPropertyAttribute::kind_copy;
269006f32e7eSjoerg }
2691*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_retain) {
269206f32e7eSjoerg Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
269306f32e7eSjoerg << "assign" << "retain";
2694*13fbcb42Sjoerg Attributes &= ~ObjCPropertyAttribute::kind_retain;
269506f32e7eSjoerg }
2696*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_strong) {
269706f32e7eSjoerg Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
269806f32e7eSjoerg << "assign" << "strong";
2699*13fbcb42Sjoerg Attributes &= ~ObjCPropertyAttribute::kind_strong;
270006f32e7eSjoerg }
270106f32e7eSjoerg if (getLangOpts().ObjCAutoRefCount &&
2702*13fbcb42Sjoerg (Attributes & ObjCPropertyAttribute::kind_weak)) {
270306f32e7eSjoerg Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
270406f32e7eSjoerg << "assign" << "weak";
2705*13fbcb42Sjoerg Attributes &= ~ObjCPropertyAttribute::kind_weak;
270606f32e7eSjoerg }
270706f32e7eSjoerg if (PropertyDecl->hasAttr<IBOutletCollectionAttr>())
270806f32e7eSjoerg Diag(Loc, diag::warn_iboutletcollection_property_assign);
2709*13fbcb42Sjoerg } else if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained) {
2710*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_copy) {
271106f32e7eSjoerg Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
271206f32e7eSjoerg << "unsafe_unretained" << "copy";
2713*13fbcb42Sjoerg Attributes &= ~ObjCPropertyAttribute::kind_copy;
271406f32e7eSjoerg }
2715*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_retain) {
271606f32e7eSjoerg Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
271706f32e7eSjoerg << "unsafe_unretained" << "retain";
2718*13fbcb42Sjoerg Attributes &= ~ObjCPropertyAttribute::kind_retain;
271906f32e7eSjoerg }
2720*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_strong) {
272106f32e7eSjoerg Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
272206f32e7eSjoerg << "unsafe_unretained" << "strong";
2723*13fbcb42Sjoerg Attributes &= ~ObjCPropertyAttribute::kind_strong;
272406f32e7eSjoerg }
272506f32e7eSjoerg if (getLangOpts().ObjCAutoRefCount &&
2726*13fbcb42Sjoerg (Attributes & ObjCPropertyAttribute::kind_weak)) {
272706f32e7eSjoerg Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
272806f32e7eSjoerg << "unsafe_unretained" << "weak";
2729*13fbcb42Sjoerg Attributes &= ~ObjCPropertyAttribute::kind_weak;
273006f32e7eSjoerg }
2731*13fbcb42Sjoerg } else if (Attributes & ObjCPropertyAttribute::kind_copy) {
2732*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_retain) {
273306f32e7eSjoerg Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
273406f32e7eSjoerg << "copy" << "retain";
2735*13fbcb42Sjoerg Attributes &= ~ObjCPropertyAttribute::kind_retain;
273606f32e7eSjoerg }
2737*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_strong) {
273806f32e7eSjoerg Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
273906f32e7eSjoerg << "copy" << "strong";
2740*13fbcb42Sjoerg Attributes &= ~ObjCPropertyAttribute::kind_strong;
274106f32e7eSjoerg }
2742*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_weak) {
274306f32e7eSjoerg Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
274406f32e7eSjoerg << "copy" << "weak";
2745*13fbcb42Sjoerg Attributes &= ~ObjCPropertyAttribute::kind_weak;
274606f32e7eSjoerg }
2747*13fbcb42Sjoerg } else if ((Attributes & ObjCPropertyAttribute::kind_retain) &&
2748*13fbcb42Sjoerg (Attributes & ObjCPropertyAttribute::kind_weak)) {
2749*13fbcb42Sjoerg Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "retain"
2750*13fbcb42Sjoerg << "weak";
2751*13fbcb42Sjoerg Attributes &= ~ObjCPropertyAttribute::kind_retain;
2752*13fbcb42Sjoerg } else if ((Attributes & ObjCPropertyAttribute::kind_strong) &&
2753*13fbcb42Sjoerg (Attributes & ObjCPropertyAttribute::kind_weak)) {
2754*13fbcb42Sjoerg Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "strong"
2755*13fbcb42Sjoerg << "weak";
2756*13fbcb42Sjoerg Attributes &= ~ObjCPropertyAttribute::kind_weak;
275706f32e7eSjoerg }
275806f32e7eSjoerg
2759*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_weak) {
276006f32e7eSjoerg // 'weak' and 'nonnull' are mutually exclusive.
276106f32e7eSjoerg if (auto nullability = PropertyTy->getNullability(Context)) {
276206f32e7eSjoerg if (*nullability == NullabilityKind::NonNull)
276306f32e7eSjoerg Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
276406f32e7eSjoerg << "nonnull" << "weak";
276506f32e7eSjoerg }
276606f32e7eSjoerg }
276706f32e7eSjoerg
2768*13fbcb42Sjoerg if ((Attributes & ObjCPropertyAttribute::kind_atomic) &&
2769*13fbcb42Sjoerg (Attributes & ObjCPropertyAttribute::kind_nonatomic)) {
2770*13fbcb42Sjoerg Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "atomic"
2771*13fbcb42Sjoerg << "nonatomic";
2772*13fbcb42Sjoerg Attributes &= ~ObjCPropertyAttribute::kind_atomic;
277306f32e7eSjoerg }
277406f32e7eSjoerg
277506f32e7eSjoerg // Warn if user supplied no assignment attribute, property is
277606f32e7eSjoerg // readwrite, and this is an object type.
277706f32e7eSjoerg if (!getOwnershipRule(Attributes) && PropertyTy->isObjCRetainableType()) {
2778*13fbcb42Sjoerg if (Attributes & ObjCPropertyAttribute::kind_readonly) {
277906f32e7eSjoerg // do nothing
278006f32e7eSjoerg } else if (getLangOpts().ObjCAutoRefCount) {
278106f32e7eSjoerg // With arc, @property definitions should default to strong when
278206f32e7eSjoerg // not specified.
2783*13fbcb42Sjoerg PropertyDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_strong);
278406f32e7eSjoerg } else if (PropertyTy->isObjCObjectPointerType()) {
2785*13fbcb42Sjoerg bool isAnyClassTy = (PropertyTy->isObjCClassType() ||
278606f32e7eSjoerg PropertyTy->isObjCQualifiedClassType());
278706f32e7eSjoerg // In non-gc, non-arc mode, 'Class' is treated as a 'void *' no need to
278806f32e7eSjoerg // issue any warning.
278906f32e7eSjoerg if (isAnyClassTy && getLangOpts().getGC() == LangOptions::NonGC)
279006f32e7eSjoerg ;
279106f32e7eSjoerg else if (propertyInPrimaryClass) {
279206f32e7eSjoerg // Don't issue warning on property with no life time in class
279306f32e7eSjoerg // extension as it is inherited from property in primary class.
279406f32e7eSjoerg // Skip this warning in gc-only mode.
279506f32e7eSjoerg if (getLangOpts().getGC() != LangOptions::GCOnly)
279606f32e7eSjoerg Diag(Loc, diag::warn_objc_property_no_assignment_attribute);
279706f32e7eSjoerg
279806f32e7eSjoerg // If non-gc code warn that this is likely inappropriate.
279906f32e7eSjoerg if (getLangOpts().getGC() == LangOptions::NonGC)
280006f32e7eSjoerg Diag(Loc, diag::warn_objc_property_default_assign_on_object);
280106f32e7eSjoerg }
280206f32e7eSjoerg }
280306f32e7eSjoerg
280406f32e7eSjoerg // FIXME: Implement warning dependent on NSCopying being
280506f32e7eSjoerg // implemented. See also:
280606f32e7eSjoerg // <rdar://5168496&4855821&5607453&5096644&4947311&5698469&4947014&5168496>
280706f32e7eSjoerg // (please trim this list while you are at it).
280806f32e7eSjoerg }
280906f32e7eSjoerg
2810*13fbcb42Sjoerg if (!(Attributes & ObjCPropertyAttribute::kind_copy) &&
2811*13fbcb42Sjoerg !(Attributes & ObjCPropertyAttribute::kind_readonly) &&
2812*13fbcb42Sjoerg getLangOpts().getGC() == LangOptions::GCOnly &&
2813*13fbcb42Sjoerg PropertyTy->isBlockPointerType())
281406f32e7eSjoerg Diag(Loc, diag::warn_objc_property_copy_missing_on_block);
2815*13fbcb42Sjoerg else if ((Attributes & ObjCPropertyAttribute::kind_retain) &&
2816*13fbcb42Sjoerg !(Attributes & ObjCPropertyAttribute::kind_readonly) &&
2817*13fbcb42Sjoerg !(Attributes & ObjCPropertyAttribute::kind_strong) &&
281806f32e7eSjoerg PropertyTy->isBlockPointerType())
281906f32e7eSjoerg Diag(Loc, diag::warn_objc_property_retain_of_block);
282006f32e7eSjoerg
2821*13fbcb42Sjoerg if ((Attributes & ObjCPropertyAttribute::kind_readonly) &&
2822*13fbcb42Sjoerg (Attributes & ObjCPropertyAttribute::kind_setter))
282306f32e7eSjoerg Diag(Loc, diag::warn_objc_readonly_property_has_setter);
282406f32e7eSjoerg }
2825