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