10b57cec5SDimitry Andric //===--- SemaObjCProperty.cpp - Semantic Analysis for ObjC @property ------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements semantic analysis for Objective C @property and
100b57cec5SDimitry Andric // @synthesize declarations.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "clang/AST/ASTMutationListener.h"
150b57cec5SDimitry Andric #include "clang/AST/DeclObjC.h"
160b57cec5SDimitry Andric #include "clang/AST/ExprCXX.h"
170b57cec5SDimitry Andric #include "clang/AST/ExprObjC.h"
180b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h"
190b57cec5SDimitry Andric #include "clang/Lex/Lexer.h"
200b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h"
210b57cec5SDimitry Andric #include "clang/Sema/Initialization.h"
22*0fca6ea1SDimitry Andric #include "clang/Sema/SemaInternal.h"
23*0fca6ea1SDimitry Andric #include "clang/Sema/SemaObjC.h"
240b57cec5SDimitry Andric #include "llvm/ADT/DenseSet.h"
250b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
260b57cec5SDimitry Andric
270b57cec5SDimitry Andric using namespace clang;
280b57cec5SDimitry Andric
290b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
300b57cec5SDimitry Andric // Grammar actions.
310b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
320b57cec5SDimitry Andric
330b57cec5SDimitry Andric /// getImpliedARCOwnership - Given a set of property attributes and a
340b57cec5SDimitry Andric /// type, infer an expected lifetime. The type's ownership qualification
350b57cec5SDimitry Andric /// is not considered.
360b57cec5SDimitry Andric ///
370b57cec5SDimitry Andric /// Returns OCL_None if the attributes as stated do not imply an ownership.
380b57cec5SDimitry Andric /// Never returns OCL_Autoreleasing.
395ffd83dbSDimitry Andric static Qualifiers::ObjCLifetime
getImpliedARCOwnership(ObjCPropertyAttribute::Kind attrs,QualType type)405ffd83dbSDimitry Andric getImpliedARCOwnership(ObjCPropertyAttribute::Kind attrs, QualType type) {
410b57cec5SDimitry Andric // retain, strong, copy, weak, and unsafe_unretained are only legal
420b57cec5SDimitry Andric // on properties of retainable pointer type.
435ffd83dbSDimitry Andric if (attrs &
445ffd83dbSDimitry Andric (ObjCPropertyAttribute::kind_retain | ObjCPropertyAttribute::kind_strong |
455ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_copy)) {
460b57cec5SDimitry Andric return Qualifiers::OCL_Strong;
475ffd83dbSDimitry Andric } else if (attrs & ObjCPropertyAttribute::kind_weak) {
480b57cec5SDimitry Andric return Qualifiers::OCL_Weak;
495ffd83dbSDimitry Andric } else if (attrs & ObjCPropertyAttribute::kind_unsafe_unretained) {
500b57cec5SDimitry Andric return Qualifiers::OCL_ExplicitNone;
510b57cec5SDimitry Andric }
520b57cec5SDimitry Andric
530b57cec5SDimitry Andric // assign can appear on other types, so we have to check the
540b57cec5SDimitry Andric // property type.
555ffd83dbSDimitry Andric if (attrs & ObjCPropertyAttribute::kind_assign &&
560b57cec5SDimitry Andric type->isObjCRetainableType()) {
570b57cec5SDimitry Andric return Qualifiers::OCL_ExplicitNone;
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric
600b57cec5SDimitry Andric return Qualifiers::OCL_None;
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric
630b57cec5SDimitry Andric /// Check the internal consistency of a property declaration with
640b57cec5SDimitry Andric /// an explicit ownership qualifier.
checkPropertyDeclWithOwnership(Sema & S,ObjCPropertyDecl * property)650b57cec5SDimitry Andric static void checkPropertyDeclWithOwnership(Sema &S,
660b57cec5SDimitry Andric ObjCPropertyDecl *property) {
670b57cec5SDimitry Andric if (property->isInvalidDecl()) return;
680b57cec5SDimitry Andric
695ffd83dbSDimitry Andric ObjCPropertyAttribute::Kind propertyKind = property->getPropertyAttributes();
700b57cec5SDimitry Andric Qualifiers::ObjCLifetime propertyLifetime
710b57cec5SDimitry Andric = property->getType().getObjCLifetime();
720b57cec5SDimitry Andric
730b57cec5SDimitry Andric assert(propertyLifetime != Qualifiers::OCL_None);
740b57cec5SDimitry Andric
750b57cec5SDimitry Andric Qualifiers::ObjCLifetime expectedLifetime
760b57cec5SDimitry Andric = getImpliedARCOwnership(propertyKind, property->getType());
770b57cec5SDimitry Andric if (!expectedLifetime) {
780b57cec5SDimitry Andric // We have a lifetime qualifier but no dominating property
790b57cec5SDimitry Andric // attribute. That's okay, but restore reasonable invariants by
800b57cec5SDimitry Andric // setting the property attribute according to the lifetime
810b57cec5SDimitry Andric // qualifier.
825ffd83dbSDimitry Andric ObjCPropertyAttribute::Kind attr;
830b57cec5SDimitry Andric if (propertyLifetime == Qualifiers::OCL_Strong) {
845ffd83dbSDimitry Andric attr = ObjCPropertyAttribute::kind_strong;
850b57cec5SDimitry Andric } else if (propertyLifetime == Qualifiers::OCL_Weak) {
865ffd83dbSDimitry Andric attr = ObjCPropertyAttribute::kind_weak;
870b57cec5SDimitry Andric } else {
880b57cec5SDimitry Andric assert(propertyLifetime == Qualifiers::OCL_ExplicitNone);
895ffd83dbSDimitry Andric attr = ObjCPropertyAttribute::kind_unsafe_unretained;
900b57cec5SDimitry Andric }
910b57cec5SDimitry Andric property->setPropertyAttributes(attr);
920b57cec5SDimitry Andric return;
930b57cec5SDimitry Andric }
940b57cec5SDimitry Andric
950b57cec5SDimitry Andric if (propertyLifetime == expectedLifetime) return;
960b57cec5SDimitry Andric
970b57cec5SDimitry Andric property->setInvalidDecl();
980b57cec5SDimitry Andric S.Diag(property->getLocation(),
990b57cec5SDimitry Andric diag::err_arc_inconsistent_property_ownership)
1000b57cec5SDimitry Andric << property->getDeclName()
1010b57cec5SDimitry Andric << expectedLifetime
1020b57cec5SDimitry Andric << propertyLifetime;
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric
1050b57cec5SDimitry Andric /// Check this Objective-C property against a property declared in the
1060b57cec5SDimitry Andric /// given protocol.
1070b57cec5SDimitry Andric static void
CheckPropertyAgainstProtocol(Sema & S,ObjCPropertyDecl * Prop,ObjCProtocolDecl * Proto,llvm::SmallPtrSetImpl<ObjCProtocolDecl * > & Known)1080b57cec5SDimitry Andric CheckPropertyAgainstProtocol(Sema &S, ObjCPropertyDecl *Prop,
1090b57cec5SDimitry Andric ObjCProtocolDecl *Proto,
1100b57cec5SDimitry Andric llvm::SmallPtrSetImpl<ObjCProtocolDecl *> &Known) {
1110b57cec5SDimitry Andric // Have we seen this protocol before?
1120b57cec5SDimitry Andric if (!Known.insert(Proto).second)
1130b57cec5SDimitry Andric return;
1140b57cec5SDimitry Andric
1150b57cec5SDimitry Andric // Look for a property with the same name.
11604eeddc0SDimitry Andric if (ObjCPropertyDecl *ProtoProp = Proto->getProperty(
11704eeddc0SDimitry Andric Prop->getIdentifier(), Prop->isInstanceProperty())) {
118*0fca6ea1SDimitry Andric S.ObjC().DiagnosePropertyMismatch(Prop, ProtoProp, Proto->getIdentifier(),
119*0fca6ea1SDimitry Andric true);
1200b57cec5SDimitry Andric return;
1210b57cec5SDimitry Andric }
1220b57cec5SDimitry Andric
1230b57cec5SDimitry Andric // Check this property against any protocols we inherit.
1240b57cec5SDimitry Andric for (auto *P : Proto->protocols())
1250b57cec5SDimitry Andric CheckPropertyAgainstProtocol(S, Prop, P, Known);
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric
deducePropertyOwnershipFromType(Sema & S,QualType T)1280b57cec5SDimitry Andric static unsigned deducePropertyOwnershipFromType(Sema &S, QualType T) {
1290b57cec5SDimitry Andric // In GC mode, just look for the __weak qualifier.
1300b57cec5SDimitry Andric if (S.getLangOpts().getGC() != LangOptions::NonGC) {
1315ffd83dbSDimitry Andric if (T.isObjCGCWeak())
1325ffd83dbSDimitry Andric return ObjCPropertyAttribute::kind_weak;
1330b57cec5SDimitry Andric
1340b57cec5SDimitry Andric // In ARC/MRC, look for an explicit ownership qualifier.
1350b57cec5SDimitry Andric // For some reason, this only applies to __weak.
1360b57cec5SDimitry Andric } else if (auto ownership = T.getObjCLifetime()) {
1370b57cec5SDimitry Andric switch (ownership) {
1380b57cec5SDimitry Andric case Qualifiers::OCL_Weak:
1395ffd83dbSDimitry Andric return ObjCPropertyAttribute::kind_weak;
1400b57cec5SDimitry Andric case Qualifiers::OCL_Strong:
1415ffd83dbSDimitry Andric return ObjCPropertyAttribute::kind_strong;
1420b57cec5SDimitry Andric case Qualifiers::OCL_ExplicitNone:
1435ffd83dbSDimitry Andric return ObjCPropertyAttribute::kind_unsafe_unretained;
1440b57cec5SDimitry Andric case Qualifiers::OCL_Autoreleasing:
1450b57cec5SDimitry Andric case Qualifiers::OCL_None:
1460b57cec5SDimitry Andric return 0;
1470b57cec5SDimitry Andric }
1480b57cec5SDimitry Andric llvm_unreachable("bad qualifier");
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric
1510b57cec5SDimitry Andric return 0;
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric
1540b57cec5SDimitry Andric static const unsigned OwnershipMask =
1555ffd83dbSDimitry Andric (ObjCPropertyAttribute::kind_assign | ObjCPropertyAttribute::kind_retain |
1565ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_copy | ObjCPropertyAttribute::kind_weak |
1575ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_strong |
1585ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_unsafe_unretained);
1590b57cec5SDimitry Andric
getOwnershipRule(unsigned attr)1600b57cec5SDimitry Andric static unsigned getOwnershipRule(unsigned attr) {
1610b57cec5SDimitry Andric unsigned result = attr & OwnershipMask;
1620b57cec5SDimitry Andric
1630b57cec5SDimitry Andric // From an ownership perspective, assign and unsafe_unretained are
1640b57cec5SDimitry Andric // identical; make sure one also implies the other.
1655ffd83dbSDimitry Andric if (result & (ObjCPropertyAttribute::kind_assign |
1665ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_unsafe_unretained)) {
1675ffd83dbSDimitry Andric result |= ObjCPropertyAttribute::kind_assign |
1685ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_unsafe_unretained;
1690b57cec5SDimitry Andric }
1700b57cec5SDimitry Andric
1710b57cec5SDimitry Andric return result;
1720b57cec5SDimitry Andric }
1730b57cec5SDimitry Andric
ActOnProperty(Scope * S,SourceLocation AtLoc,SourceLocation LParenLoc,FieldDeclarator & FD,ObjCDeclSpec & ODS,Selector GetterSel,Selector SetterSel,tok::ObjCKeywordKind MethodImplKind,DeclContext * lexicalDC)174*0fca6ea1SDimitry Andric Decl *SemaObjC::ActOnProperty(Scope *S, SourceLocation AtLoc,
175*0fca6ea1SDimitry Andric SourceLocation LParenLoc, FieldDeclarator &FD,
176*0fca6ea1SDimitry Andric ObjCDeclSpec &ODS, Selector GetterSel,
1770b57cec5SDimitry Andric Selector SetterSel,
1780b57cec5SDimitry Andric tok::ObjCKeywordKind MethodImplKind,
1790b57cec5SDimitry Andric DeclContext *lexicalDC) {
1800b57cec5SDimitry Andric unsigned Attributes = ODS.getPropertyAttributes();
1815ffd83dbSDimitry Andric FD.D.setObjCWeakProperty((Attributes & ObjCPropertyAttribute::kind_weak) !=
1825ffd83dbSDimitry Andric 0);
183*0fca6ea1SDimitry Andric TypeSourceInfo *TSI = SemaRef.GetTypeForDeclarator(FD.D);
1840b57cec5SDimitry Andric QualType T = TSI->getType();
1850b57cec5SDimitry Andric if (!getOwnershipRule(Attributes)) {
186*0fca6ea1SDimitry Andric Attributes |= deducePropertyOwnershipFromType(SemaRef, T);
1870b57cec5SDimitry Andric }
1885ffd83dbSDimitry Andric bool isReadWrite = ((Attributes & ObjCPropertyAttribute::kind_readwrite) ||
1890b57cec5SDimitry Andric // default is readwrite!
1905ffd83dbSDimitry Andric !(Attributes & ObjCPropertyAttribute::kind_readonly));
1910b57cec5SDimitry Andric
1920b57cec5SDimitry Andric // Proceed with constructing the ObjCPropertyDecls.
193*0fca6ea1SDimitry Andric ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(SemaRef.CurContext);
1940b57cec5SDimitry Andric ObjCPropertyDecl *Res = nullptr;
1950b57cec5SDimitry Andric if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
1960b57cec5SDimitry Andric if (CDecl->IsClassExtension()) {
1970b57cec5SDimitry Andric Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc,
1980b57cec5SDimitry Andric FD,
1990b57cec5SDimitry Andric GetterSel, ODS.getGetterNameLoc(),
2000b57cec5SDimitry Andric SetterSel, ODS.getSetterNameLoc(),
2010b57cec5SDimitry Andric isReadWrite, Attributes,
2020b57cec5SDimitry Andric ODS.getPropertyAttributes(),
2030b57cec5SDimitry Andric T, TSI, MethodImplKind);
2040b57cec5SDimitry Andric if (!Res)
2050b57cec5SDimitry Andric return nullptr;
2060b57cec5SDimitry Andric }
2070b57cec5SDimitry Andric }
2080b57cec5SDimitry Andric
2090b57cec5SDimitry Andric if (!Res) {
2100b57cec5SDimitry Andric Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD,
2110b57cec5SDimitry Andric GetterSel, ODS.getGetterNameLoc(), SetterSel,
2120b57cec5SDimitry Andric ODS.getSetterNameLoc(), isReadWrite, Attributes,
2130b57cec5SDimitry Andric ODS.getPropertyAttributes(), T, TSI,
2140b57cec5SDimitry Andric MethodImplKind);
2150b57cec5SDimitry Andric if (lexicalDC)
2160b57cec5SDimitry Andric Res->setLexicalDeclContext(lexicalDC);
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric
2190b57cec5SDimitry Andric // Validate the attributes on the @property.
2200b57cec5SDimitry Andric CheckObjCPropertyAttributes(Res, AtLoc, Attributes,
2210b57cec5SDimitry Andric (isa<ObjCInterfaceDecl>(ClassDecl) ||
2220b57cec5SDimitry Andric isa<ObjCProtocolDecl>(ClassDecl)));
2230b57cec5SDimitry Andric
2240b57cec5SDimitry Andric // Check consistency if the type has explicit ownership qualification.
2250b57cec5SDimitry Andric if (Res->getType().getObjCLifetime())
226*0fca6ea1SDimitry Andric checkPropertyDeclWithOwnership(SemaRef, Res);
2270b57cec5SDimitry Andric
2280b57cec5SDimitry Andric llvm::SmallPtrSet<ObjCProtocolDecl *, 16> KnownProtos;
2290b57cec5SDimitry Andric if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
2300b57cec5SDimitry Andric // For a class, compare the property against a property in our superclass.
2310b57cec5SDimitry Andric bool FoundInSuper = false;
2320b57cec5SDimitry Andric ObjCInterfaceDecl *CurrentInterfaceDecl = IFace;
2330b57cec5SDimitry Andric while (ObjCInterfaceDecl *Super = CurrentInterfaceDecl->getSuperClass()) {
23404eeddc0SDimitry Andric if (ObjCPropertyDecl *SuperProp = Super->getProperty(
23504eeddc0SDimitry Andric Res->getIdentifier(), Res->isInstanceProperty())) {
2360b57cec5SDimitry Andric DiagnosePropertyMismatch(Res, SuperProp, Super->getIdentifier(), false);
2370b57cec5SDimitry Andric FoundInSuper = true;
2380b57cec5SDimitry Andric break;
2390b57cec5SDimitry Andric }
2400b57cec5SDimitry Andric CurrentInterfaceDecl = Super;
2410b57cec5SDimitry Andric }
2420b57cec5SDimitry Andric
2430b57cec5SDimitry Andric if (FoundInSuper) {
2440b57cec5SDimitry Andric // Also compare the property against a property in our protocols.
2450b57cec5SDimitry Andric for (auto *P : CurrentInterfaceDecl->protocols()) {
246*0fca6ea1SDimitry Andric CheckPropertyAgainstProtocol(SemaRef, Res, P, KnownProtos);
2470b57cec5SDimitry Andric }
2480b57cec5SDimitry Andric } else {
2490b57cec5SDimitry Andric // Slower path: look in all protocols we referenced.
2500b57cec5SDimitry Andric for (auto *P : IFace->all_referenced_protocols()) {
251*0fca6ea1SDimitry Andric CheckPropertyAgainstProtocol(SemaRef, Res, P, KnownProtos);
2520b57cec5SDimitry Andric }
2530b57cec5SDimitry Andric }
2540b57cec5SDimitry Andric } else if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
2550b57cec5SDimitry Andric // We don't check if class extension. Because properties in class extension
2560b57cec5SDimitry Andric // are meant to override some of the attributes and checking has already done
2570b57cec5SDimitry Andric // when property in class extension is constructed.
2580b57cec5SDimitry Andric if (!Cat->IsClassExtension())
2590b57cec5SDimitry Andric for (auto *P : Cat->protocols())
260*0fca6ea1SDimitry Andric CheckPropertyAgainstProtocol(SemaRef, Res, P, KnownProtos);
2610b57cec5SDimitry Andric } else {
2620b57cec5SDimitry Andric ObjCProtocolDecl *Proto = cast<ObjCProtocolDecl>(ClassDecl);
2630b57cec5SDimitry Andric for (auto *P : Proto->protocols())
264*0fca6ea1SDimitry Andric CheckPropertyAgainstProtocol(SemaRef, Res, P, KnownProtos);
2650b57cec5SDimitry Andric }
2660b57cec5SDimitry Andric
267*0fca6ea1SDimitry Andric SemaRef.ActOnDocumentableDecl(Res);
2680b57cec5SDimitry Andric return Res;
2690b57cec5SDimitry Andric }
2700b57cec5SDimitry Andric
2715ffd83dbSDimitry Andric static ObjCPropertyAttribute::Kind
makePropertyAttributesAsWritten(unsigned Attributes)2720b57cec5SDimitry Andric makePropertyAttributesAsWritten(unsigned Attributes) {
2730b57cec5SDimitry Andric unsigned attributesAsWritten = 0;
2745ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_readonly)
2755ffd83dbSDimitry Andric attributesAsWritten |= ObjCPropertyAttribute::kind_readonly;
2765ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_readwrite)
2775ffd83dbSDimitry Andric attributesAsWritten |= ObjCPropertyAttribute::kind_readwrite;
2785ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_getter)
2795ffd83dbSDimitry Andric attributesAsWritten |= ObjCPropertyAttribute::kind_getter;
2805ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_setter)
2815ffd83dbSDimitry Andric attributesAsWritten |= ObjCPropertyAttribute::kind_setter;
2825ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_assign)
2835ffd83dbSDimitry Andric attributesAsWritten |= ObjCPropertyAttribute::kind_assign;
2845ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_retain)
2855ffd83dbSDimitry Andric attributesAsWritten |= ObjCPropertyAttribute::kind_retain;
2865ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_strong)
2875ffd83dbSDimitry Andric attributesAsWritten |= ObjCPropertyAttribute::kind_strong;
2885ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_weak)
2895ffd83dbSDimitry Andric attributesAsWritten |= ObjCPropertyAttribute::kind_weak;
2905ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_copy)
2915ffd83dbSDimitry Andric attributesAsWritten |= ObjCPropertyAttribute::kind_copy;
2925ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained)
2935ffd83dbSDimitry Andric attributesAsWritten |= ObjCPropertyAttribute::kind_unsafe_unretained;
2945ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_nonatomic)
2955ffd83dbSDimitry Andric attributesAsWritten |= ObjCPropertyAttribute::kind_nonatomic;
2965ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_atomic)
2975ffd83dbSDimitry Andric attributesAsWritten |= ObjCPropertyAttribute::kind_atomic;
2985ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_class)
2995ffd83dbSDimitry Andric attributesAsWritten |= ObjCPropertyAttribute::kind_class;
3005ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_direct)
3015ffd83dbSDimitry Andric attributesAsWritten |= ObjCPropertyAttribute::kind_direct;
3020b57cec5SDimitry Andric
3035ffd83dbSDimitry Andric return (ObjCPropertyAttribute::Kind)attributesAsWritten;
3040b57cec5SDimitry Andric }
3050b57cec5SDimitry Andric
LocPropertyAttribute(ASTContext & Context,const char * attrName,SourceLocation LParenLoc,SourceLocation & Loc)3060b57cec5SDimitry Andric static bool LocPropertyAttribute( ASTContext &Context, const char *attrName,
3070b57cec5SDimitry Andric SourceLocation LParenLoc, SourceLocation &Loc) {
3080b57cec5SDimitry Andric if (LParenLoc.isMacroID())
3090b57cec5SDimitry Andric return false;
3100b57cec5SDimitry Andric
3110b57cec5SDimitry Andric SourceManager &SM = Context.getSourceManager();
3120b57cec5SDimitry Andric std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(LParenLoc);
3130b57cec5SDimitry Andric // Try to load the file buffer.
3140b57cec5SDimitry Andric bool invalidTemp = false;
3150b57cec5SDimitry Andric StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
3160b57cec5SDimitry Andric if (invalidTemp)
3170b57cec5SDimitry Andric return false;
3180b57cec5SDimitry Andric const char *tokenBegin = file.data() + locInfo.second;
3190b57cec5SDimitry Andric
3200b57cec5SDimitry Andric // Lex from the start of the given location.
3210b57cec5SDimitry Andric Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
3220b57cec5SDimitry Andric Context.getLangOpts(),
3230b57cec5SDimitry Andric file.begin(), tokenBegin, file.end());
3240b57cec5SDimitry Andric Token Tok;
3250b57cec5SDimitry Andric do {
3260b57cec5SDimitry Andric lexer.LexFromRawLexer(Tok);
3270b57cec5SDimitry Andric if (Tok.is(tok::raw_identifier) && Tok.getRawIdentifier() == attrName) {
3280b57cec5SDimitry Andric Loc = Tok.getLocation();
3290b57cec5SDimitry Andric return true;
3300b57cec5SDimitry Andric }
3310b57cec5SDimitry Andric } while (Tok.isNot(tok::r_paren));
3320b57cec5SDimitry Andric return false;
3330b57cec5SDimitry Andric }
3340b57cec5SDimitry Andric
3350b57cec5SDimitry Andric /// Check for a mismatch in the atomicity of the given properties.
checkAtomicPropertyMismatch(Sema & S,ObjCPropertyDecl * OldProperty,ObjCPropertyDecl * NewProperty,bool PropagateAtomicity)3360b57cec5SDimitry Andric static void checkAtomicPropertyMismatch(Sema &S,
3370b57cec5SDimitry Andric ObjCPropertyDecl *OldProperty,
3380b57cec5SDimitry Andric ObjCPropertyDecl *NewProperty,
3390b57cec5SDimitry Andric bool PropagateAtomicity) {
3400b57cec5SDimitry Andric // If the atomicity of both matches, we're done.
3415ffd83dbSDimitry Andric bool OldIsAtomic = (OldProperty->getPropertyAttributes() &
3425ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_nonatomic) == 0;
3435ffd83dbSDimitry Andric bool NewIsAtomic = (NewProperty->getPropertyAttributes() &
3445ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_nonatomic) == 0;
3450b57cec5SDimitry Andric if (OldIsAtomic == NewIsAtomic) return;
3460b57cec5SDimitry Andric
3470b57cec5SDimitry Andric // Determine whether the given property is readonly and implicitly
3480b57cec5SDimitry Andric // atomic.
3490b57cec5SDimitry Andric auto isImplicitlyReadonlyAtomic = [](ObjCPropertyDecl *Property) -> bool {
3500b57cec5SDimitry Andric // Is it readonly?
3510b57cec5SDimitry Andric auto Attrs = Property->getPropertyAttributes();
3525ffd83dbSDimitry Andric if ((Attrs & ObjCPropertyAttribute::kind_readonly) == 0)
3535ffd83dbSDimitry Andric return false;
3540b57cec5SDimitry Andric
3550b57cec5SDimitry Andric // Is it nonatomic?
3565ffd83dbSDimitry Andric if (Attrs & ObjCPropertyAttribute::kind_nonatomic)
3575ffd83dbSDimitry Andric return false;
3580b57cec5SDimitry Andric
3590b57cec5SDimitry Andric // Was 'atomic' specified directly?
3600b57cec5SDimitry Andric if (Property->getPropertyAttributesAsWritten() &
3615ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_atomic)
3620b57cec5SDimitry Andric return false;
3630b57cec5SDimitry Andric
3640b57cec5SDimitry Andric return true;
3650b57cec5SDimitry Andric };
3660b57cec5SDimitry Andric
3670b57cec5SDimitry Andric // If we're allowed to propagate atomicity, and the new property did
3680b57cec5SDimitry Andric // not specify atomicity at all, propagate.
3695ffd83dbSDimitry Andric const unsigned AtomicityMask = (ObjCPropertyAttribute::kind_atomic |
3705ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_nonatomic);
3710b57cec5SDimitry Andric if (PropagateAtomicity &&
3720b57cec5SDimitry Andric ((NewProperty->getPropertyAttributesAsWritten() & AtomicityMask) == 0)) {
3730b57cec5SDimitry Andric unsigned Attrs = NewProperty->getPropertyAttributes();
3740b57cec5SDimitry Andric Attrs = Attrs & ~AtomicityMask;
3750b57cec5SDimitry Andric if (OldIsAtomic)
3765ffd83dbSDimitry Andric Attrs |= ObjCPropertyAttribute::kind_atomic;
3770b57cec5SDimitry Andric else
3785ffd83dbSDimitry Andric Attrs |= ObjCPropertyAttribute::kind_nonatomic;
3790b57cec5SDimitry Andric
3800b57cec5SDimitry Andric NewProperty->overwritePropertyAttributes(Attrs);
3810b57cec5SDimitry Andric return;
3820b57cec5SDimitry Andric }
3830b57cec5SDimitry Andric
3840b57cec5SDimitry Andric // One of the properties is atomic; if it's a readonly property, and
3850b57cec5SDimitry Andric // 'atomic' wasn't explicitly specified, we're okay.
3860b57cec5SDimitry Andric if ((OldIsAtomic && isImplicitlyReadonlyAtomic(OldProperty)) ||
3870b57cec5SDimitry Andric (NewIsAtomic && isImplicitlyReadonlyAtomic(NewProperty)))
3880b57cec5SDimitry Andric return;
3890b57cec5SDimitry Andric
3900b57cec5SDimitry Andric // Diagnose the conflict.
3910b57cec5SDimitry Andric const IdentifierInfo *OldContextName;
3920b57cec5SDimitry Andric auto *OldDC = OldProperty->getDeclContext();
3930b57cec5SDimitry Andric if (auto Category = dyn_cast<ObjCCategoryDecl>(OldDC))
3940b57cec5SDimitry Andric OldContextName = Category->getClassInterface()->getIdentifier();
3950b57cec5SDimitry Andric else
3960b57cec5SDimitry Andric OldContextName = cast<ObjCContainerDecl>(OldDC)->getIdentifier();
3970b57cec5SDimitry Andric
3980b57cec5SDimitry Andric S.Diag(NewProperty->getLocation(), diag::warn_property_attribute)
3990b57cec5SDimitry Andric << NewProperty->getDeclName() << "atomic"
4000b57cec5SDimitry Andric << OldContextName;
4010b57cec5SDimitry Andric S.Diag(OldProperty->getLocation(), diag::note_property_declare);
4020b57cec5SDimitry Andric }
4030b57cec5SDimitry Andric
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)404*0fca6ea1SDimitry Andric ObjCPropertyDecl *SemaObjC::HandlePropertyInClassExtension(
405*0fca6ea1SDimitry Andric Scope *S, SourceLocation AtLoc, SourceLocation LParenLoc,
406*0fca6ea1SDimitry Andric FieldDeclarator &FD, Selector GetterSel, SourceLocation GetterNameLoc,
407*0fca6ea1SDimitry Andric Selector SetterSel, SourceLocation SetterNameLoc, const bool isReadWrite,
408*0fca6ea1SDimitry Andric unsigned &Attributes, const unsigned AttributesAsWritten, QualType T,
409*0fca6ea1SDimitry Andric TypeSourceInfo *TSI, tok::ObjCKeywordKind MethodImplKind) {
410*0fca6ea1SDimitry Andric ObjCCategoryDecl *CDecl = cast<ObjCCategoryDecl>(SemaRef.CurContext);
4110b57cec5SDimitry Andric // Diagnose if this property is already in continuation class.
412*0fca6ea1SDimitry Andric DeclContext *DC = SemaRef.CurContext;
413*0fca6ea1SDimitry Andric const IdentifierInfo *PropertyId = FD.D.getIdentifier();
4140b57cec5SDimitry Andric ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface();
4150b57cec5SDimitry Andric
4160b57cec5SDimitry Andric // We need to look in the @interface to see if the @property was
4170b57cec5SDimitry Andric // already declared.
4180b57cec5SDimitry Andric if (!CCPrimary) {
4190b57cec5SDimitry Andric Diag(CDecl->getLocation(), diag::err_continuation_class);
4200b57cec5SDimitry Andric return nullptr;
4210b57cec5SDimitry Andric }
4220b57cec5SDimitry Andric
4235ffd83dbSDimitry Andric bool isClassProperty =
4245ffd83dbSDimitry Andric (AttributesAsWritten & ObjCPropertyAttribute::kind_class) ||
4255ffd83dbSDimitry Andric (Attributes & ObjCPropertyAttribute::kind_class);
4260b57cec5SDimitry Andric
4270b57cec5SDimitry Andric // Find the property in the extended class's primary class or
4280b57cec5SDimitry Andric // extensions.
4290b57cec5SDimitry Andric ObjCPropertyDecl *PIDecl = CCPrimary->FindPropertyVisibleInPrimaryClass(
4300b57cec5SDimitry Andric PropertyId, ObjCPropertyDecl::getQueryKind(isClassProperty));
4310b57cec5SDimitry Andric
4320b57cec5SDimitry Andric // If we found a property in an extension, complain.
4330b57cec5SDimitry Andric if (PIDecl && isa<ObjCCategoryDecl>(PIDecl->getDeclContext())) {
4340b57cec5SDimitry Andric Diag(AtLoc, diag::err_duplicate_property);
4350b57cec5SDimitry Andric Diag(PIDecl->getLocation(), diag::note_property_declare);
4360b57cec5SDimitry Andric return nullptr;
4370b57cec5SDimitry Andric }
4380b57cec5SDimitry Andric
4390b57cec5SDimitry Andric // Check for consistency with the previous declaration, if there is one.
4400b57cec5SDimitry Andric if (PIDecl) {
4410b57cec5SDimitry Andric // A readonly property declared in the primary class can be refined
4420b57cec5SDimitry Andric // by adding a readwrite property within an extension.
4430b57cec5SDimitry Andric // Anything else is an error.
4440b57cec5SDimitry Andric if (!(PIDecl->isReadOnly() && isReadWrite)) {
4450b57cec5SDimitry Andric // Tailor the diagnostics for the common case where a readwrite
4460b57cec5SDimitry Andric // property is declared both in the @interface and the continuation.
4470b57cec5SDimitry Andric // This is a common error where the user often intended the original
4480b57cec5SDimitry Andric // declaration to be readonly.
4490b57cec5SDimitry Andric unsigned diag =
4505ffd83dbSDimitry Andric (Attributes & ObjCPropertyAttribute::kind_readwrite) &&
4510b57cec5SDimitry Andric (PIDecl->getPropertyAttributesAsWritten() &
4525ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_readwrite)
4530b57cec5SDimitry Andric ? diag::err_use_continuation_class_redeclaration_readwrite
4540b57cec5SDimitry Andric : diag::err_use_continuation_class;
4550b57cec5SDimitry Andric Diag(AtLoc, diag)
4560b57cec5SDimitry Andric << CCPrimary->getDeclName();
4570b57cec5SDimitry Andric Diag(PIDecl->getLocation(), diag::note_property_declare);
4580b57cec5SDimitry Andric return nullptr;
4590b57cec5SDimitry Andric }
4600b57cec5SDimitry Andric
4610b57cec5SDimitry Andric // Check for consistency of getters.
4620b57cec5SDimitry Andric if (PIDecl->getGetterName() != GetterSel) {
4630b57cec5SDimitry Andric // If the getter was written explicitly, complain.
4645ffd83dbSDimitry Andric if (AttributesAsWritten & ObjCPropertyAttribute::kind_getter) {
4650b57cec5SDimitry Andric Diag(AtLoc, diag::warn_property_redecl_getter_mismatch)
4660b57cec5SDimitry Andric << PIDecl->getGetterName() << GetterSel;
4670b57cec5SDimitry Andric Diag(PIDecl->getLocation(), diag::note_property_declare);
4680b57cec5SDimitry Andric }
4690b57cec5SDimitry Andric
4700b57cec5SDimitry Andric // Always adopt the getter from the original declaration.
4710b57cec5SDimitry Andric GetterSel = PIDecl->getGetterName();
4725ffd83dbSDimitry Andric Attributes |= ObjCPropertyAttribute::kind_getter;
4730b57cec5SDimitry Andric }
4740b57cec5SDimitry Andric
4750b57cec5SDimitry Andric // Check consistency of ownership.
4760b57cec5SDimitry Andric unsigned ExistingOwnership
4770b57cec5SDimitry Andric = getOwnershipRule(PIDecl->getPropertyAttributes());
4780b57cec5SDimitry Andric unsigned NewOwnership = getOwnershipRule(Attributes);
4790b57cec5SDimitry Andric if (ExistingOwnership && NewOwnership != ExistingOwnership) {
4800b57cec5SDimitry Andric // If the ownership was written explicitly, complain.
4810b57cec5SDimitry Andric if (getOwnershipRule(AttributesAsWritten)) {
4820b57cec5SDimitry Andric Diag(AtLoc, diag::warn_property_attr_mismatch);
4830b57cec5SDimitry Andric Diag(PIDecl->getLocation(), diag::note_property_declare);
4840b57cec5SDimitry Andric }
4850b57cec5SDimitry Andric
4860b57cec5SDimitry Andric // Take the ownership from the original property.
4870b57cec5SDimitry Andric Attributes = (Attributes & ~OwnershipMask) | ExistingOwnership;
4880b57cec5SDimitry Andric }
4890b57cec5SDimitry Andric
4900b57cec5SDimitry Andric // If the redeclaration is 'weak' but the original property is not,
4915ffd83dbSDimitry Andric if ((Attributes & ObjCPropertyAttribute::kind_weak) &&
4925ffd83dbSDimitry Andric !(PIDecl->getPropertyAttributesAsWritten() &
4935ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_weak) &&
4940b57cec5SDimitry Andric PIDecl->getType()->getAs<ObjCObjectPointerType>() &&
4950b57cec5SDimitry Andric PIDecl->getType().getObjCLifetime() == Qualifiers::OCL_None) {
4960b57cec5SDimitry Andric Diag(AtLoc, diag::warn_property_implicitly_mismatched);
4970b57cec5SDimitry Andric Diag(PIDecl->getLocation(), diag::note_property_declare);
4980b57cec5SDimitry Andric }
4990b57cec5SDimitry Andric }
5000b57cec5SDimitry Andric
5010b57cec5SDimitry Andric // Create a new ObjCPropertyDecl with the DeclContext being
5020b57cec5SDimitry Andric // the class extension.
5030b57cec5SDimitry Andric ObjCPropertyDecl *PDecl = CreatePropertyDecl(S, CDecl, AtLoc, LParenLoc,
5040b57cec5SDimitry Andric FD, GetterSel, GetterNameLoc,
5050b57cec5SDimitry Andric SetterSel, SetterNameLoc,
5060b57cec5SDimitry Andric isReadWrite,
5070b57cec5SDimitry Andric Attributes, AttributesAsWritten,
5080b57cec5SDimitry Andric T, TSI, MethodImplKind, DC);
509*0fca6ea1SDimitry Andric ASTContext &Context = getASTContext();
5100b57cec5SDimitry Andric // If there was no declaration of a property with the same name in
5110b57cec5SDimitry Andric // the primary class, we're done.
5120b57cec5SDimitry Andric if (!PIDecl) {
5130b57cec5SDimitry Andric ProcessPropertyDecl(PDecl);
5140b57cec5SDimitry Andric return PDecl;
5150b57cec5SDimitry Andric }
5160b57cec5SDimitry Andric
5170b57cec5SDimitry Andric if (!Context.hasSameType(PIDecl->getType(), PDecl->getType())) {
5180b57cec5SDimitry Andric bool IncompatibleObjC = false;
5190b57cec5SDimitry Andric QualType ConvertedType;
5200b57cec5SDimitry Andric // Relax the strict type matching for property type in continuation class.
5210b57cec5SDimitry Andric // Allow property object type of continuation class to be different as long
5220b57cec5SDimitry Andric // as it narrows the object type in its primary class property. Note that
5230b57cec5SDimitry Andric // this conversion is safe only because the wider type is for a 'readonly'
5240b57cec5SDimitry Andric // property in primary class and 'narrowed' type for a 'readwrite' property
5250b57cec5SDimitry Andric // in continuation class.
5260b57cec5SDimitry Andric QualType PrimaryClassPropertyT = Context.getCanonicalType(PIDecl->getType());
5270b57cec5SDimitry Andric QualType ClassExtPropertyT = Context.getCanonicalType(PDecl->getType());
5280b57cec5SDimitry Andric if (!isa<ObjCObjectPointerType>(PrimaryClassPropertyT) ||
5290b57cec5SDimitry Andric !isa<ObjCObjectPointerType>(ClassExtPropertyT) ||
530*0fca6ea1SDimitry Andric (!SemaRef.isObjCPointerConversion(ClassExtPropertyT,
531*0fca6ea1SDimitry Andric PrimaryClassPropertyT, ConvertedType,
532*0fca6ea1SDimitry Andric IncompatibleObjC)) ||
533*0fca6ea1SDimitry Andric IncompatibleObjC) {
5340b57cec5SDimitry Andric Diag(AtLoc,
5350b57cec5SDimitry Andric diag::err_type_mismatch_continuation_class) << PDecl->getType();
5360b57cec5SDimitry Andric Diag(PIDecl->getLocation(), diag::note_property_declare);
5370b57cec5SDimitry Andric return nullptr;
5380b57cec5SDimitry Andric }
5390b57cec5SDimitry Andric }
5400b57cec5SDimitry Andric
5410b57cec5SDimitry Andric // Check that atomicity of property in class extension matches the previous
5420b57cec5SDimitry Andric // declaration.
543*0fca6ea1SDimitry Andric checkAtomicPropertyMismatch(SemaRef, PIDecl, PDecl, true);
5440b57cec5SDimitry Andric
5450b57cec5SDimitry Andric // Make sure getter/setter are appropriately synthesized.
5460b57cec5SDimitry Andric ProcessPropertyDecl(PDecl);
5470b57cec5SDimitry Andric return PDecl;
5480b57cec5SDimitry Andric }
5490b57cec5SDimitry Andric
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)550*0fca6ea1SDimitry Andric ObjCPropertyDecl *SemaObjC::CreatePropertyDecl(
551*0fca6ea1SDimitry Andric Scope *S, ObjCContainerDecl *CDecl, SourceLocation AtLoc,
552*0fca6ea1SDimitry Andric SourceLocation LParenLoc, FieldDeclarator &FD, Selector GetterSel,
553*0fca6ea1SDimitry Andric SourceLocation GetterNameLoc, Selector SetterSel,
554*0fca6ea1SDimitry Andric SourceLocation SetterNameLoc, const bool isReadWrite,
555*0fca6ea1SDimitry Andric const unsigned Attributes, const unsigned AttributesAsWritten, QualType T,
556*0fca6ea1SDimitry Andric TypeSourceInfo *TInfo, tok::ObjCKeywordKind MethodImplKind,
5570b57cec5SDimitry Andric DeclContext *lexicalDC) {
558*0fca6ea1SDimitry Andric ASTContext &Context = getASTContext();
559*0fca6ea1SDimitry Andric const IdentifierInfo *PropertyId = FD.D.getIdentifier();
5600b57cec5SDimitry Andric
5610b57cec5SDimitry Andric // Property defaults to 'assign' if it is readwrite, unless this is ARC
5620b57cec5SDimitry Andric // and the type is retainable.
5630b57cec5SDimitry Andric bool isAssign;
5645ffd83dbSDimitry Andric if (Attributes & (ObjCPropertyAttribute::kind_assign |
5655ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_unsafe_unretained)) {
5660b57cec5SDimitry Andric isAssign = true;
5670b57cec5SDimitry Andric } else if (getOwnershipRule(Attributes) || !isReadWrite) {
5680b57cec5SDimitry Andric isAssign = false;
5690b57cec5SDimitry Andric } else {
5700b57cec5SDimitry Andric isAssign = (!getLangOpts().ObjCAutoRefCount ||
5710b57cec5SDimitry Andric !T->isObjCRetainableType());
5720b57cec5SDimitry Andric }
5730b57cec5SDimitry Andric
5740b57cec5SDimitry Andric // Issue a warning if property is 'assign' as default and its
5750b57cec5SDimitry Andric // object, which is gc'able conforms to NSCopying protocol
5765ffd83dbSDimitry Andric if (getLangOpts().getGC() != LangOptions::NonGC && isAssign &&
5775ffd83dbSDimitry Andric !(Attributes & ObjCPropertyAttribute::kind_assign)) {
5780b57cec5SDimitry Andric if (const ObjCObjectPointerType *ObjPtrTy =
5790b57cec5SDimitry Andric T->getAs<ObjCObjectPointerType>()) {
5800b57cec5SDimitry Andric ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
5810b57cec5SDimitry Andric if (IDecl)
5820b57cec5SDimitry Andric if (ObjCProtocolDecl* PNSCopying =
5830b57cec5SDimitry Andric LookupProtocol(&Context.Idents.get("NSCopying"), AtLoc))
5840b57cec5SDimitry Andric if (IDecl->ClassImplementsProtocol(PNSCopying, true))
5850b57cec5SDimitry Andric Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId;
5860b57cec5SDimitry Andric }
5870b57cec5SDimitry Andric }
5880b57cec5SDimitry Andric
5890b57cec5SDimitry Andric if (T->isObjCObjectType()) {
5900b57cec5SDimitry Andric SourceLocation StarLoc = TInfo->getTypeLoc().getEndLoc();
591*0fca6ea1SDimitry Andric StarLoc = SemaRef.getLocForEndOfToken(StarLoc);
5920b57cec5SDimitry Andric Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object)
5930b57cec5SDimitry Andric << FixItHint::CreateInsertion(StarLoc, "*");
5940b57cec5SDimitry Andric T = Context.getObjCObjectPointerType(T);
5950b57cec5SDimitry Andric SourceLocation TLoc = TInfo->getTypeLoc().getBeginLoc();
5960b57cec5SDimitry Andric TInfo = Context.getTrivialTypeSourceInfo(T, TLoc);
5970b57cec5SDimitry Andric }
5980b57cec5SDimitry Andric
5990b57cec5SDimitry Andric DeclContext *DC = CDecl;
6000b57cec5SDimitry Andric ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
6010b57cec5SDimitry Andric FD.D.getIdentifierLoc(),
6020b57cec5SDimitry Andric PropertyId, AtLoc,
6030b57cec5SDimitry Andric LParenLoc, T, TInfo);
6040b57cec5SDimitry Andric
6055ffd83dbSDimitry Andric bool isClassProperty =
6065ffd83dbSDimitry Andric (AttributesAsWritten & ObjCPropertyAttribute::kind_class) ||
6075ffd83dbSDimitry Andric (Attributes & ObjCPropertyAttribute::kind_class);
6080b57cec5SDimitry Andric // Class property and instance property can have the same name.
6090b57cec5SDimitry Andric if (ObjCPropertyDecl *prevDecl = ObjCPropertyDecl::findPropertyDecl(
6100b57cec5SDimitry Andric DC, PropertyId, ObjCPropertyDecl::getQueryKind(isClassProperty))) {
6110b57cec5SDimitry Andric Diag(PDecl->getLocation(), diag::err_duplicate_property);
6120b57cec5SDimitry Andric Diag(prevDecl->getLocation(), diag::note_property_declare);
6130b57cec5SDimitry Andric PDecl->setInvalidDecl();
6140b57cec5SDimitry Andric }
6150b57cec5SDimitry Andric else {
6160b57cec5SDimitry Andric DC->addDecl(PDecl);
6170b57cec5SDimitry Andric if (lexicalDC)
6180b57cec5SDimitry Andric PDecl->setLexicalDeclContext(lexicalDC);
6190b57cec5SDimitry Andric }
6200b57cec5SDimitry Andric
6210b57cec5SDimitry Andric if (T->isArrayType() || T->isFunctionType()) {
6220b57cec5SDimitry Andric Diag(AtLoc, diag::err_property_type) << T;
6230b57cec5SDimitry Andric PDecl->setInvalidDecl();
6240b57cec5SDimitry Andric }
6250b57cec5SDimitry Andric
6260b57cec5SDimitry Andric // Regardless of setter/getter attribute, we save the default getter/setter
6270b57cec5SDimitry Andric // selector names in anticipation of declaration of setter/getter methods.
6280b57cec5SDimitry Andric PDecl->setGetterName(GetterSel, GetterNameLoc);
6290b57cec5SDimitry Andric PDecl->setSetterName(SetterSel, SetterNameLoc);
6300b57cec5SDimitry Andric PDecl->setPropertyAttributesAsWritten(
6310b57cec5SDimitry Andric makePropertyAttributesAsWritten(AttributesAsWritten));
6320b57cec5SDimitry Andric
633*0fca6ea1SDimitry Andric SemaRef.ProcessDeclAttributes(S, PDecl, FD.D);
634*0fca6ea1SDimitry Andric
6355ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_readonly)
6365ffd83dbSDimitry Andric PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_readonly);
6370b57cec5SDimitry Andric
6385ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_getter)
6395ffd83dbSDimitry Andric PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_getter);
6400b57cec5SDimitry Andric
6415ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_setter)
6425ffd83dbSDimitry Andric PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_setter);
6430b57cec5SDimitry Andric
6440b57cec5SDimitry Andric if (isReadWrite)
6455ffd83dbSDimitry Andric PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_readwrite);
6460b57cec5SDimitry Andric
6475ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_retain)
6485ffd83dbSDimitry Andric PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_retain);
6490b57cec5SDimitry Andric
6505ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_strong)
6515ffd83dbSDimitry Andric PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_strong);
6520b57cec5SDimitry Andric
6535ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_weak)
6545ffd83dbSDimitry Andric PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_weak);
6550b57cec5SDimitry Andric
6565ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_copy)
6575ffd83dbSDimitry Andric PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_copy);
6580b57cec5SDimitry Andric
6595ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained)
6605ffd83dbSDimitry Andric PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_unsafe_unretained);
6610b57cec5SDimitry Andric
6620b57cec5SDimitry Andric if (isAssign)
6635ffd83dbSDimitry Andric PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_assign);
6640b57cec5SDimitry Andric
6650b57cec5SDimitry Andric // In the semantic attributes, one of nonatomic or atomic is always set.
6665ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_nonatomic)
6675ffd83dbSDimitry Andric PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_nonatomic);
6680b57cec5SDimitry Andric else
6695ffd83dbSDimitry Andric PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_atomic);
6700b57cec5SDimitry Andric
6710b57cec5SDimitry Andric // 'unsafe_unretained' is alias for 'assign'.
6725ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained)
6735ffd83dbSDimitry Andric PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_assign);
6740b57cec5SDimitry Andric if (isAssign)
6755ffd83dbSDimitry Andric PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_unsafe_unretained);
6760b57cec5SDimitry Andric
6770b57cec5SDimitry Andric if (MethodImplKind == tok::objc_required)
6780b57cec5SDimitry Andric PDecl->setPropertyImplementation(ObjCPropertyDecl::Required);
6790b57cec5SDimitry Andric else if (MethodImplKind == tok::objc_optional)
6800b57cec5SDimitry Andric PDecl->setPropertyImplementation(ObjCPropertyDecl::Optional);
6810b57cec5SDimitry Andric
6825ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_nullability)
6835ffd83dbSDimitry Andric PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_nullability);
6840b57cec5SDimitry Andric
6855ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_null_resettable)
6865ffd83dbSDimitry Andric PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_null_resettable);
6870b57cec5SDimitry Andric
6885ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_class)
6895ffd83dbSDimitry Andric PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_class);
6900b57cec5SDimitry Andric
6915ffd83dbSDimitry Andric if ((Attributes & ObjCPropertyAttribute::kind_direct) ||
692480093f4SDimitry Andric CDecl->hasAttr<ObjCDirectMembersAttr>()) {
693480093f4SDimitry Andric if (isa<ObjCProtocolDecl>(CDecl)) {
694480093f4SDimitry Andric Diag(PDecl->getLocation(), diag::err_objc_direct_on_protocol) << true;
695480093f4SDimitry Andric } else if (getLangOpts().ObjCRuntime.allowsDirectDispatch()) {
6965ffd83dbSDimitry Andric PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_direct);
697480093f4SDimitry Andric } else {
698480093f4SDimitry Andric Diag(PDecl->getLocation(), diag::warn_objc_direct_property_ignored)
699480093f4SDimitry Andric << PDecl->getDeclName();
700480093f4SDimitry Andric }
701480093f4SDimitry Andric }
702480093f4SDimitry Andric
7030b57cec5SDimitry Andric return PDecl;
7040b57cec5SDimitry Andric }
7050b57cec5SDimitry Andric
checkARCPropertyImpl(Sema & S,SourceLocation propertyImplLoc,ObjCPropertyDecl * property,ObjCIvarDecl * ivar)7060b57cec5SDimitry Andric static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc,
7070b57cec5SDimitry Andric ObjCPropertyDecl *property,
7080b57cec5SDimitry Andric ObjCIvarDecl *ivar) {
7090b57cec5SDimitry Andric if (property->isInvalidDecl() || ivar->isInvalidDecl()) return;
7100b57cec5SDimitry Andric
7110b57cec5SDimitry Andric QualType ivarType = ivar->getType();
7120b57cec5SDimitry Andric Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime();
7130b57cec5SDimitry Andric
7140b57cec5SDimitry Andric // The lifetime implied by the property's attributes.
7150b57cec5SDimitry Andric Qualifiers::ObjCLifetime propertyLifetime =
7160b57cec5SDimitry Andric getImpliedARCOwnership(property->getPropertyAttributes(),
7170b57cec5SDimitry Andric property->getType());
7180b57cec5SDimitry Andric
7190b57cec5SDimitry Andric // We're fine if they match.
7200b57cec5SDimitry Andric if (propertyLifetime == ivarLifetime) return;
7210b57cec5SDimitry Andric
7220b57cec5SDimitry Andric // None isn't a valid lifetime for an object ivar in ARC, and
7230b57cec5SDimitry Andric // __autoreleasing is never valid; don't diagnose twice.
7240b57cec5SDimitry Andric if ((ivarLifetime == Qualifiers::OCL_None &&
7250b57cec5SDimitry Andric S.getLangOpts().ObjCAutoRefCount) ||
7260b57cec5SDimitry Andric ivarLifetime == Qualifiers::OCL_Autoreleasing)
7270b57cec5SDimitry Andric return;
7280b57cec5SDimitry Andric
7290b57cec5SDimitry Andric // If the ivar is private, and it's implicitly __unsafe_unretained
730a7dea167SDimitry Andric // because of its type, then pretend it was actually implicitly
7310b57cec5SDimitry Andric // __strong. This is only sound because we're processing the
7320b57cec5SDimitry Andric // property implementation before parsing any method bodies.
7330b57cec5SDimitry Andric if (ivarLifetime == Qualifiers::OCL_ExplicitNone &&
7340b57cec5SDimitry Andric propertyLifetime == Qualifiers::OCL_Strong &&
7350b57cec5SDimitry Andric ivar->getAccessControl() == ObjCIvarDecl::Private) {
7360b57cec5SDimitry Andric SplitQualType split = ivarType.split();
7370b57cec5SDimitry Andric if (split.Quals.hasObjCLifetime()) {
7380b57cec5SDimitry Andric assert(ivarType->isObjCARCImplicitlyUnretainedType());
7390b57cec5SDimitry Andric split.Quals.setObjCLifetime(Qualifiers::OCL_Strong);
7400b57cec5SDimitry Andric ivarType = S.Context.getQualifiedType(split);
7410b57cec5SDimitry Andric ivar->setType(ivarType);
7420b57cec5SDimitry Andric return;
7430b57cec5SDimitry Andric }
7440b57cec5SDimitry Andric }
7450b57cec5SDimitry Andric
7460b57cec5SDimitry Andric switch (propertyLifetime) {
7470b57cec5SDimitry Andric case Qualifiers::OCL_Strong:
7480b57cec5SDimitry Andric S.Diag(ivar->getLocation(), diag::err_arc_strong_property_ownership)
7490b57cec5SDimitry Andric << property->getDeclName()
7500b57cec5SDimitry Andric << ivar->getDeclName()
7510b57cec5SDimitry Andric << ivarLifetime;
7520b57cec5SDimitry Andric break;
7530b57cec5SDimitry Andric
7540b57cec5SDimitry Andric case Qualifiers::OCL_Weak:
7550b57cec5SDimitry Andric S.Diag(ivar->getLocation(), diag::err_weak_property)
7560b57cec5SDimitry Andric << property->getDeclName()
7570b57cec5SDimitry Andric << ivar->getDeclName();
7580b57cec5SDimitry Andric break;
7590b57cec5SDimitry Andric
7600b57cec5SDimitry Andric case Qualifiers::OCL_ExplicitNone:
7610b57cec5SDimitry Andric S.Diag(ivar->getLocation(), diag::err_arc_assign_property_ownership)
7625ffd83dbSDimitry Andric << property->getDeclName() << ivar->getDeclName()
7635ffd83dbSDimitry Andric << ((property->getPropertyAttributesAsWritten() &
7645ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_assign) != 0);
7650b57cec5SDimitry Andric break;
7660b57cec5SDimitry Andric
7670b57cec5SDimitry Andric case Qualifiers::OCL_Autoreleasing:
7680b57cec5SDimitry Andric llvm_unreachable("properties cannot be autoreleasing");
7690b57cec5SDimitry Andric
7700b57cec5SDimitry Andric case Qualifiers::OCL_None:
7710b57cec5SDimitry Andric // Any other property should be ignored.
7720b57cec5SDimitry Andric return;
7730b57cec5SDimitry Andric }
7740b57cec5SDimitry Andric
7750b57cec5SDimitry Andric S.Diag(property->getLocation(), diag::note_property_declare);
7760b57cec5SDimitry Andric if (propertyImplLoc.isValid())
7770b57cec5SDimitry Andric S.Diag(propertyImplLoc, diag::note_property_synthesize);
7780b57cec5SDimitry Andric }
7790b57cec5SDimitry Andric
7800b57cec5SDimitry Andric /// setImpliedPropertyAttributeForReadOnlyProperty -
7810b57cec5SDimitry Andric /// This routine evaludates life-time attributes for a 'readonly'
7820b57cec5SDimitry Andric /// property with no known lifetime of its own, using backing
7830b57cec5SDimitry Andric /// 'ivar's attribute, if any. If no backing 'ivar', property's
7840b57cec5SDimitry Andric /// life-time is assumed 'strong'.
setImpliedPropertyAttributeForReadOnlyProperty(ObjCPropertyDecl * property,ObjCIvarDecl * ivar)7850b57cec5SDimitry Andric static void setImpliedPropertyAttributeForReadOnlyProperty(
7860b57cec5SDimitry Andric ObjCPropertyDecl *property, ObjCIvarDecl *ivar) {
7870b57cec5SDimitry Andric Qualifiers::ObjCLifetime propertyLifetime =
7880b57cec5SDimitry Andric getImpliedARCOwnership(property->getPropertyAttributes(),
7890b57cec5SDimitry Andric property->getType());
7900b57cec5SDimitry Andric if (propertyLifetime != Qualifiers::OCL_None)
7910b57cec5SDimitry Andric return;
7920b57cec5SDimitry Andric
7930b57cec5SDimitry Andric if (!ivar) {
7940b57cec5SDimitry Andric // if no backing ivar, make property 'strong'.
7955ffd83dbSDimitry Andric property->setPropertyAttributes(ObjCPropertyAttribute::kind_strong);
7960b57cec5SDimitry Andric return;
7970b57cec5SDimitry Andric }
7980b57cec5SDimitry Andric // property assumes owenership of backing ivar.
7990b57cec5SDimitry Andric QualType ivarType = ivar->getType();
8000b57cec5SDimitry Andric Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime();
8010b57cec5SDimitry Andric if (ivarLifetime == Qualifiers::OCL_Strong)
8025ffd83dbSDimitry Andric property->setPropertyAttributes(ObjCPropertyAttribute::kind_strong);
8030b57cec5SDimitry Andric else if (ivarLifetime == Qualifiers::OCL_Weak)
8045ffd83dbSDimitry Andric property->setPropertyAttributes(ObjCPropertyAttribute::kind_weak);
8050b57cec5SDimitry Andric }
8060b57cec5SDimitry Andric
isIncompatiblePropertyAttribute(unsigned Attr1,unsigned Attr2,ObjCPropertyAttribute::Kind Kind)8075ffd83dbSDimitry Andric static bool isIncompatiblePropertyAttribute(unsigned Attr1, unsigned Attr2,
8085ffd83dbSDimitry Andric ObjCPropertyAttribute::Kind Kind) {
8090b57cec5SDimitry Andric return (Attr1 & Kind) != (Attr2 & Kind);
8100b57cec5SDimitry Andric }
8110b57cec5SDimitry Andric
areIncompatiblePropertyAttributes(unsigned Attr1,unsigned Attr2,unsigned Kinds)8120b57cec5SDimitry Andric static bool areIncompatiblePropertyAttributes(unsigned Attr1, unsigned Attr2,
8130b57cec5SDimitry Andric unsigned Kinds) {
8140b57cec5SDimitry Andric return ((Attr1 & Kinds) != 0) != ((Attr2 & Kinds) != 0);
8150b57cec5SDimitry Andric }
8160b57cec5SDimitry Andric
8170b57cec5SDimitry Andric /// SelectPropertyForSynthesisFromProtocols - Finds the most appropriate
8180b57cec5SDimitry Andric /// property declaration that should be synthesised in all of the inherited
8190b57cec5SDimitry Andric /// protocols. It also diagnoses properties declared in inherited protocols with
8200b57cec5SDimitry Andric /// mismatched types or attributes, since any of them can be candidate for
8210b57cec5SDimitry Andric /// synthesis.
8220b57cec5SDimitry Andric static ObjCPropertyDecl *
SelectPropertyForSynthesisFromProtocols(Sema & S,SourceLocation AtLoc,ObjCInterfaceDecl * ClassDecl,ObjCPropertyDecl * Property)8230b57cec5SDimitry Andric SelectPropertyForSynthesisFromProtocols(Sema &S, SourceLocation AtLoc,
8240b57cec5SDimitry Andric ObjCInterfaceDecl *ClassDecl,
8250b57cec5SDimitry Andric ObjCPropertyDecl *Property) {
8260b57cec5SDimitry Andric assert(isa<ObjCProtocolDecl>(Property->getDeclContext()) &&
8270b57cec5SDimitry Andric "Expected a property from a protocol");
8280b57cec5SDimitry Andric ObjCInterfaceDecl::ProtocolPropertySet ProtocolSet;
8290b57cec5SDimitry Andric ObjCInterfaceDecl::PropertyDeclOrder Properties;
8300b57cec5SDimitry Andric for (const auto *PI : ClassDecl->all_referenced_protocols()) {
8310b57cec5SDimitry Andric if (const ObjCProtocolDecl *PDecl = PI->getDefinition())
8320b57cec5SDimitry Andric PDecl->collectInheritedProtocolProperties(Property, ProtocolSet,
8330b57cec5SDimitry Andric Properties);
8340b57cec5SDimitry Andric }
8350b57cec5SDimitry Andric if (ObjCInterfaceDecl *SDecl = ClassDecl->getSuperClass()) {
8360b57cec5SDimitry Andric while (SDecl) {
8370b57cec5SDimitry Andric for (const auto *PI : SDecl->all_referenced_protocols()) {
8380b57cec5SDimitry Andric if (const ObjCProtocolDecl *PDecl = PI->getDefinition())
8390b57cec5SDimitry Andric PDecl->collectInheritedProtocolProperties(Property, ProtocolSet,
8400b57cec5SDimitry Andric Properties);
8410b57cec5SDimitry Andric }
8420b57cec5SDimitry Andric SDecl = SDecl->getSuperClass();
8430b57cec5SDimitry Andric }
8440b57cec5SDimitry Andric }
8450b57cec5SDimitry Andric
8460b57cec5SDimitry Andric if (Properties.empty())
8470b57cec5SDimitry Andric return Property;
8480b57cec5SDimitry Andric
8490b57cec5SDimitry Andric ObjCPropertyDecl *OriginalProperty = Property;
8500b57cec5SDimitry Andric size_t SelectedIndex = 0;
8510b57cec5SDimitry Andric for (const auto &Prop : llvm::enumerate(Properties)) {
8520b57cec5SDimitry Andric // Select the 'readwrite' property if such property exists.
8530b57cec5SDimitry Andric if (Property->isReadOnly() && !Prop.value()->isReadOnly()) {
8540b57cec5SDimitry Andric Property = Prop.value();
8550b57cec5SDimitry Andric SelectedIndex = Prop.index();
8560b57cec5SDimitry Andric }
8570b57cec5SDimitry Andric }
8580b57cec5SDimitry Andric if (Property != OriginalProperty) {
8590b57cec5SDimitry Andric // Check that the old property is compatible with the new one.
8600b57cec5SDimitry Andric Properties[SelectedIndex] = OriginalProperty;
8610b57cec5SDimitry Andric }
8620b57cec5SDimitry Andric
8630b57cec5SDimitry Andric QualType RHSType = S.Context.getCanonicalType(Property->getType());
8640b57cec5SDimitry Andric unsigned OriginalAttributes = Property->getPropertyAttributesAsWritten();
8650b57cec5SDimitry Andric enum MismatchKind {
8660b57cec5SDimitry Andric IncompatibleType = 0,
8670b57cec5SDimitry Andric HasNoExpectedAttribute,
8680b57cec5SDimitry Andric HasUnexpectedAttribute,
8690b57cec5SDimitry Andric DifferentGetter,
8700b57cec5SDimitry Andric DifferentSetter
8710b57cec5SDimitry Andric };
8720b57cec5SDimitry Andric // Represents a property from another protocol that conflicts with the
8730b57cec5SDimitry Andric // selected declaration.
8740b57cec5SDimitry Andric struct MismatchingProperty {
8750b57cec5SDimitry Andric const ObjCPropertyDecl *Prop;
8760b57cec5SDimitry Andric MismatchKind Kind;
8770b57cec5SDimitry Andric StringRef AttributeName;
8780b57cec5SDimitry Andric };
8790b57cec5SDimitry Andric SmallVector<MismatchingProperty, 4> Mismatches;
8800b57cec5SDimitry Andric for (ObjCPropertyDecl *Prop : Properties) {
8810b57cec5SDimitry Andric // Verify the property attributes.
8820b57cec5SDimitry Andric unsigned Attr = Prop->getPropertyAttributesAsWritten();
8830b57cec5SDimitry Andric if (Attr != OriginalAttributes) {
8840b57cec5SDimitry Andric auto Diag = [&](bool OriginalHasAttribute, StringRef AttributeName) {
8850b57cec5SDimitry Andric MismatchKind Kind = OriginalHasAttribute ? HasNoExpectedAttribute
8860b57cec5SDimitry Andric : HasUnexpectedAttribute;
8870b57cec5SDimitry Andric Mismatches.push_back({Prop, Kind, AttributeName});
8880b57cec5SDimitry Andric };
8890b57cec5SDimitry Andric // The ownership might be incompatible unless the property has no explicit
8900b57cec5SDimitry Andric // ownership.
8915ffd83dbSDimitry Andric bool HasOwnership =
8925ffd83dbSDimitry Andric (Attr & (ObjCPropertyAttribute::kind_retain |
8935ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_strong |
8945ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_copy |
8955ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_assign |
8965ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_unsafe_unretained |
8975ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_weak)) != 0;
8980b57cec5SDimitry Andric if (HasOwnership &&
8990b57cec5SDimitry Andric isIncompatiblePropertyAttribute(OriginalAttributes, Attr,
9005ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_copy)) {
9015ffd83dbSDimitry Andric Diag(OriginalAttributes & ObjCPropertyAttribute::kind_copy, "copy");
9020b57cec5SDimitry Andric continue;
9030b57cec5SDimitry Andric }
9040b57cec5SDimitry Andric if (HasOwnership && areIncompatiblePropertyAttributes(
9050b57cec5SDimitry Andric OriginalAttributes, Attr,
9065ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_retain |
9075ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_strong)) {
9085ffd83dbSDimitry Andric Diag(OriginalAttributes & (ObjCPropertyAttribute::kind_retain |
9095ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_strong),
9100b57cec5SDimitry Andric "retain (or strong)");
9110b57cec5SDimitry Andric continue;
9120b57cec5SDimitry Andric }
9130b57cec5SDimitry Andric if (isIncompatiblePropertyAttribute(OriginalAttributes, Attr,
9145ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_atomic)) {
9155ffd83dbSDimitry Andric Diag(OriginalAttributes & ObjCPropertyAttribute::kind_atomic, "atomic");
9160b57cec5SDimitry Andric continue;
9170b57cec5SDimitry Andric }
9180b57cec5SDimitry Andric }
9190b57cec5SDimitry Andric if (Property->getGetterName() != Prop->getGetterName()) {
9200b57cec5SDimitry Andric Mismatches.push_back({Prop, DifferentGetter, ""});
9210b57cec5SDimitry Andric continue;
9220b57cec5SDimitry Andric }
9230b57cec5SDimitry Andric if (!Property->isReadOnly() && !Prop->isReadOnly() &&
9240b57cec5SDimitry Andric Property->getSetterName() != Prop->getSetterName()) {
9250b57cec5SDimitry Andric Mismatches.push_back({Prop, DifferentSetter, ""});
9260b57cec5SDimitry Andric continue;
9270b57cec5SDimitry Andric }
9280b57cec5SDimitry Andric QualType LHSType = S.Context.getCanonicalType(Prop->getType());
9290b57cec5SDimitry Andric if (!S.Context.propertyTypesAreCompatible(LHSType, RHSType)) {
9300b57cec5SDimitry Andric bool IncompatibleObjC = false;
9310b57cec5SDimitry Andric QualType ConvertedType;
9320b57cec5SDimitry Andric if (!S.isObjCPointerConversion(RHSType, LHSType, ConvertedType, IncompatibleObjC)
9330b57cec5SDimitry Andric || IncompatibleObjC) {
9340b57cec5SDimitry Andric Mismatches.push_back({Prop, IncompatibleType, ""});
9350b57cec5SDimitry Andric continue;
9360b57cec5SDimitry Andric }
9370b57cec5SDimitry Andric }
9380b57cec5SDimitry Andric }
9390b57cec5SDimitry Andric
9400b57cec5SDimitry Andric if (Mismatches.empty())
9410b57cec5SDimitry Andric return Property;
9420b57cec5SDimitry Andric
9430b57cec5SDimitry Andric // Diagnose incompability.
9440b57cec5SDimitry Andric {
9450b57cec5SDimitry Andric bool HasIncompatibleAttributes = false;
9460b57cec5SDimitry Andric for (const auto &Note : Mismatches)
9470b57cec5SDimitry Andric HasIncompatibleAttributes =
9480b57cec5SDimitry Andric Note.Kind != IncompatibleType ? true : HasIncompatibleAttributes;
9490b57cec5SDimitry Andric // Promote the warning to an error if there are incompatible attributes or
9500b57cec5SDimitry Andric // incompatible types together with readwrite/readonly incompatibility.
9510b57cec5SDimitry Andric auto Diag = S.Diag(Property->getLocation(),
9520b57cec5SDimitry Andric Property != OriginalProperty || HasIncompatibleAttributes
9530b57cec5SDimitry Andric ? diag::err_protocol_property_mismatch
9540b57cec5SDimitry Andric : diag::warn_protocol_property_mismatch);
9550b57cec5SDimitry Andric Diag << Mismatches[0].Kind;
9560b57cec5SDimitry Andric switch (Mismatches[0].Kind) {
9570b57cec5SDimitry Andric case IncompatibleType:
9580b57cec5SDimitry Andric Diag << Property->getType();
9590b57cec5SDimitry Andric break;
9600b57cec5SDimitry Andric case HasNoExpectedAttribute:
9610b57cec5SDimitry Andric case HasUnexpectedAttribute:
9620b57cec5SDimitry Andric Diag << Mismatches[0].AttributeName;
9630b57cec5SDimitry Andric break;
9640b57cec5SDimitry Andric case DifferentGetter:
9650b57cec5SDimitry Andric Diag << Property->getGetterName();
9660b57cec5SDimitry Andric break;
9670b57cec5SDimitry Andric case DifferentSetter:
9680b57cec5SDimitry Andric Diag << Property->getSetterName();
9690b57cec5SDimitry Andric break;
9700b57cec5SDimitry Andric }
9710b57cec5SDimitry Andric }
9720b57cec5SDimitry Andric for (const auto &Note : Mismatches) {
9730b57cec5SDimitry Andric auto Diag =
9740b57cec5SDimitry Andric S.Diag(Note.Prop->getLocation(), diag::note_protocol_property_declare)
9750b57cec5SDimitry Andric << Note.Kind;
9760b57cec5SDimitry Andric switch (Note.Kind) {
9770b57cec5SDimitry Andric case IncompatibleType:
9780b57cec5SDimitry Andric Diag << Note.Prop->getType();
9790b57cec5SDimitry Andric break;
9800b57cec5SDimitry Andric case HasNoExpectedAttribute:
9810b57cec5SDimitry Andric case HasUnexpectedAttribute:
9820b57cec5SDimitry Andric Diag << Note.AttributeName;
9830b57cec5SDimitry Andric break;
9840b57cec5SDimitry Andric case DifferentGetter:
9850b57cec5SDimitry Andric Diag << Note.Prop->getGetterName();
9860b57cec5SDimitry Andric break;
9870b57cec5SDimitry Andric case DifferentSetter:
9880b57cec5SDimitry Andric Diag << Note.Prop->getSetterName();
9890b57cec5SDimitry Andric break;
9900b57cec5SDimitry Andric }
9910b57cec5SDimitry Andric }
9920b57cec5SDimitry Andric if (AtLoc.isValid())
9930b57cec5SDimitry Andric S.Diag(AtLoc, diag::note_property_synthesize);
9940b57cec5SDimitry Andric
9950b57cec5SDimitry Andric return Property;
9960b57cec5SDimitry Andric }
9970b57cec5SDimitry Andric
9980b57cec5SDimitry Andric /// Determine whether any storage attributes were written on the property.
hasWrittenStorageAttribute(ObjCPropertyDecl * Prop,ObjCPropertyQueryKind QueryKind)9990b57cec5SDimitry Andric static bool hasWrittenStorageAttribute(ObjCPropertyDecl *Prop,
10000b57cec5SDimitry Andric ObjCPropertyQueryKind QueryKind) {
10010b57cec5SDimitry Andric if (Prop->getPropertyAttributesAsWritten() & OwnershipMask) return true;
10020b57cec5SDimitry Andric
10030b57cec5SDimitry Andric // If this is a readwrite property in a class extension that refines
10040b57cec5SDimitry Andric // a readonly property in the original class definition, check it as
10050b57cec5SDimitry Andric // well.
10060b57cec5SDimitry Andric
10070b57cec5SDimitry Andric // If it's a readonly property, we're not interested.
10080b57cec5SDimitry Andric if (Prop->isReadOnly()) return false;
10090b57cec5SDimitry Andric
10100b57cec5SDimitry Andric // Is it declared in an extension?
10110b57cec5SDimitry Andric auto Category = dyn_cast<ObjCCategoryDecl>(Prop->getDeclContext());
10120b57cec5SDimitry Andric if (!Category || !Category->IsClassExtension()) return false;
10130b57cec5SDimitry Andric
10140b57cec5SDimitry Andric // Find the corresponding property in the primary class definition.
10150b57cec5SDimitry Andric auto OrigClass = Category->getClassInterface();
1016bdd1243dSDimitry Andric for (auto *Found : OrigClass->lookup(Prop->getDeclName())) {
10170b57cec5SDimitry Andric if (ObjCPropertyDecl *OrigProp = dyn_cast<ObjCPropertyDecl>(Found))
10180b57cec5SDimitry Andric return OrigProp->getPropertyAttributesAsWritten() & OwnershipMask;
10190b57cec5SDimitry Andric }
10200b57cec5SDimitry Andric
10210b57cec5SDimitry Andric // Look through all of the protocols.
10220b57cec5SDimitry Andric for (const auto *Proto : OrigClass->all_referenced_protocols()) {
10230b57cec5SDimitry Andric if (ObjCPropertyDecl *OrigProp = Proto->FindPropertyDeclaration(
10240b57cec5SDimitry Andric Prop->getIdentifier(), QueryKind))
10250b57cec5SDimitry Andric return OrigProp->getPropertyAttributesAsWritten() & OwnershipMask;
10260b57cec5SDimitry Andric }
10270b57cec5SDimitry Andric
10280b57cec5SDimitry Andric return false;
10290b57cec5SDimitry Andric }
10300b57cec5SDimitry Andric
1031480093f4SDimitry Andric /// Create a synthesized property accessor stub inside the \@implementation.
1032480093f4SDimitry Andric static ObjCMethodDecl *
RedeclarePropertyAccessor(ASTContext & Context,ObjCImplementationDecl * Impl,ObjCMethodDecl * AccessorDecl,SourceLocation AtLoc,SourceLocation PropertyLoc)1033480093f4SDimitry Andric RedeclarePropertyAccessor(ASTContext &Context, ObjCImplementationDecl *Impl,
1034480093f4SDimitry Andric ObjCMethodDecl *AccessorDecl, SourceLocation AtLoc,
1035480093f4SDimitry Andric SourceLocation PropertyLoc) {
1036480093f4SDimitry Andric ObjCMethodDecl *Decl = AccessorDecl;
1037480093f4SDimitry Andric ObjCMethodDecl *ImplDecl = ObjCMethodDecl::Create(
1038480093f4SDimitry Andric Context, AtLoc.isValid() ? AtLoc : Decl->getBeginLoc(),
1039480093f4SDimitry Andric PropertyLoc.isValid() ? PropertyLoc : Decl->getEndLoc(),
1040480093f4SDimitry Andric Decl->getSelector(), Decl->getReturnType(),
1041480093f4SDimitry Andric Decl->getReturnTypeSourceInfo(), Impl, Decl->isInstanceMethod(),
1042480093f4SDimitry Andric Decl->isVariadic(), Decl->isPropertyAccessor(),
1043480093f4SDimitry Andric /* isSynthesized*/ true, Decl->isImplicit(), Decl->isDefined(),
1044480093f4SDimitry Andric Decl->getImplementationControl(), Decl->hasRelatedResultType());
1045480093f4SDimitry Andric ImplDecl->getMethodFamily();
1046480093f4SDimitry Andric if (Decl->hasAttrs())
1047480093f4SDimitry Andric ImplDecl->setAttrs(Decl->getAttrs());
1048480093f4SDimitry Andric ImplDecl->setSelfDecl(Decl->getSelfDecl());
1049480093f4SDimitry Andric ImplDecl->setCmdDecl(Decl->getCmdDecl());
1050480093f4SDimitry Andric SmallVector<SourceLocation, 1> SelLocs;
1051480093f4SDimitry Andric Decl->getSelectorLocs(SelLocs);
1052480093f4SDimitry Andric ImplDecl->setMethodParams(Context, Decl->parameters(), SelLocs);
1053480093f4SDimitry Andric ImplDecl->setLexicalDeclContext(Impl);
1054480093f4SDimitry Andric ImplDecl->setDefined(false);
1055480093f4SDimitry Andric return ImplDecl;
1056480093f4SDimitry Andric }
1057480093f4SDimitry Andric
10580b57cec5SDimitry Andric /// ActOnPropertyImplDecl - This routine performs semantic checks and
10590b57cec5SDimitry Andric /// builds the AST node for a property implementation declaration; declared
10600b57cec5SDimitry Andric /// as \@synthesize or \@dynamic.
10610b57cec5SDimitry Andric ///
ActOnPropertyImplDecl(Scope * S,SourceLocation AtLoc,SourceLocation PropertyLoc,bool Synthesize,IdentifierInfo * PropertyId,IdentifierInfo * PropertyIvar,SourceLocation PropertyIvarLoc,ObjCPropertyQueryKind QueryKind)1062*0fca6ea1SDimitry Andric Decl *SemaObjC::ActOnPropertyImplDecl(
1063*0fca6ea1SDimitry Andric Scope *S, SourceLocation AtLoc, SourceLocation PropertyLoc, bool Synthesize,
1064*0fca6ea1SDimitry Andric IdentifierInfo *PropertyId, IdentifierInfo *PropertyIvar,
1065*0fca6ea1SDimitry Andric SourceLocation PropertyIvarLoc, ObjCPropertyQueryKind QueryKind) {
1066*0fca6ea1SDimitry Andric ASTContext &Context = getASTContext();
10670b57cec5SDimitry Andric ObjCContainerDecl *ClassImpDecl =
1068*0fca6ea1SDimitry Andric dyn_cast<ObjCContainerDecl>(SemaRef.CurContext);
10690b57cec5SDimitry Andric // Make sure we have a context for the property implementation declaration.
10700b57cec5SDimitry Andric if (!ClassImpDecl) {
10710b57cec5SDimitry Andric Diag(AtLoc, diag::err_missing_property_context);
10720b57cec5SDimitry Andric return nullptr;
10730b57cec5SDimitry Andric }
10740b57cec5SDimitry Andric if (PropertyIvarLoc.isInvalid())
10750b57cec5SDimitry Andric PropertyIvarLoc = PropertyLoc;
10760b57cec5SDimitry Andric SourceLocation PropertyDiagLoc = PropertyLoc;
10770b57cec5SDimitry Andric if (PropertyDiagLoc.isInvalid())
10780b57cec5SDimitry Andric PropertyDiagLoc = ClassImpDecl->getBeginLoc();
10790b57cec5SDimitry Andric ObjCPropertyDecl *property = nullptr;
10800b57cec5SDimitry Andric ObjCInterfaceDecl *IDecl = nullptr;
10810b57cec5SDimitry Andric // Find the class or category class where this property must have
10820b57cec5SDimitry Andric // a declaration.
10830b57cec5SDimitry Andric ObjCImplementationDecl *IC = nullptr;
10840b57cec5SDimitry Andric ObjCCategoryImplDecl *CatImplClass = nullptr;
10850b57cec5SDimitry Andric if ((IC = dyn_cast<ObjCImplementationDecl>(ClassImpDecl))) {
10860b57cec5SDimitry Andric IDecl = IC->getClassInterface();
10870b57cec5SDimitry Andric // We always synthesize an interface for an implementation
10880b57cec5SDimitry Andric // without an interface decl. So, IDecl is always non-zero.
10890b57cec5SDimitry Andric assert(IDecl &&
10900b57cec5SDimitry Andric "ActOnPropertyImplDecl - @implementation without @interface");
10910b57cec5SDimitry Andric
10920b57cec5SDimitry Andric // Look for this property declaration in the @implementation's @interface
10930b57cec5SDimitry Andric property = IDecl->FindPropertyDeclaration(PropertyId, QueryKind);
10940b57cec5SDimitry Andric if (!property) {
10950b57cec5SDimitry Andric Diag(PropertyLoc, diag::err_bad_property_decl) << IDecl->getDeclName();
10960b57cec5SDimitry Andric return nullptr;
10970b57cec5SDimitry Andric }
10980b57cec5SDimitry Andric if (property->isClassProperty() && Synthesize) {
10990b57cec5SDimitry Andric Diag(PropertyLoc, diag::err_synthesize_on_class_property) << PropertyId;
11000b57cec5SDimitry Andric return nullptr;
11010b57cec5SDimitry Andric }
11020b57cec5SDimitry Andric unsigned PIkind = property->getPropertyAttributesAsWritten();
11035ffd83dbSDimitry Andric if ((PIkind & (ObjCPropertyAttribute::kind_atomic |
11045ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_nonatomic)) == 0) {
11050b57cec5SDimitry Andric if (AtLoc.isValid())
11060b57cec5SDimitry Andric Diag(AtLoc, diag::warn_implicit_atomic_property);
11070b57cec5SDimitry Andric else
11080b57cec5SDimitry Andric Diag(IC->getLocation(), diag::warn_auto_implicit_atomic_property);
11090b57cec5SDimitry Andric Diag(property->getLocation(), diag::note_property_declare);
11100b57cec5SDimitry Andric }
11110b57cec5SDimitry Andric
11120b57cec5SDimitry Andric if (const ObjCCategoryDecl *CD =
11130b57cec5SDimitry Andric dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) {
11140b57cec5SDimitry Andric if (!CD->IsClassExtension()) {
11150b57cec5SDimitry Andric Diag(PropertyLoc, diag::err_category_property) << CD->getDeclName();
11160b57cec5SDimitry Andric Diag(property->getLocation(), diag::note_property_declare);
11170b57cec5SDimitry Andric return nullptr;
11180b57cec5SDimitry Andric }
11190b57cec5SDimitry Andric }
11205ffd83dbSDimitry Andric if (Synthesize && (PIkind & ObjCPropertyAttribute::kind_readonly) &&
11215ffd83dbSDimitry Andric property->hasAttr<IBOutletAttr>() && !AtLoc.isValid()) {
11220b57cec5SDimitry Andric bool ReadWriteProperty = false;
11230b57cec5SDimitry Andric // Search into the class extensions and see if 'readonly property is
11240b57cec5SDimitry Andric // redeclared 'readwrite', then no warning is to be issued.
11250b57cec5SDimitry Andric for (auto *Ext : IDecl->known_extensions()) {
11260b57cec5SDimitry Andric DeclContext::lookup_result R = Ext->lookup(property->getDeclName());
1127fe6060f1SDimitry Andric if (auto *ExtProp = R.find_first<ObjCPropertyDecl>()) {
11280b57cec5SDimitry Andric PIkind = ExtProp->getPropertyAttributesAsWritten();
11295ffd83dbSDimitry Andric if (PIkind & ObjCPropertyAttribute::kind_readwrite) {
11300b57cec5SDimitry Andric ReadWriteProperty = true;
11310b57cec5SDimitry Andric break;
11320b57cec5SDimitry Andric }
11330b57cec5SDimitry Andric }
11340b57cec5SDimitry Andric }
11350b57cec5SDimitry Andric
11360b57cec5SDimitry Andric if (!ReadWriteProperty) {
11370b57cec5SDimitry Andric Diag(property->getLocation(), diag::warn_auto_readonly_iboutlet_property)
11380b57cec5SDimitry Andric << property;
11390b57cec5SDimitry Andric SourceLocation readonlyLoc;
11400b57cec5SDimitry Andric if (LocPropertyAttribute(Context, "readonly",
11410b57cec5SDimitry Andric property->getLParenLoc(), readonlyLoc)) {
11420b57cec5SDimitry Andric SourceLocation endLoc =
11430b57cec5SDimitry Andric readonlyLoc.getLocWithOffset(strlen("readonly")-1);
11440b57cec5SDimitry Andric SourceRange ReadonlySourceRange(readonlyLoc, endLoc);
11450b57cec5SDimitry Andric Diag(property->getLocation(),
11460b57cec5SDimitry Andric diag::note_auto_readonly_iboutlet_fixup_suggest) <<
11470b57cec5SDimitry Andric FixItHint::CreateReplacement(ReadonlySourceRange, "readwrite");
11480b57cec5SDimitry Andric }
11490b57cec5SDimitry Andric }
11500b57cec5SDimitry Andric }
11510b57cec5SDimitry Andric if (Synthesize && isa<ObjCProtocolDecl>(property->getDeclContext()))
1152*0fca6ea1SDimitry Andric property = SelectPropertyForSynthesisFromProtocols(SemaRef, AtLoc, IDecl,
11530b57cec5SDimitry Andric property);
11540b57cec5SDimitry Andric
11550b57cec5SDimitry Andric } else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) {
11560b57cec5SDimitry Andric if (Synthesize) {
11570b57cec5SDimitry Andric Diag(AtLoc, diag::err_synthesize_category_decl);
11580b57cec5SDimitry Andric return nullptr;
11590b57cec5SDimitry Andric }
11600b57cec5SDimitry Andric IDecl = CatImplClass->getClassInterface();
11610b57cec5SDimitry Andric if (!IDecl) {
11620b57cec5SDimitry Andric Diag(AtLoc, diag::err_missing_property_interface);
11630b57cec5SDimitry Andric return nullptr;
11640b57cec5SDimitry Andric }
11650b57cec5SDimitry Andric ObjCCategoryDecl *Category =
11660b57cec5SDimitry Andric IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier());
11670b57cec5SDimitry Andric
11680b57cec5SDimitry Andric // If category for this implementation not found, it is an error which
11690b57cec5SDimitry Andric // has already been reported eralier.
11700b57cec5SDimitry Andric if (!Category)
11710b57cec5SDimitry Andric return nullptr;
11720b57cec5SDimitry Andric // Look for this property declaration in @implementation's category
11730b57cec5SDimitry Andric property = Category->FindPropertyDeclaration(PropertyId, QueryKind);
11740b57cec5SDimitry Andric if (!property) {
11750b57cec5SDimitry Andric Diag(PropertyLoc, diag::err_bad_category_property_decl)
11760b57cec5SDimitry Andric << Category->getDeclName();
11770b57cec5SDimitry Andric return nullptr;
11780b57cec5SDimitry Andric }
11790b57cec5SDimitry Andric } else {
11800b57cec5SDimitry Andric Diag(AtLoc, diag::err_bad_property_context);
11810b57cec5SDimitry Andric return nullptr;
11820b57cec5SDimitry Andric }
11830b57cec5SDimitry Andric ObjCIvarDecl *Ivar = nullptr;
11840b57cec5SDimitry Andric bool CompleteTypeErr = false;
11850b57cec5SDimitry Andric bool compat = true;
11860b57cec5SDimitry Andric // Check that we have a valid, previously declared ivar for @synthesize
11870b57cec5SDimitry Andric if (Synthesize) {
11880b57cec5SDimitry Andric // @synthesize
11890b57cec5SDimitry Andric if (!PropertyIvar)
11900b57cec5SDimitry Andric PropertyIvar = PropertyId;
11910b57cec5SDimitry Andric // Check that this is a previously declared 'ivar' in 'IDecl' interface
11920b57cec5SDimitry Andric ObjCInterfaceDecl *ClassDeclared;
11930b57cec5SDimitry Andric Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared);
11940b57cec5SDimitry Andric QualType PropType = property->getType();
11950b57cec5SDimitry Andric QualType PropertyIvarType = PropType.getNonReferenceType();
11960b57cec5SDimitry Andric
1197*0fca6ea1SDimitry Andric if (SemaRef.RequireCompleteType(PropertyDiagLoc, PropertyIvarType,
11980b57cec5SDimitry Andric diag::err_incomplete_synthesized_property,
11990b57cec5SDimitry Andric property->getDeclName())) {
12000b57cec5SDimitry Andric Diag(property->getLocation(), diag::note_property_declare);
12010b57cec5SDimitry Andric CompleteTypeErr = true;
12020b57cec5SDimitry Andric }
12030b57cec5SDimitry Andric
12040b57cec5SDimitry Andric if (getLangOpts().ObjCAutoRefCount &&
12050b57cec5SDimitry Andric (property->getPropertyAttributesAsWritten() &
12065ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_readonly) &&
12070b57cec5SDimitry Andric PropertyIvarType->isObjCRetainableType()) {
12080b57cec5SDimitry Andric setImpliedPropertyAttributeForReadOnlyProperty(property, Ivar);
12090b57cec5SDimitry Andric }
12100b57cec5SDimitry Andric
12115ffd83dbSDimitry Andric ObjCPropertyAttribute::Kind kind = property->getPropertyAttributes();
12120b57cec5SDimitry Andric
12130b57cec5SDimitry Andric bool isARCWeak = false;
12145ffd83dbSDimitry Andric if (kind & ObjCPropertyAttribute::kind_weak) {
12150b57cec5SDimitry Andric // Add GC __weak to the ivar type if the property is weak.
12160b57cec5SDimitry Andric if (getLangOpts().getGC() != LangOptions::NonGC) {
12170b57cec5SDimitry Andric assert(!getLangOpts().ObjCAutoRefCount);
12180b57cec5SDimitry Andric if (PropertyIvarType.isObjCGCStrong()) {
12190b57cec5SDimitry Andric Diag(PropertyDiagLoc, diag::err_gc_weak_property_strong_type);
12200b57cec5SDimitry Andric Diag(property->getLocation(), diag::note_property_declare);
12210b57cec5SDimitry Andric } else {
12220b57cec5SDimitry Andric PropertyIvarType =
12230b57cec5SDimitry Andric Context.getObjCGCQualType(PropertyIvarType, Qualifiers::Weak);
12240b57cec5SDimitry Andric }
12250b57cec5SDimitry Andric
12260b57cec5SDimitry Andric // Otherwise, check whether ARC __weak is enabled and works with
12270b57cec5SDimitry Andric // the property type.
12280b57cec5SDimitry Andric } else {
12290b57cec5SDimitry Andric if (!getLangOpts().ObjCWeak) {
12300b57cec5SDimitry Andric // Only complain here when synthesizing an ivar.
12310b57cec5SDimitry Andric if (!Ivar) {
12320b57cec5SDimitry Andric Diag(PropertyDiagLoc,
12330b57cec5SDimitry Andric getLangOpts().ObjCWeakRuntime
12340b57cec5SDimitry Andric ? diag::err_synthesizing_arc_weak_property_disabled
12350b57cec5SDimitry Andric : diag::err_synthesizing_arc_weak_property_no_runtime);
12360b57cec5SDimitry Andric Diag(property->getLocation(), diag::note_property_declare);
12370b57cec5SDimitry Andric }
12380b57cec5SDimitry Andric CompleteTypeErr = true; // suppress later diagnostics about the ivar
12390b57cec5SDimitry Andric } else {
12400b57cec5SDimitry Andric isARCWeak = true;
12410b57cec5SDimitry Andric if (const ObjCObjectPointerType *ObjT =
12420b57cec5SDimitry Andric PropertyIvarType->getAs<ObjCObjectPointerType>()) {
12430b57cec5SDimitry Andric const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl();
12440b57cec5SDimitry Andric if (ObjI && ObjI->isArcWeakrefUnavailable()) {
12450b57cec5SDimitry Andric Diag(property->getLocation(),
12460b57cec5SDimitry Andric diag::err_arc_weak_unavailable_property)
12470b57cec5SDimitry Andric << PropertyIvarType;
12480b57cec5SDimitry Andric Diag(ClassImpDecl->getLocation(), diag::note_implemented_by_class)
12490b57cec5SDimitry Andric << ClassImpDecl->getName();
12500b57cec5SDimitry Andric }
12510b57cec5SDimitry Andric }
12520b57cec5SDimitry Andric }
12530b57cec5SDimitry Andric }
12540b57cec5SDimitry Andric }
12550b57cec5SDimitry Andric
12560b57cec5SDimitry Andric if (AtLoc.isInvalid()) {
12570b57cec5SDimitry Andric // Check when default synthesizing a property that there is
12580b57cec5SDimitry Andric // an ivar matching property name and issue warning; since this
12590b57cec5SDimitry Andric // is the most common case of not using an ivar used for backing
12600b57cec5SDimitry Andric // property in non-default synthesis case.
12610b57cec5SDimitry Andric ObjCInterfaceDecl *ClassDeclared=nullptr;
12620b57cec5SDimitry Andric ObjCIvarDecl *originalIvar =
12630b57cec5SDimitry Andric IDecl->lookupInstanceVariable(property->getIdentifier(),
12640b57cec5SDimitry Andric ClassDeclared);
12650b57cec5SDimitry Andric if (originalIvar) {
12660b57cec5SDimitry Andric Diag(PropertyDiagLoc,
12670b57cec5SDimitry Andric diag::warn_autosynthesis_property_ivar_match)
12680b57cec5SDimitry Andric << PropertyId << (Ivar == nullptr) << PropertyIvar
12690b57cec5SDimitry Andric << originalIvar->getIdentifier();
12700b57cec5SDimitry Andric Diag(property->getLocation(), diag::note_property_declare);
12710b57cec5SDimitry Andric Diag(originalIvar->getLocation(), diag::note_ivar_decl);
12720b57cec5SDimitry Andric }
12730b57cec5SDimitry Andric }
12740b57cec5SDimitry Andric
12750b57cec5SDimitry Andric if (!Ivar) {
12760b57cec5SDimitry Andric // In ARC, give the ivar a lifetime qualifier based on the
12770b57cec5SDimitry Andric // property attributes.
12780b57cec5SDimitry Andric if ((getLangOpts().ObjCAutoRefCount || isARCWeak) &&
12790b57cec5SDimitry Andric !PropertyIvarType.getObjCLifetime() &&
12800b57cec5SDimitry Andric PropertyIvarType->isObjCRetainableType()) {
12810b57cec5SDimitry Andric
12820b57cec5SDimitry Andric // It's an error if we have to do this and the user didn't
12830b57cec5SDimitry Andric // explicitly write an ownership attribute on the property.
12840b57cec5SDimitry Andric if (!hasWrittenStorageAttribute(property, QueryKind) &&
12855ffd83dbSDimitry Andric !(kind & ObjCPropertyAttribute::kind_strong)) {
12860b57cec5SDimitry Andric Diag(PropertyDiagLoc,
12870b57cec5SDimitry Andric diag::err_arc_objc_property_default_assign_on_object);
12880b57cec5SDimitry Andric Diag(property->getLocation(), diag::note_property_declare);
12890b57cec5SDimitry Andric } else {
12900b57cec5SDimitry Andric Qualifiers::ObjCLifetime lifetime =
12910b57cec5SDimitry Andric getImpliedARCOwnership(kind, PropertyIvarType);
12920b57cec5SDimitry Andric assert(lifetime && "no lifetime for property?");
12930b57cec5SDimitry Andric
12940b57cec5SDimitry Andric Qualifiers qs;
12950b57cec5SDimitry Andric qs.addObjCLifetime(lifetime);
12960b57cec5SDimitry Andric PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs);
12970b57cec5SDimitry Andric }
12980b57cec5SDimitry Andric }
12990b57cec5SDimitry Andric
13000b57cec5SDimitry Andric Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl,
13010b57cec5SDimitry Andric PropertyIvarLoc,PropertyIvarLoc, PropertyIvar,
13020b57cec5SDimitry Andric PropertyIvarType, /*TInfo=*/nullptr,
13030b57cec5SDimitry Andric ObjCIvarDecl::Private,
13040b57cec5SDimitry Andric (Expr *)nullptr, true);
1305*0fca6ea1SDimitry Andric if (SemaRef.RequireNonAbstractType(PropertyIvarLoc, PropertyIvarType,
13060b57cec5SDimitry Andric diag::err_abstract_type_in_decl,
1307*0fca6ea1SDimitry Andric Sema::AbstractSynthesizedIvarType)) {
13080b57cec5SDimitry Andric Diag(property->getLocation(), diag::note_property_declare);
13090b57cec5SDimitry Andric // An abstract type is as bad as an incomplete type.
13100b57cec5SDimitry Andric CompleteTypeErr = true;
13110b57cec5SDimitry Andric }
13120b57cec5SDimitry Andric if (!CompleteTypeErr) {
13130b57cec5SDimitry Andric const RecordType *RecordTy = PropertyIvarType->getAs<RecordType>();
13140b57cec5SDimitry Andric if (RecordTy && RecordTy->getDecl()->hasFlexibleArrayMember()) {
13150b57cec5SDimitry Andric Diag(PropertyIvarLoc, diag::err_synthesize_variable_sized_ivar)
13160b57cec5SDimitry Andric << PropertyIvarType;
13170b57cec5SDimitry Andric CompleteTypeErr = true; // suppress later diagnostics about the ivar
13180b57cec5SDimitry Andric }
13190b57cec5SDimitry Andric }
13200b57cec5SDimitry Andric if (CompleteTypeErr)
13210b57cec5SDimitry Andric Ivar->setInvalidDecl();
13220b57cec5SDimitry Andric ClassImpDecl->addDecl(Ivar);
13230b57cec5SDimitry Andric IDecl->makeDeclVisibleInContext(Ivar);
13240b57cec5SDimitry Andric
13250b57cec5SDimitry Andric if (getLangOpts().ObjCRuntime.isFragile())
13260b57cec5SDimitry Andric Diag(PropertyDiagLoc, diag::err_missing_property_ivar_decl)
13270b57cec5SDimitry Andric << PropertyId;
13280b57cec5SDimitry Andric // Note! I deliberately want it to fall thru so, we have a
13290b57cec5SDimitry Andric // a property implementation and to avoid future warnings.
13300b57cec5SDimitry Andric } else if (getLangOpts().ObjCRuntime.isNonFragile() &&
13310b57cec5SDimitry Andric !declaresSameEntity(ClassDeclared, IDecl)) {
13320b57cec5SDimitry Andric Diag(PropertyDiagLoc, diag::err_ivar_in_superclass_use)
13330b57cec5SDimitry Andric << property->getDeclName() << Ivar->getDeclName()
13340b57cec5SDimitry Andric << ClassDeclared->getDeclName();
13350b57cec5SDimitry Andric Diag(Ivar->getLocation(), diag::note_previous_access_declaration)
13360b57cec5SDimitry Andric << Ivar << Ivar->getName();
13370b57cec5SDimitry Andric // Note! I deliberately want it to fall thru so more errors are caught.
13380b57cec5SDimitry Andric }
13390b57cec5SDimitry Andric property->setPropertyIvarDecl(Ivar);
13400b57cec5SDimitry Andric
13410b57cec5SDimitry Andric QualType IvarType = Context.getCanonicalType(Ivar->getType());
13420b57cec5SDimitry Andric
13430b57cec5SDimitry Andric // Check that type of property and its ivar are type compatible.
13440b57cec5SDimitry Andric if (!Context.hasSameType(PropertyIvarType, IvarType)) {
13450b57cec5SDimitry Andric if (isa<ObjCObjectPointerType>(PropertyIvarType)
13460b57cec5SDimitry Andric && isa<ObjCObjectPointerType>(IvarType))
134706c3fb27SDimitry Andric compat = Context.canAssignObjCInterfaces(
134806c3fb27SDimitry Andric PropertyIvarType->castAs<ObjCObjectPointerType>(),
134906c3fb27SDimitry Andric IvarType->castAs<ObjCObjectPointerType>());
13500b57cec5SDimitry Andric else {
1351*0fca6ea1SDimitry Andric compat = (SemaRef.CheckAssignmentConstraints(
1352*0fca6ea1SDimitry Andric PropertyIvarLoc, PropertyIvarType, IvarType) ==
1353*0fca6ea1SDimitry Andric Sema::Compatible);
13540b57cec5SDimitry Andric }
13550b57cec5SDimitry Andric if (!compat) {
13560b57cec5SDimitry Andric Diag(PropertyDiagLoc, diag::err_property_ivar_type)
13570b57cec5SDimitry Andric << property->getDeclName() << PropType
13580b57cec5SDimitry Andric << Ivar->getDeclName() << IvarType;
13590b57cec5SDimitry Andric Diag(Ivar->getLocation(), diag::note_ivar_decl);
13600b57cec5SDimitry Andric // Note! I deliberately want it to fall thru so, we have a
13610b57cec5SDimitry Andric // a property implementation and to avoid future warnings.
13620b57cec5SDimitry Andric }
13630b57cec5SDimitry Andric else {
13640b57cec5SDimitry Andric // FIXME! Rules for properties are somewhat different that those
13650b57cec5SDimitry Andric // for assignments. Use a new routine to consolidate all cases;
13660b57cec5SDimitry Andric // specifically for property redeclarations as well as for ivars.
13670b57cec5SDimitry Andric QualType lhsType =Context.getCanonicalType(PropertyIvarType).getUnqualifiedType();
13680b57cec5SDimitry Andric QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType();
13690b57cec5SDimitry Andric if (lhsType != rhsType &&
13700b57cec5SDimitry Andric lhsType->isArithmeticType()) {
13710b57cec5SDimitry Andric Diag(PropertyDiagLoc, diag::err_property_ivar_type)
13720b57cec5SDimitry Andric << property->getDeclName() << PropType
13730b57cec5SDimitry Andric << Ivar->getDeclName() << IvarType;
13740b57cec5SDimitry Andric Diag(Ivar->getLocation(), diag::note_ivar_decl);
13750b57cec5SDimitry Andric // Fall thru - see previous comment
13760b57cec5SDimitry Andric }
13770b57cec5SDimitry Andric }
13780b57cec5SDimitry Andric // __weak is explicit. So it works on Canonical type.
13790b57cec5SDimitry Andric if ((PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() &&
13800b57cec5SDimitry Andric getLangOpts().getGC() != LangOptions::NonGC)) {
13810b57cec5SDimitry Andric Diag(PropertyDiagLoc, diag::err_weak_property)
13820b57cec5SDimitry Andric << property->getDeclName() << Ivar->getDeclName();
13830b57cec5SDimitry Andric Diag(Ivar->getLocation(), diag::note_ivar_decl);
13840b57cec5SDimitry Andric // Fall thru - see previous comment
13850b57cec5SDimitry Andric }
13860b57cec5SDimitry Andric // Fall thru - see previous comment
13870b57cec5SDimitry Andric if ((property->getType()->isObjCObjectPointerType() ||
13880b57cec5SDimitry Andric PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&
13890b57cec5SDimitry Andric getLangOpts().getGC() != LangOptions::NonGC) {
13900b57cec5SDimitry Andric Diag(PropertyDiagLoc, diag::err_strong_property)
13910b57cec5SDimitry Andric << property->getDeclName() << Ivar->getDeclName();
13920b57cec5SDimitry Andric // Fall thru - see previous comment
13930b57cec5SDimitry Andric }
13940b57cec5SDimitry Andric }
13950b57cec5SDimitry Andric if (getLangOpts().ObjCAutoRefCount || isARCWeak ||
13960b57cec5SDimitry Andric Ivar->getType().getObjCLifetime())
1397*0fca6ea1SDimitry Andric checkARCPropertyImpl(SemaRef, PropertyLoc, property, Ivar);
13980b57cec5SDimitry Andric } else if (PropertyIvar)
13990b57cec5SDimitry Andric // @dynamic
14000b57cec5SDimitry Andric Diag(PropertyDiagLoc, diag::err_dynamic_property_ivar_decl);
14010b57cec5SDimitry Andric
14020b57cec5SDimitry Andric assert (property && "ActOnPropertyImplDecl - property declaration missing");
1403*0fca6ea1SDimitry Andric ObjCPropertyImplDecl *PIDecl = ObjCPropertyImplDecl::Create(
1404*0fca6ea1SDimitry Andric Context, SemaRef.CurContext, AtLoc, PropertyLoc, property,
1405*0fca6ea1SDimitry Andric (Synthesize ? ObjCPropertyImplDecl::Synthesize
14060b57cec5SDimitry Andric : ObjCPropertyImplDecl::Dynamic),
14070b57cec5SDimitry Andric Ivar, PropertyIvarLoc);
14080b57cec5SDimitry Andric
14090b57cec5SDimitry Andric if (CompleteTypeErr || !compat)
14100b57cec5SDimitry Andric PIDecl->setInvalidDecl();
14110b57cec5SDimitry Andric
14120b57cec5SDimitry Andric if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) {
14130b57cec5SDimitry Andric getterMethod->createImplicitParams(Context, IDecl);
1414480093f4SDimitry Andric
1415480093f4SDimitry Andric // Redeclare the getter within the implementation as DeclContext.
1416480093f4SDimitry Andric if (Synthesize) {
1417480093f4SDimitry Andric // If the method hasn't been overridden, create a synthesized implementation.
1418480093f4SDimitry Andric ObjCMethodDecl *OMD = ClassImpDecl->getMethod(
1419480093f4SDimitry Andric getterMethod->getSelector(), getterMethod->isInstanceMethod());
1420480093f4SDimitry Andric if (!OMD)
1421480093f4SDimitry Andric OMD = RedeclarePropertyAccessor(Context, IC, getterMethod, AtLoc,
1422480093f4SDimitry Andric PropertyLoc);
1423480093f4SDimitry Andric PIDecl->setGetterMethodDecl(OMD);
1424480093f4SDimitry Andric }
1425480093f4SDimitry Andric
14260b57cec5SDimitry Andric if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr &&
14270b57cec5SDimitry Andric Ivar->getType()->isRecordType()) {
14280b57cec5SDimitry Andric // For Objective-C++, need to synthesize the AST for the IVAR object to be
14290b57cec5SDimitry Andric // returned by the getter as it must conform to C++'s copy-return rules.
14300b57cec5SDimitry Andric // FIXME. Eventually we want to do this for Objective-C as well.
1431*0fca6ea1SDimitry Andric Sema::SynthesizedFunctionScope Scope(SemaRef, getterMethod);
14320b57cec5SDimitry Andric ImplicitParamDecl *SelfDecl = getterMethod->getSelfDecl();
14330b57cec5SDimitry Andric DeclRefExpr *SelfExpr = new (Context)
14340b57cec5SDimitry Andric DeclRefExpr(Context, SelfDecl, false, SelfDecl->getType(), VK_LValue,
14350b57cec5SDimitry Andric PropertyDiagLoc);
1436*0fca6ea1SDimitry Andric SemaRef.MarkDeclRefReferenced(SelfExpr);
1437e8d8bef9SDimitry Andric Expr *LoadSelfExpr = ImplicitCastExpr::Create(
1438e8d8bef9SDimitry Andric Context, SelfDecl->getType(), CK_LValueToRValue, SelfExpr, nullptr,
1439fe6060f1SDimitry Andric VK_PRValue, FPOptionsOverride());
14400b57cec5SDimitry Andric Expr *IvarRefExpr =
14410b57cec5SDimitry Andric new (Context) ObjCIvarRefExpr(Ivar,
14420b57cec5SDimitry Andric Ivar->getUsageType(SelfDecl->getType()),
14430b57cec5SDimitry Andric PropertyDiagLoc,
14440b57cec5SDimitry Andric Ivar->getLocation(),
14450b57cec5SDimitry Andric LoadSelfExpr, true, true);
1446*0fca6ea1SDimitry Andric ExprResult Res = SemaRef.PerformCopyInitialization(
14470b57cec5SDimitry Andric InitializedEntity::InitializeResult(PropertyDiagLoc,
144828a41182SDimitry Andric getterMethod->getReturnType()),
14490b57cec5SDimitry Andric PropertyDiagLoc, IvarRefExpr);
14500b57cec5SDimitry Andric if (!Res.isInvalid()) {
14510b57cec5SDimitry Andric Expr *ResExpr = Res.getAs<Expr>();
14520b57cec5SDimitry Andric if (ResExpr)
1453*0fca6ea1SDimitry Andric ResExpr = SemaRef.MaybeCreateExprWithCleanups(ResExpr);
14540b57cec5SDimitry Andric PIDecl->setGetterCXXConstructor(ResExpr);
14550b57cec5SDimitry Andric }
14560b57cec5SDimitry Andric }
14570b57cec5SDimitry Andric if (property->hasAttr<NSReturnsNotRetainedAttr>() &&
14580b57cec5SDimitry Andric !getterMethod->hasAttr<NSReturnsNotRetainedAttr>()) {
14590b57cec5SDimitry Andric Diag(getterMethod->getLocation(),
14600b57cec5SDimitry Andric diag::warn_property_getter_owning_mismatch);
14610b57cec5SDimitry Andric Diag(property->getLocation(), diag::note_property_declare);
14620b57cec5SDimitry Andric }
14630b57cec5SDimitry Andric if (getLangOpts().ObjCAutoRefCount && Synthesize)
14640b57cec5SDimitry Andric switch (getterMethod->getMethodFamily()) {
14650b57cec5SDimitry Andric case OMF_retain:
14660b57cec5SDimitry Andric case OMF_retainCount:
14670b57cec5SDimitry Andric case OMF_release:
14680b57cec5SDimitry Andric case OMF_autorelease:
14690b57cec5SDimitry Andric Diag(getterMethod->getLocation(), diag::err_arc_illegal_method_def)
14700b57cec5SDimitry Andric << 1 << getterMethod->getSelector();
14710b57cec5SDimitry Andric break;
14720b57cec5SDimitry Andric default:
14730b57cec5SDimitry Andric break;
14740b57cec5SDimitry Andric }
14750b57cec5SDimitry Andric }
1476480093f4SDimitry Andric
14770b57cec5SDimitry Andric if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) {
14780b57cec5SDimitry Andric setterMethod->createImplicitParams(Context, IDecl);
1479480093f4SDimitry Andric
1480480093f4SDimitry Andric // Redeclare the setter within the implementation as DeclContext.
1481480093f4SDimitry Andric if (Synthesize) {
1482480093f4SDimitry Andric ObjCMethodDecl *OMD = ClassImpDecl->getMethod(
1483480093f4SDimitry Andric setterMethod->getSelector(), setterMethod->isInstanceMethod());
1484480093f4SDimitry Andric if (!OMD)
1485480093f4SDimitry Andric OMD = RedeclarePropertyAccessor(Context, IC, setterMethod,
1486480093f4SDimitry Andric AtLoc, PropertyLoc);
1487480093f4SDimitry Andric PIDecl->setSetterMethodDecl(OMD);
1488480093f4SDimitry Andric }
1489480093f4SDimitry Andric
14900b57cec5SDimitry Andric if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr &&
14910b57cec5SDimitry Andric Ivar->getType()->isRecordType()) {
14920b57cec5SDimitry Andric // FIXME. Eventually we want to do this for Objective-C as well.
1493*0fca6ea1SDimitry Andric Sema::SynthesizedFunctionScope Scope(SemaRef, setterMethod);
14940b57cec5SDimitry Andric ImplicitParamDecl *SelfDecl = setterMethod->getSelfDecl();
14950b57cec5SDimitry Andric DeclRefExpr *SelfExpr = new (Context)
14960b57cec5SDimitry Andric DeclRefExpr(Context, SelfDecl, false, SelfDecl->getType(), VK_LValue,
14970b57cec5SDimitry Andric PropertyDiagLoc);
1498*0fca6ea1SDimitry Andric SemaRef.MarkDeclRefReferenced(SelfExpr);
1499e8d8bef9SDimitry Andric Expr *LoadSelfExpr = ImplicitCastExpr::Create(
1500e8d8bef9SDimitry Andric Context, SelfDecl->getType(), CK_LValueToRValue, SelfExpr, nullptr,
1501fe6060f1SDimitry Andric VK_PRValue, FPOptionsOverride());
15020b57cec5SDimitry Andric Expr *lhs =
15030b57cec5SDimitry Andric new (Context) ObjCIvarRefExpr(Ivar,
15040b57cec5SDimitry Andric Ivar->getUsageType(SelfDecl->getType()),
15050b57cec5SDimitry Andric PropertyDiagLoc,
15060b57cec5SDimitry Andric Ivar->getLocation(),
15070b57cec5SDimitry Andric LoadSelfExpr, true, true);
15080b57cec5SDimitry Andric ObjCMethodDecl::param_iterator P = setterMethod->param_begin();
15090b57cec5SDimitry Andric ParmVarDecl *Param = (*P);
15100b57cec5SDimitry Andric QualType T = Param->getType().getNonReferenceType();
15110b57cec5SDimitry Andric DeclRefExpr *rhs = new (Context)
15120b57cec5SDimitry Andric DeclRefExpr(Context, Param, false, T, VK_LValue, PropertyDiagLoc);
1513*0fca6ea1SDimitry Andric SemaRef.MarkDeclRefReferenced(rhs);
1514*0fca6ea1SDimitry Andric ExprResult Res =
1515*0fca6ea1SDimitry Andric SemaRef.BuildBinOp(S, PropertyDiagLoc, BO_Assign, lhs, rhs);
15160b57cec5SDimitry Andric if (property->getPropertyAttributes() &
15175ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_atomic) {
15180b57cec5SDimitry Andric Expr *callExpr = Res.getAs<Expr>();
15190b57cec5SDimitry Andric if (const CXXOperatorCallExpr *CXXCE =
15200b57cec5SDimitry Andric dyn_cast_or_null<CXXOperatorCallExpr>(callExpr))
15210b57cec5SDimitry Andric if (const FunctionDecl *FuncDecl = CXXCE->getDirectCallee())
15220b57cec5SDimitry Andric if (!FuncDecl->isTrivial())
15230b57cec5SDimitry Andric if (property->getType()->isReferenceType()) {
15240b57cec5SDimitry Andric Diag(PropertyDiagLoc,
15250b57cec5SDimitry Andric diag::err_atomic_property_nontrivial_assign_op)
15260b57cec5SDimitry Andric << property->getType();
15270b57cec5SDimitry Andric Diag(FuncDecl->getBeginLoc(), diag::note_callee_decl)
15280b57cec5SDimitry Andric << FuncDecl;
15290b57cec5SDimitry Andric }
15300b57cec5SDimitry Andric }
15310b57cec5SDimitry Andric PIDecl->setSetterCXXAssignment(Res.getAs<Expr>());
15320b57cec5SDimitry Andric }
15330b57cec5SDimitry Andric }
15340b57cec5SDimitry Andric
15350b57cec5SDimitry Andric if (IC) {
15360b57cec5SDimitry Andric if (Synthesize)
15370b57cec5SDimitry Andric if (ObjCPropertyImplDecl *PPIDecl =
15380b57cec5SDimitry Andric IC->FindPropertyImplIvarDecl(PropertyIvar)) {
15390b57cec5SDimitry Andric Diag(PropertyLoc, diag::err_duplicate_ivar_use)
15400b57cec5SDimitry Andric << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
15410b57cec5SDimitry Andric << PropertyIvar;
15420b57cec5SDimitry Andric Diag(PPIDecl->getLocation(), diag::note_previous_use);
15430b57cec5SDimitry Andric }
15440b57cec5SDimitry Andric
15450b57cec5SDimitry Andric if (ObjCPropertyImplDecl *PPIDecl
15460b57cec5SDimitry Andric = IC->FindPropertyImplDecl(PropertyId, QueryKind)) {
15470b57cec5SDimitry Andric Diag(PropertyLoc, diag::err_property_implemented) << PropertyId;
15480b57cec5SDimitry Andric Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
15490b57cec5SDimitry Andric return nullptr;
15500b57cec5SDimitry Andric }
15510b57cec5SDimitry Andric IC->addPropertyImplementation(PIDecl);
15520b57cec5SDimitry Andric if (getLangOpts().ObjCDefaultSynthProperties &&
15530b57cec5SDimitry Andric getLangOpts().ObjCRuntime.isNonFragile() &&
15540b57cec5SDimitry Andric !IDecl->isObjCRequiresPropertyDefs()) {
15550b57cec5SDimitry Andric // Diagnose if an ivar was lazily synthesdized due to a previous
15560b57cec5SDimitry Andric // use and if 1) property is @dynamic or 2) property is synthesized
15570b57cec5SDimitry Andric // but it requires an ivar of different name.
15580b57cec5SDimitry Andric ObjCInterfaceDecl *ClassDeclared=nullptr;
15590b57cec5SDimitry Andric ObjCIvarDecl *Ivar = nullptr;
15600b57cec5SDimitry Andric if (!Synthesize)
15610b57cec5SDimitry Andric Ivar = IDecl->lookupInstanceVariable(PropertyId, ClassDeclared);
15620b57cec5SDimitry Andric else {
15630b57cec5SDimitry Andric if (PropertyIvar && PropertyIvar != PropertyId)
15640b57cec5SDimitry Andric Ivar = IDecl->lookupInstanceVariable(PropertyId, ClassDeclared);
15650b57cec5SDimitry Andric }
15660b57cec5SDimitry Andric // Issue diagnostics only if Ivar belongs to current class.
15670b57cec5SDimitry Andric if (Ivar && Ivar->getSynthesize() &&
15680b57cec5SDimitry Andric declaresSameEntity(IC->getClassInterface(), ClassDeclared)) {
15690b57cec5SDimitry Andric Diag(Ivar->getLocation(), diag::err_undeclared_var_use)
15700b57cec5SDimitry Andric << PropertyId;
15710b57cec5SDimitry Andric Ivar->setInvalidDecl();
15720b57cec5SDimitry Andric }
15730b57cec5SDimitry Andric }
15740b57cec5SDimitry Andric } else {
15750b57cec5SDimitry Andric if (Synthesize)
15760b57cec5SDimitry Andric if (ObjCPropertyImplDecl *PPIDecl =
15770b57cec5SDimitry Andric CatImplClass->FindPropertyImplIvarDecl(PropertyIvar)) {
15780b57cec5SDimitry Andric Diag(PropertyDiagLoc, diag::err_duplicate_ivar_use)
15790b57cec5SDimitry Andric << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
15800b57cec5SDimitry Andric << PropertyIvar;
15810b57cec5SDimitry Andric Diag(PPIDecl->getLocation(), diag::note_previous_use);
15820b57cec5SDimitry Andric }
15830b57cec5SDimitry Andric
15840b57cec5SDimitry Andric if (ObjCPropertyImplDecl *PPIDecl =
15850b57cec5SDimitry Andric CatImplClass->FindPropertyImplDecl(PropertyId, QueryKind)) {
15860b57cec5SDimitry Andric Diag(PropertyDiagLoc, diag::err_property_implemented) << PropertyId;
15870b57cec5SDimitry Andric Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
15880b57cec5SDimitry Andric return nullptr;
15890b57cec5SDimitry Andric }
15900b57cec5SDimitry Andric CatImplClass->addPropertyImplementation(PIDecl);
15910b57cec5SDimitry Andric }
15920b57cec5SDimitry Andric
15935ffd83dbSDimitry Andric if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic &&
15945ffd83dbSDimitry Andric PIDecl->getPropertyDecl() &&
15955ffd83dbSDimitry Andric PIDecl->getPropertyDecl()->isDirectProperty()) {
15965ffd83dbSDimitry Andric Diag(PropertyLoc, diag::err_objc_direct_dynamic_property);
15975ffd83dbSDimitry Andric Diag(PIDecl->getPropertyDecl()->getLocation(),
15985ffd83dbSDimitry Andric diag::note_previous_declaration);
15995ffd83dbSDimitry Andric return nullptr;
16005ffd83dbSDimitry Andric }
16015ffd83dbSDimitry Andric
16020b57cec5SDimitry Andric return PIDecl;
16030b57cec5SDimitry Andric }
16040b57cec5SDimitry Andric
16050b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
16060b57cec5SDimitry Andric // Helper methods.
16070b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
16080b57cec5SDimitry Andric
16090b57cec5SDimitry Andric /// DiagnosePropertyMismatch - Compares two properties for their
16100b57cec5SDimitry Andric /// attributes and types and warns on a variety of inconsistencies.
16110b57cec5SDimitry Andric ///
DiagnosePropertyMismatch(ObjCPropertyDecl * Property,ObjCPropertyDecl * SuperProperty,const IdentifierInfo * inheritedName,bool OverridingProtocolProperty)1612*0fca6ea1SDimitry Andric void SemaObjC::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
16130b57cec5SDimitry Andric ObjCPropertyDecl *SuperProperty,
16140b57cec5SDimitry Andric const IdentifierInfo *inheritedName,
16150b57cec5SDimitry Andric bool OverridingProtocolProperty) {
1616*0fca6ea1SDimitry Andric ASTContext &Context = getASTContext();
16175ffd83dbSDimitry Andric ObjCPropertyAttribute::Kind CAttr = Property->getPropertyAttributes();
16185ffd83dbSDimitry Andric ObjCPropertyAttribute::Kind SAttr = SuperProperty->getPropertyAttributes();
16190b57cec5SDimitry Andric
16200b57cec5SDimitry Andric // We allow readonly properties without an explicit ownership
16210b57cec5SDimitry Andric // (assign/unsafe_unretained/weak/retain/strong/copy) in super class
16220b57cec5SDimitry Andric // to be overridden by a property with any explicit ownership in the subclass.
16230b57cec5SDimitry Andric if (!OverridingProtocolProperty &&
16240b57cec5SDimitry Andric !getOwnershipRule(SAttr) && getOwnershipRule(CAttr))
16250b57cec5SDimitry Andric ;
16260b57cec5SDimitry Andric else {
16275ffd83dbSDimitry Andric if ((CAttr & ObjCPropertyAttribute::kind_readonly) &&
16285ffd83dbSDimitry Andric (SAttr & ObjCPropertyAttribute::kind_readwrite))
16290b57cec5SDimitry Andric Diag(Property->getLocation(), diag::warn_readonly_property)
16300b57cec5SDimitry Andric << Property->getDeclName() << inheritedName;
16315ffd83dbSDimitry Andric if ((CAttr & ObjCPropertyAttribute::kind_copy) !=
16325ffd83dbSDimitry Andric (SAttr & ObjCPropertyAttribute::kind_copy))
16330b57cec5SDimitry Andric Diag(Property->getLocation(), diag::warn_property_attribute)
16340b57cec5SDimitry Andric << Property->getDeclName() << "copy" << inheritedName;
16355ffd83dbSDimitry Andric else if (!(SAttr & ObjCPropertyAttribute::kind_readonly)) {
16365ffd83dbSDimitry Andric unsigned CAttrRetain = (CAttr & (ObjCPropertyAttribute::kind_retain |
16375ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_strong));
16385ffd83dbSDimitry Andric unsigned SAttrRetain = (SAttr & (ObjCPropertyAttribute::kind_retain |
16395ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_strong));
16400b57cec5SDimitry Andric bool CStrong = (CAttrRetain != 0);
16410b57cec5SDimitry Andric bool SStrong = (SAttrRetain != 0);
16420b57cec5SDimitry Andric if (CStrong != SStrong)
16430b57cec5SDimitry Andric Diag(Property->getLocation(), diag::warn_property_attribute)
16440b57cec5SDimitry Andric << Property->getDeclName() << "retain (or strong)" << inheritedName;
16450b57cec5SDimitry Andric }
16460b57cec5SDimitry Andric }
16470b57cec5SDimitry Andric
16480b57cec5SDimitry Andric // Check for nonatomic; note that nonatomic is effectively
16490b57cec5SDimitry Andric // meaningless for readonly properties, so don't diagnose if the
16500b57cec5SDimitry Andric // atomic property is 'readonly'.
1651*0fca6ea1SDimitry Andric checkAtomicPropertyMismatch(SemaRef, SuperProperty, Property, false);
16520b57cec5SDimitry Andric // Readonly properties from protocols can be implemented as "readwrite"
16530b57cec5SDimitry Andric // with a custom setter name.
16540b57cec5SDimitry Andric if (Property->getSetterName() != SuperProperty->getSetterName() &&
16550b57cec5SDimitry Andric !(SuperProperty->isReadOnly() &&
16560b57cec5SDimitry Andric isa<ObjCProtocolDecl>(SuperProperty->getDeclContext()))) {
16570b57cec5SDimitry Andric Diag(Property->getLocation(), diag::warn_property_attribute)
16580b57cec5SDimitry Andric << Property->getDeclName() << "setter" << inheritedName;
16590b57cec5SDimitry Andric Diag(SuperProperty->getLocation(), diag::note_property_declare);
16600b57cec5SDimitry Andric }
16610b57cec5SDimitry Andric if (Property->getGetterName() != SuperProperty->getGetterName()) {
16620b57cec5SDimitry Andric Diag(Property->getLocation(), diag::warn_property_attribute)
16630b57cec5SDimitry Andric << Property->getDeclName() << "getter" << inheritedName;
16640b57cec5SDimitry Andric Diag(SuperProperty->getLocation(), diag::note_property_declare);
16650b57cec5SDimitry Andric }
16660b57cec5SDimitry Andric
16670b57cec5SDimitry Andric QualType LHSType =
16680b57cec5SDimitry Andric Context.getCanonicalType(SuperProperty->getType());
16690b57cec5SDimitry Andric QualType RHSType =
16700b57cec5SDimitry Andric Context.getCanonicalType(Property->getType());
16710b57cec5SDimitry Andric
16720b57cec5SDimitry Andric if (!Context.propertyTypesAreCompatible(LHSType, RHSType)) {
16730b57cec5SDimitry Andric // Do cases not handled in above.
16740b57cec5SDimitry Andric // FIXME. For future support of covariant property types, revisit this.
16750b57cec5SDimitry Andric bool IncompatibleObjC = false;
16760b57cec5SDimitry Andric QualType ConvertedType;
1677*0fca6ea1SDimitry Andric if (!SemaRef.isObjCPointerConversion(RHSType, LHSType, ConvertedType,
1678*0fca6ea1SDimitry Andric IncompatibleObjC) ||
16790b57cec5SDimitry Andric IncompatibleObjC) {
16800b57cec5SDimitry Andric Diag(Property->getLocation(), diag::warn_property_types_are_incompatible)
16810b57cec5SDimitry Andric << Property->getType() << SuperProperty->getType() << inheritedName;
16820b57cec5SDimitry Andric Diag(SuperProperty->getLocation(), diag::note_property_declare);
16830b57cec5SDimitry Andric }
16840b57cec5SDimitry Andric }
16850b57cec5SDimitry Andric }
16860b57cec5SDimitry Andric
DiagnosePropertyAccessorMismatch(ObjCPropertyDecl * property,ObjCMethodDecl * GetterMethod,SourceLocation Loc)1687*0fca6ea1SDimitry Andric bool SemaObjC::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
16880b57cec5SDimitry Andric ObjCMethodDecl *GetterMethod,
16890b57cec5SDimitry Andric SourceLocation Loc) {
1690*0fca6ea1SDimitry Andric ASTContext &Context = getASTContext();
16910b57cec5SDimitry Andric if (!GetterMethod)
16920b57cec5SDimitry Andric return false;
16930b57cec5SDimitry Andric QualType GetterType = GetterMethod->getReturnType().getNonReferenceType();
16940b57cec5SDimitry Andric QualType PropertyRValueType =
16950b57cec5SDimitry Andric property->getType().getNonReferenceType().getAtomicUnqualifiedType();
16960b57cec5SDimitry Andric bool compat = Context.hasSameType(PropertyRValueType, GetterType);
16970b57cec5SDimitry Andric if (!compat) {
16980b57cec5SDimitry Andric const ObjCObjectPointerType *propertyObjCPtr = nullptr;
16990b57cec5SDimitry Andric const ObjCObjectPointerType *getterObjCPtr = nullptr;
17000b57cec5SDimitry Andric if ((propertyObjCPtr =
17010b57cec5SDimitry Andric PropertyRValueType->getAs<ObjCObjectPointerType>()) &&
17020b57cec5SDimitry Andric (getterObjCPtr = GetterType->getAs<ObjCObjectPointerType>()))
17030b57cec5SDimitry Andric compat = Context.canAssignObjCInterfaces(getterObjCPtr, propertyObjCPtr);
1704*0fca6ea1SDimitry Andric else if (SemaRef.CheckAssignmentConstraints(
1705*0fca6ea1SDimitry Andric Loc, GetterType, PropertyRValueType) != Sema::Compatible) {
17060b57cec5SDimitry Andric Diag(Loc, diag::err_property_accessor_type)
17070b57cec5SDimitry Andric << property->getDeclName() << PropertyRValueType
17080b57cec5SDimitry Andric << GetterMethod->getSelector() << GetterType;
17090b57cec5SDimitry Andric Diag(GetterMethod->getLocation(), diag::note_declared_at);
17100b57cec5SDimitry Andric return true;
17110b57cec5SDimitry Andric } else {
17120b57cec5SDimitry Andric compat = true;
17130b57cec5SDimitry Andric QualType lhsType = Context.getCanonicalType(PropertyRValueType);
17140b57cec5SDimitry Andric QualType rhsType =Context.getCanonicalType(GetterType).getUnqualifiedType();
17150b57cec5SDimitry Andric if (lhsType != rhsType && lhsType->isArithmeticType())
17160b57cec5SDimitry Andric compat = false;
17170b57cec5SDimitry Andric }
17180b57cec5SDimitry Andric }
17190b57cec5SDimitry Andric
17200b57cec5SDimitry Andric if (!compat) {
17210b57cec5SDimitry Andric Diag(Loc, diag::warn_accessor_property_type_mismatch)
17220b57cec5SDimitry Andric << property->getDeclName()
17230b57cec5SDimitry Andric << GetterMethod->getSelector();
17240b57cec5SDimitry Andric Diag(GetterMethod->getLocation(), diag::note_declared_at);
17250b57cec5SDimitry Andric return true;
17260b57cec5SDimitry Andric }
17270b57cec5SDimitry Andric
17280b57cec5SDimitry Andric return false;
17290b57cec5SDimitry Andric }
17300b57cec5SDimitry Andric
17310b57cec5SDimitry Andric /// CollectImmediateProperties - This routine collects all properties in
17320b57cec5SDimitry Andric /// the class and its conforming protocols; but not those in its super class.
17330b57cec5SDimitry Andric static void
CollectImmediateProperties(ObjCContainerDecl * CDecl,ObjCContainerDecl::PropertyMap & PropMap,ObjCContainerDecl::PropertyMap & SuperPropMap,bool CollectClassPropsOnly=false,bool IncludeProtocols=true)17340b57cec5SDimitry Andric CollectImmediateProperties(ObjCContainerDecl *CDecl,
17350b57cec5SDimitry Andric ObjCContainerDecl::PropertyMap &PropMap,
17360b57cec5SDimitry Andric ObjCContainerDecl::PropertyMap &SuperPropMap,
17370b57cec5SDimitry Andric bool CollectClassPropsOnly = false,
17380b57cec5SDimitry Andric bool IncludeProtocols = true) {
17390b57cec5SDimitry Andric if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
17400b57cec5SDimitry Andric for (auto *Prop : IDecl->properties()) {
17410b57cec5SDimitry Andric if (CollectClassPropsOnly && !Prop->isClassProperty())
17420b57cec5SDimitry Andric continue;
17430b57cec5SDimitry Andric PropMap[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] =
17440b57cec5SDimitry Andric Prop;
17450b57cec5SDimitry Andric }
17460b57cec5SDimitry Andric
17470b57cec5SDimitry Andric // Collect the properties from visible extensions.
17480b57cec5SDimitry Andric for (auto *Ext : IDecl->visible_extensions())
17490b57cec5SDimitry Andric CollectImmediateProperties(Ext, PropMap, SuperPropMap,
17500b57cec5SDimitry Andric CollectClassPropsOnly, IncludeProtocols);
17510b57cec5SDimitry Andric
17520b57cec5SDimitry Andric if (IncludeProtocols) {
17530b57cec5SDimitry Andric // Scan through class's protocols.
17540b57cec5SDimitry Andric for (auto *PI : IDecl->all_referenced_protocols())
17550b57cec5SDimitry Andric CollectImmediateProperties(PI, PropMap, SuperPropMap,
17560b57cec5SDimitry Andric CollectClassPropsOnly);
17570b57cec5SDimitry Andric }
17580b57cec5SDimitry Andric }
17590b57cec5SDimitry Andric if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
17600b57cec5SDimitry Andric for (auto *Prop : CATDecl->properties()) {
17610b57cec5SDimitry Andric if (CollectClassPropsOnly && !Prop->isClassProperty())
17620b57cec5SDimitry Andric continue;
17630b57cec5SDimitry Andric PropMap[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] =
17640b57cec5SDimitry Andric Prop;
17650b57cec5SDimitry Andric }
17660b57cec5SDimitry Andric if (IncludeProtocols) {
17670b57cec5SDimitry Andric // Scan through class's protocols.
17680b57cec5SDimitry Andric for (auto *PI : CATDecl->protocols())
17690b57cec5SDimitry Andric CollectImmediateProperties(PI, PropMap, SuperPropMap,
17700b57cec5SDimitry Andric CollectClassPropsOnly);
17710b57cec5SDimitry Andric }
17720b57cec5SDimitry Andric }
17730b57cec5SDimitry Andric else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) {
17740b57cec5SDimitry Andric for (auto *Prop : PDecl->properties()) {
17750b57cec5SDimitry Andric if (CollectClassPropsOnly && !Prop->isClassProperty())
17760b57cec5SDimitry Andric continue;
17770b57cec5SDimitry Andric ObjCPropertyDecl *PropertyFromSuper =
17780b57cec5SDimitry Andric SuperPropMap[std::make_pair(Prop->getIdentifier(),
17790b57cec5SDimitry Andric Prop->isClassProperty())];
17800b57cec5SDimitry Andric // Exclude property for protocols which conform to class's super-class,
17810b57cec5SDimitry Andric // as super-class has to implement the property.
17820b57cec5SDimitry Andric if (!PropertyFromSuper ||
17830b57cec5SDimitry Andric PropertyFromSuper->getIdentifier() != Prop->getIdentifier()) {
17840b57cec5SDimitry Andric ObjCPropertyDecl *&PropEntry =
17850b57cec5SDimitry Andric PropMap[std::make_pair(Prop->getIdentifier(),
17860b57cec5SDimitry Andric Prop->isClassProperty())];
17870b57cec5SDimitry Andric if (!PropEntry)
17880b57cec5SDimitry Andric PropEntry = Prop;
17890b57cec5SDimitry Andric }
17900b57cec5SDimitry Andric }
17910b57cec5SDimitry Andric // Scan through protocol's protocols.
17920b57cec5SDimitry Andric for (auto *PI : PDecl->protocols())
17930b57cec5SDimitry Andric CollectImmediateProperties(PI, PropMap, SuperPropMap,
17940b57cec5SDimitry Andric CollectClassPropsOnly);
17950b57cec5SDimitry Andric }
17960b57cec5SDimitry Andric }
17970b57cec5SDimitry Andric
17980b57cec5SDimitry Andric /// CollectSuperClassPropertyImplementations - This routine collects list of
17990b57cec5SDimitry Andric /// properties to be implemented in super class(s) and also coming from their
18000b57cec5SDimitry Andric /// conforming protocols.
CollectSuperClassPropertyImplementations(ObjCInterfaceDecl * CDecl,ObjCInterfaceDecl::PropertyMap & PropMap)18010b57cec5SDimitry Andric static void CollectSuperClassPropertyImplementations(ObjCInterfaceDecl *CDecl,
18020b57cec5SDimitry Andric ObjCInterfaceDecl::PropertyMap &PropMap) {
18030b57cec5SDimitry Andric if (ObjCInterfaceDecl *SDecl = CDecl->getSuperClass()) {
18040b57cec5SDimitry Andric while (SDecl) {
1805bdd1243dSDimitry Andric SDecl->collectPropertiesToImplement(PropMap);
18060b57cec5SDimitry Andric SDecl = SDecl->getSuperClass();
18070b57cec5SDimitry Andric }
18080b57cec5SDimitry Andric }
18090b57cec5SDimitry Andric }
18100b57cec5SDimitry Andric
18110b57cec5SDimitry Andric /// IvarBacksCurrentMethodAccessor - This routine returns 'true' if 'IV' is
18120b57cec5SDimitry Andric /// an ivar synthesized for 'Method' and 'Method' is a property accessor
18130b57cec5SDimitry Andric /// declared in class 'IFace'.
IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl * IFace,ObjCMethodDecl * Method,ObjCIvarDecl * IV)1814*0fca6ea1SDimitry Andric bool SemaObjC::IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace,
1815*0fca6ea1SDimitry Andric ObjCMethodDecl *Method,
1816*0fca6ea1SDimitry Andric ObjCIvarDecl *IV) {
18170b57cec5SDimitry Andric if (!IV->getSynthesize())
18180b57cec5SDimitry Andric return false;
18190b57cec5SDimitry Andric ObjCMethodDecl *IMD = IFace->lookupMethod(Method->getSelector(),
18200b57cec5SDimitry Andric Method->isInstanceMethod());
18210b57cec5SDimitry Andric if (!IMD || !IMD->isPropertyAccessor())
18220b57cec5SDimitry Andric return false;
18230b57cec5SDimitry Andric
18240b57cec5SDimitry Andric // look up a property declaration whose one of its accessors is implemented
18250b57cec5SDimitry Andric // by this method.
18260b57cec5SDimitry Andric for (const auto *Property : IFace->instance_properties()) {
18270b57cec5SDimitry Andric if ((Property->getGetterName() == IMD->getSelector() ||
18280b57cec5SDimitry Andric Property->getSetterName() == IMD->getSelector()) &&
18290b57cec5SDimitry Andric (Property->getPropertyIvarDecl() == IV))
18300b57cec5SDimitry Andric return true;
18310b57cec5SDimitry Andric }
18320b57cec5SDimitry Andric // Also look up property declaration in class extension whose one of its
18330b57cec5SDimitry Andric // accessors is implemented by this method.
18340b57cec5SDimitry Andric for (const auto *Ext : IFace->known_extensions())
18350b57cec5SDimitry Andric for (const auto *Property : Ext->instance_properties())
18360b57cec5SDimitry Andric if ((Property->getGetterName() == IMD->getSelector() ||
18370b57cec5SDimitry Andric Property->getSetterName() == IMD->getSelector()) &&
18380b57cec5SDimitry Andric (Property->getPropertyIvarDecl() == IV))
18390b57cec5SDimitry Andric return true;
18400b57cec5SDimitry Andric return false;
18410b57cec5SDimitry Andric }
18420b57cec5SDimitry Andric
SuperClassImplementsProperty(ObjCInterfaceDecl * IDecl,ObjCPropertyDecl * Prop)18430b57cec5SDimitry Andric static bool SuperClassImplementsProperty(ObjCInterfaceDecl *IDecl,
18440b57cec5SDimitry Andric ObjCPropertyDecl *Prop) {
18450b57cec5SDimitry Andric bool SuperClassImplementsGetter = false;
18460b57cec5SDimitry Andric bool SuperClassImplementsSetter = false;
18475ffd83dbSDimitry Andric if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_readonly)
18480b57cec5SDimitry Andric SuperClassImplementsSetter = true;
18490b57cec5SDimitry Andric
18500b57cec5SDimitry Andric while (IDecl->getSuperClass()) {
18510b57cec5SDimitry Andric ObjCInterfaceDecl *SDecl = IDecl->getSuperClass();
18520b57cec5SDimitry Andric if (!SuperClassImplementsGetter && SDecl->getInstanceMethod(Prop->getGetterName()))
18530b57cec5SDimitry Andric SuperClassImplementsGetter = true;
18540b57cec5SDimitry Andric
18550b57cec5SDimitry Andric if (!SuperClassImplementsSetter && SDecl->getInstanceMethod(Prop->getSetterName()))
18560b57cec5SDimitry Andric SuperClassImplementsSetter = true;
18570b57cec5SDimitry Andric if (SuperClassImplementsGetter && SuperClassImplementsSetter)
18580b57cec5SDimitry Andric return true;
18590b57cec5SDimitry Andric IDecl = IDecl->getSuperClass();
18600b57cec5SDimitry Andric }
18610b57cec5SDimitry Andric return false;
18620b57cec5SDimitry Andric }
18630b57cec5SDimitry Andric
18640b57cec5SDimitry Andric /// Default synthesizes all properties which must be synthesized
18650b57cec5SDimitry Andric /// in class's \@implementation.
DefaultSynthesizeProperties(Scope * S,ObjCImplDecl * IMPDecl,ObjCInterfaceDecl * IDecl,SourceLocation AtEnd)1866*0fca6ea1SDimitry Andric void SemaObjC::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl,
18670b57cec5SDimitry Andric ObjCInterfaceDecl *IDecl,
18680b57cec5SDimitry Andric SourceLocation AtEnd) {
1869*0fca6ea1SDimitry Andric ASTContext &Context = getASTContext();
18700b57cec5SDimitry Andric ObjCInterfaceDecl::PropertyMap PropMap;
1871bdd1243dSDimitry Andric IDecl->collectPropertiesToImplement(PropMap);
18720b57cec5SDimitry Andric if (PropMap.empty())
18730b57cec5SDimitry Andric return;
18740b57cec5SDimitry Andric ObjCInterfaceDecl::PropertyMap SuperPropMap;
18750b57cec5SDimitry Andric CollectSuperClassPropertyImplementations(IDecl, SuperPropMap);
18760b57cec5SDimitry Andric
1877bdd1243dSDimitry Andric for (const auto &PropEntry : PropMap) {
1878bdd1243dSDimitry Andric ObjCPropertyDecl *Prop = PropEntry.second;
18790b57cec5SDimitry Andric // Is there a matching property synthesize/dynamic?
18800b57cec5SDimitry Andric if (Prop->isInvalidDecl() ||
18810b57cec5SDimitry Andric Prop->isClassProperty() ||
18820b57cec5SDimitry Andric Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional)
18830b57cec5SDimitry Andric continue;
18840b57cec5SDimitry Andric // Property may have been synthesized by user.
18850b57cec5SDimitry Andric if (IMPDecl->FindPropertyImplDecl(
18860b57cec5SDimitry Andric Prop->getIdentifier(), Prop->getQueryKind()))
18870b57cec5SDimitry Andric continue;
1888480093f4SDimitry Andric ObjCMethodDecl *ImpMethod = IMPDecl->getInstanceMethod(Prop->getGetterName());
1889480093f4SDimitry Andric if (ImpMethod && !ImpMethod->getBody()) {
18905ffd83dbSDimitry Andric if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_readonly)
18910b57cec5SDimitry Andric continue;
1892480093f4SDimitry Andric ImpMethod = IMPDecl->getInstanceMethod(Prop->getSetterName());
1893480093f4SDimitry Andric if (ImpMethod && !ImpMethod->getBody())
18940b57cec5SDimitry Andric continue;
18950b57cec5SDimitry Andric }
18960b57cec5SDimitry Andric if (ObjCPropertyImplDecl *PID =
18970b57cec5SDimitry Andric IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier())) {
18980b57cec5SDimitry Andric Diag(Prop->getLocation(), diag::warn_no_autosynthesis_shared_ivar_property)
18990b57cec5SDimitry Andric << Prop->getIdentifier();
19000b57cec5SDimitry Andric if (PID->getLocation().isValid())
19010b57cec5SDimitry Andric Diag(PID->getLocation(), diag::note_property_synthesize);
19020b57cec5SDimitry Andric continue;
19030b57cec5SDimitry Andric }
19040b57cec5SDimitry Andric ObjCPropertyDecl *PropInSuperClass =
19050b57cec5SDimitry Andric SuperPropMap[std::make_pair(Prop->getIdentifier(),
19060b57cec5SDimitry Andric Prop->isClassProperty())];
19070b57cec5SDimitry Andric if (ObjCProtocolDecl *Proto =
19080b57cec5SDimitry Andric dyn_cast<ObjCProtocolDecl>(Prop->getDeclContext())) {
19090b57cec5SDimitry Andric // We won't auto-synthesize properties declared in protocols.
19100b57cec5SDimitry Andric // Suppress the warning if class's superclass implements property's
19110b57cec5SDimitry Andric // getter and implements property's setter (if readwrite property).
19120b57cec5SDimitry Andric // Or, if property is going to be implemented in its super class.
19130b57cec5SDimitry Andric if (!SuperClassImplementsProperty(IDecl, Prop) && !PropInSuperClass) {
19140b57cec5SDimitry Andric Diag(IMPDecl->getLocation(),
19150b57cec5SDimitry Andric diag::warn_auto_synthesizing_protocol_property)
19160b57cec5SDimitry Andric << Prop << Proto;
19170b57cec5SDimitry Andric Diag(Prop->getLocation(), diag::note_property_declare);
19180b57cec5SDimitry Andric std::string FixIt =
19190b57cec5SDimitry Andric (Twine("@synthesize ") + Prop->getName() + ";\n\n").str();
19200b57cec5SDimitry Andric Diag(AtEnd, diag::note_add_synthesize_directive)
19210b57cec5SDimitry Andric << FixItHint::CreateInsertion(AtEnd, FixIt);
19220b57cec5SDimitry Andric }
19230b57cec5SDimitry Andric continue;
19240b57cec5SDimitry Andric }
19250b57cec5SDimitry Andric // If property to be implemented in the super class, ignore.
19260b57cec5SDimitry Andric if (PropInSuperClass) {
19275ffd83dbSDimitry Andric if ((Prop->getPropertyAttributes() &
19285ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_readwrite) &&
19290b57cec5SDimitry Andric (PropInSuperClass->getPropertyAttributes() &
19305ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_readonly) &&
19310b57cec5SDimitry Andric !IMPDecl->getInstanceMethod(Prop->getSetterName()) &&
19320b57cec5SDimitry Andric !IDecl->HasUserDeclaredSetterMethod(Prop)) {
19330b57cec5SDimitry Andric Diag(Prop->getLocation(), diag::warn_no_autosynthesis_property)
19340b57cec5SDimitry Andric << Prop->getIdentifier();
19350b57cec5SDimitry Andric Diag(PropInSuperClass->getLocation(), diag::note_property_declare);
19365ffd83dbSDimitry Andric } else {
19370b57cec5SDimitry Andric Diag(Prop->getLocation(), diag::warn_autosynthesis_property_in_superclass)
19380b57cec5SDimitry Andric << Prop->getIdentifier();
19390b57cec5SDimitry Andric Diag(PropInSuperClass->getLocation(), diag::note_property_declare);
19400b57cec5SDimitry Andric Diag(IMPDecl->getLocation(), diag::note_while_in_implementation);
19410b57cec5SDimitry Andric }
19420b57cec5SDimitry Andric continue;
19430b57cec5SDimitry Andric }
19440b57cec5SDimitry Andric // We use invalid SourceLocations for the synthesized ivars since they
19450b57cec5SDimitry Andric // aren't really synthesized at a particular location; they just exist.
19460b57cec5SDimitry Andric // Saying that they are located at the @implementation isn't really going
19470b57cec5SDimitry Andric // to help users.
19480b57cec5SDimitry Andric ObjCPropertyImplDecl *PIDecl = dyn_cast_or_null<ObjCPropertyImplDecl>(
19490b57cec5SDimitry Andric ActOnPropertyImplDecl(S, SourceLocation(), SourceLocation(),
19500b57cec5SDimitry Andric true,
19510b57cec5SDimitry Andric /* property = */ Prop->getIdentifier(),
19520b57cec5SDimitry Andric /* ivar = */ Prop->getDefaultSynthIvarName(Context),
19530b57cec5SDimitry Andric Prop->getLocation(), Prop->getQueryKind()));
19540b57cec5SDimitry Andric if (PIDecl && !Prop->isUnavailable()) {
19550b57cec5SDimitry Andric Diag(Prop->getLocation(), diag::warn_missing_explicit_synthesis);
19560b57cec5SDimitry Andric Diag(IMPDecl->getLocation(), diag::note_while_in_implementation);
19570b57cec5SDimitry Andric }
19580b57cec5SDimitry Andric }
19590b57cec5SDimitry Andric }
19600b57cec5SDimitry Andric
DefaultSynthesizeProperties(Scope * S,Decl * D,SourceLocation AtEnd)1961*0fca6ea1SDimitry Andric void SemaObjC::DefaultSynthesizeProperties(Scope *S, Decl *D,
19620b57cec5SDimitry Andric SourceLocation AtEnd) {
1963*0fca6ea1SDimitry Andric if (!getLangOpts().ObjCDefaultSynthProperties ||
1964*0fca6ea1SDimitry Andric getLangOpts().ObjCRuntime.isFragile())
19650b57cec5SDimitry Andric return;
19660b57cec5SDimitry Andric ObjCImplementationDecl *IC=dyn_cast_or_null<ObjCImplementationDecl>(D);
19670b57cec5SDimitry Andric if (!IC)
19680b57cec5SDimitry Andric return;
19690b57cec5SDimitry Andric if (ObjCInterfaceDecl* IDecl = IC->getClassInterface())
19700b57cec5SDimitry Andric if (!IDecl->isObjCRequiresPropertyDefs())
19710b57cec5SDimitry Andric DefaultSynthesizeProperties(S, IC, IDecl, AtEnd);
19720b57cec5SDimitry Andric }
19730b57cec5SDimitry Andric
DiagnoseUnimplementedAccessor(Sema & S,ObjCInterfaceDecl * PrimaryClass,Selector Method,ObjCImplDecl * IMPDecl,ObjCContainerDecl * CDecl,ObjCCategoryDecl * C,ObjCPropertyDecl * Prop,llvm::SmallPtrSet<const ObjCMethodDecl *,8> & SMap)19740b57cec5SDimitry Andric static void DiagnoseUnimplementedAccessor(
19750b57cec5SDimitry Andric Sema &S, ObjCInterfaceDecl *PrimaryClass, Selector Method,
19760b57cec5SDimitry Andric ObjCImplDecl *IMPDecl, ObjCContainerDecl *CDecl, ObjCCategoryDecl *C,
19770b57cec5SDimitry Andric ObjCPropertyDecl *Prop,
19780b57cec5SDimitry Andric llvm::SmallPtrSet<const ObjCMethodDecl *, 8> &SMap) {
19790b57cec5SDimitry Andric // Check to see if we have a corresponding selector in SMap and with the
19800b57cec5SDimitry Andric // right method type.
19810b57cec5SDimitry Andric auto I = llvm::find_if(SMap, [&](const ObjCMethodDecl *x) {
19820b57cec5SDimitry Andric return x->getSelector() == Method &&
19830b57cec5SDimitry Andric x->isClassMethod() == Prop->isClassProperty();
19840b57cec5SDimitry Andric });
19850b57cec5SDimitry Andric // When reporting on missing property setter/getter implementation in
19860b57cec5SDimitry Andric // categories, do not report when they are declared in primary class,
19870b57cec5SDimitry Andric // class's protocol, or one of it super classes. This is because,
19880b57cec5SDimitry Andric // the class is going to implement them.
19890b57cec5SDimitry Andric if (I == SMap.end() &&
19900b57cec5SDimitry Andric (PrimaryClass == nullptr ||
19910b57cec5SDimitry Andric !PrimaryClass->lookupPropertyAccessor(Method, C,
19920b57cec5SDimitry Andric Prop->isClassProperty()))) {
19930b57cec5SDimitry Andric unsigned diag =
19940b57cec5SDimitry Andric isa<ObjCCategoryDecl>(CDecl)
19950b57cec5SDimitry Andric ? (Prop->isClassProperty()
19960b57cec5SDimitry Andric ? diag::warn_impl_required_in_category_for_class_property
19970b57cec5SDimitry Andric : diag::warn_setter_getter_impl_required_in_category)
19980b57cec5SDimitry Andric : (Prop->isClassProperty()
19990b57cec5SDimitry Andric ? diag::warn_impl_required_for_class_property
20000b57cec5SDimitry Andric : diag::warn_setter_getter_impl_required);
20010b57cec5SDimitry Andric S.Diag(IMPDecl->getLocation(), diag) << Prop->getDeclName() << Method;
20020b57cec5SDimitry Andric S.Diag(Prop->getLocation(), diag::note_property_declare);
20030b57cec5SDimitry Andric if (S.LangOpts.ObjCDefaultSynthProperties &&
20040b57cec5SDimitry Andric S.LangOpts.ObjCRuntime.isNonFragile())
20050b57cec5SDimitry Andric if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl))
20060b57cec5SDimitry Andric if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs())
20070b57cec5SDimitry Andric S.Diag(RID->getLocation(), diag::note_suppressed_class_declare);
20080b57cec5SDimitry Andric }
20090b57cec5SDimitry Andric }
20100b57cec5SDimitry Andric
DiagnoseUnimplementedProperties(Scope * S,ObjCImplDecl * IMPDecl,ObjCContainerDecl * CDecl,bool SynthesizeProperties)2011*0fca6ea1SDimitry Andric void SemaObjC::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl *IMPDecl,
20120b57cec5SDimitry Andric ObjCContainerDecl *CDecl,
20130b57cec5SDimitry Andric bool SynthesizeProperties) {
20140b57cec5SDimitry Andric ObjCContainerDecl::PropertyMap PropMap;
20150b57cec5SDimitry Andric ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
20160b57cec5SDimitry Andric
20170b57cec5SDimitry Andric // Since we don't synthesize class properties, we should emit diagnose even
20180b57cec5SDimitry Andric // if SynthesizeProperties is true.
20190b57cec5SDimitry Andric ObjCContainerDecl::PropertyMap NoNeedToImplPropMap;
20200b57cec5SDimitry Andric // Gather properties which need not be implemented in this class
20210b57cec5SDimitry Andric // or category.
20220b57cec5SDimitry Andric if (!IDecl)
20230b57cec5SDimitry Andric if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
20240b57cec5SDimitry Andric // For categories, no need to implement properties declared in
20250b57cec5SDimitry Andric // its primary class (and its super classes) if property is
20260b57cec5SDimitry Andric // declared in one of those containers.
20270b57cec5SDimitry Andric if ((IDecl = C->getClassInterface())) {
2028bdd1243dSDimitry Andric IDecl->collectPropertiesToImplement(NoNeedToImplPropMap);
20290b57cec5SDimitry Andric }
20300b57cec5SDimitry Andric }
20310b57cec5SDimitry Andric if (IDecl)
20320b57cec5SDimitry Andric CollectSuperClassPropertyImplementations(IDecl, NoNeedToImplPropMap);
20330b57cec5SDimitry Andric
20340b57cec5SDimitry Andric // When SynthesizeProperties is true, we only check class properties.
20350b57cec5SDimitry Andric CollectImmediateProperties(CDecl, PropMap, NoNeedToImplPropMap,
20360b57cec5SDimitry Andric SynthesizeProperties/*CollectClassPropsOnly*/);
20370b57cec5SDimitry Andric
20380b57cec5SDimitry Andric // Scan the @interface to see if any of the protocols it adopts
20390b57cec5SDimitry Andric // require an explicit implementation, via attribute
20400b57cec5SDimitry Andric // 'objc_protocol_requires_explicit_implementation'.
20410b57cec5SDimitry Andric if (IDecl) {
20420b57cec5SDimitry Andric std::unique_ptr<ObjCContainerDecl::PropertyMap> LazyMap;
20430b57cec5SDimitry Andric
20440b57cec5SDimitry Andric for (auto *PDecl : IDecl->all_referenced_protocols()) {
20450b57cec5SDimitry Andric if (!PDecl->hasAttr<ObjCExplicitProtocolImplAttr>())
20460b57cec5SDimitry Andric continue;
20470b57cec5SDimitry Andric // Lazily construct a set of all the properties in the @interface
20480b57cec5SDimitry Andric // of the class, without looking at the superclass. We cannot
20490b57cec5SDimitry Andric // use the call to CollectImmediateProperties() above as that
20500b57cec5SDimitry Andric // utilizes information from the super class's properties as well
20510b57cec5SDimitry Andric // as scans the adopted protocols. This work only triggers for protocols
20520b57cec5SDimitry Andric // with the attribute, which is very rare, and only occurs when
20530b57cec5SDimitry Andric // analyzing the @implementation.
20540b57cec5SDimitry Andric if (!LazyMap) {
20550b57cec5SDimitry Andric ObjCContainerDecl::PropertyMap NoNeedToImplPropMap;
20560b57cec5SDimitry Andric LazyMap.reset(new ObjCContainerDecl::PropertyMap());
20570b57cec5SDimitry Andric CollectImmediateProperties(CDecl, *LazyMap, NoNeedToImplPropMap,
20580b57cec5SDimitry Andric /* CollectClassPropsOnly */ false,
20590b57cec5SDimitry Andric /* IncludeProtocols */ false);
20600b57cec5SDimitry Andric }
20610b57cec5SDimitry Andric // Add the properties of 'PDecl' to the list of properties that
20620b57cec5SDimitry Andric // need to be implemented.
20630b57cec5SDimitry Andric for (auto *PropDecl : PDecl->properties()) {
20640b57cec5SDimitry Andric if ((*LazyMap)[std::make_pair(PropDecl->getIdentifier(),
20650b57cec5SDimitry Andric PropDecl->isClassProperty())])
20660b57cec5SDimitry Andric continue;
20670b57cec5SDimitry Andric PropMap[std::make_pair(PropDecl->getIdentifier(),
20680b57cec5SDimitry Andric PropDecl->isClassProperty())] = PropDecl;
20690b57cec5SDimitry Andric }
20700b57cec5SDimitry Andric }
20710b57cec5SDimitry Andric }
20720b57cec5SDimitry Andric
20730b57cec5SDimitry Andric if (PropMap.empty())
20740b57cec5SDimitry Andric return;
20750b57cec5SDimitry Andric
20760b57cec5SDimitry Andric llvm::DenseSet<ObjCPropertyDecl *> PropImplMap;
20770b57cec5SDimitry Andric for (const auto *I : IMPDecl->property_impls())
20780b57cec5SDimitry Andric PropImplMap.insert(I->getPropertyDecl());
20790b57cec5SDimitry Andric
20800b57cec5SDimitry Andric llvm::SmallPtrSet<const ObjCMethodDecl *, 8> InsMap;
20810b57cec5SDimitry Andric // Collect property accessors implemented in current implementation.
20820b57cec5SDimitry Andric for (const auto *I : IMPDecl->methods())
20830b57cec5SDimitry Andric InsMap.insert(I);
20840b57cec5SDimitry Andric
20850b57cec5SDimitry Andric ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl);
20860b57cec5SDimitry Andric ObjCInterfaceDecl *PrimaryClass = nullptr;
20870b57cec5SDimitry Andric if (C && !C->IsClassExtension())
20880b57cec5SDimitry Andric if ((PrimaryClass = C->getClassInterface()))
20890b57cec5SDimitry Andric // Report unimplemented properties in the category as well.
20900b57cec5SDimitry Andric if (ObjCImplDecl *IMP = PrimaryClass->getImplementation()) {
20910b57cec5SDimitry Andric // When reporting on missing setter/getters, do not report when
20920b57cec5SDimitry Andric // setter/getter is implemented in category's primary class
20930b57cec5SDimitry Andric // implementation.
20940b57cec5SDimitry Andric for (const auto *I : IMP->methods())
20950b57cec5SDimitry Andric InsMap.insert(I);
20960b57cec5SDimitry Andric }
20970b57cec5SDimitry Andric
20980b57cec5SDimitry Andric for (ObjCContainerDecl::PropertyMap::iterator
20990b57cec5SDimitry Andric P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
21000b57cec5SDimitry Andric ObjCPropertyDecl *Prop = P->second;
21010b57cec5SDimitry Andric // Is there a matching property synthesize/dynamic?
21020b57cec5SDimitry Andric if (Prop->isInvalidDecl() ||
21030b57cec5SDimitry Andric Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
21040b57cec5SDimitry Andric PropImplMap.count(Prop) ||
21050b57cec5SDimitry Andric Prop->getAvailability() == AR_Unavailable)
21060b57cec5SDimitry Andric continue;
21070b57cec5SDimitry Andric
21080b57cec5SDimitry Andric // Diagnose unimplemented getters and setters.
2109*0fca6ea1SDimitry Andric DiagnoseUnimplementedAccessor(SemaRef, PrimaryClass, Prop->getGetterName(),
21100b57cec5SDimitry Andric IMPDecl, CDecl, C, Prop, InsMap);
2111*0fca6ea1SDimitry Andric if (!Prop->isReadOnly())
2112*0fca6ea1SDimitry Andric DiagnoseUnimplementedAccessor(SemaRef, PrimaryClass,
2113*0fca6ea1SDimitry Andric Prop->getSetterName(), IMPDecl, CDecl, C,
2114*0fca6ea1SDimitry Andric Prop, InsMap);
21150b57cec5SDimitry Andric }
21160b57cec5SDimitry Andric }
21170b57cec5SDimitry Andric
diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl * impDecl)2118*0fca6ea1SDimitry Andric void SemaObjC::diagnoseNullResettableSynthesizedSetters(
2119*0fca6ea1SDimitry Andric const ObjCImplDecl *impDecl) {
21200b57cec5SDimitry Andric for (const auto *propertyImpl : impDecl->property_impls()) {
21210b57cec5SDimitry Andric const auto *property = propertyImpl->getPropertyDecl();
21220b57cec5SDimitry Andric // Warn about null_resettable properties with synthesized setters,
21230b57cec5SDimitry Andric // because the setter won't properly handle nil.
21245ffd83dbSDimitry Andric if (propertyImpl->getPropertyImplementation() ==
21255ffd83dbSDimitry Andric ObjCPropertyImplDecl::Synthesize &&
21260b57cec5SDimitry Andric (property->getPropertyAttributes() &
21275ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_null_resettable) &&
21285ffd83dbSDimitry Andric property->getGetterMethodDecl() && property->getSetterMethodDecl()) {
2129480093f4SDimitry Andric auto *getterImpl = propertyImpl->getGetterMethodDecl();
2130480093f4SDimitry Andric auto *setterImpl = propertyImpl->getSetterMethodDecl();
2131480093f4SDimitry Andric if ((!getterImpl || getterImpl->isSynthesizedAccessorStub()) &&
2132480093f4SDimitry Andric (!setterImpl || setterImpl->isSynthesizedAccessorStub())) {
21330b57cec5SDimitry Andric SourceLocation loc = propertyImpl->getLocation();
21340b57cec5SDimitry Andric if (loc.isInvalid())
21350b57cec5SDimitry Andric loc = impDecl->getBeginLoc();
21360b57cec5SDimitry Andric
21370b57cec5SDimitry Andric Diag(loc, diag::warn_null_resettable_setter)
2138480093f4SDimitry Andric << setterImpl->getSelector() << property->getDeclName();
21390b57cec5SDimitry Andric }
21400b57cec5SDimitry Andric }
21410b57cec5SDimitry Andric }
21420b57cec5SDimitry Andric }
21430b57cec5SDimitry Andric
AtomicPropertySetterGetterRules(ObjCImplDecl * IMPDecl,ObjCInterfaceDecl * IDecl)2144*0fca6ea1SDimitry Andric void SemaObjC::AtomicPropertySetterGetterRules(ObjCImplDecl *IMPDecl,
21450b57cec5SDimitry Andric ObjCInterfaceDecl *IDecl) {
21460b57cec5SDimitry Andric // Rules apply in non-GC mode only
21470b57cec5SDimitry Andric if (getLangOpts().getGC() != LangOptions::NonGC)
21480b57cec5SDimitry Andric return;
21490b57cec5SDimitry Andric ObjCContainerDecl::PropertyMap PM;
21500b57cec5SDimitry Andric for (auto *Prop : IDecl->properties())
21510b57cec5SDimitry Andric PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop;
21520b57cec5SDimitry Andric for (const auto *Ext : IDecl->known_extensions())
21530b57cec5SDimitry Andric for (auto *Prop : Ext->properties())
21540b57cec5SDimitry Andric PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop;
21550b57cec5SDimitry Andric
21560b57cec5SDimitry Andric for (ObjCContainerDecl::PropertyMap::iterator I = PM.begin(), E = PM.end();
21570b57cec5SDimitry Andric I != E; ++I) {
21580b57cec5SDimitry Andric const ObjCPropertyDecl *Property = I->second;
21590b57cec5SDimitry Andric ObjCMethodDecl *GetterMethod = nullptr;
21600b57cec5SDimitry Andric ObjCMethodDecl *SetterMethod = nullptr;
21610b57cec5SDimitry Andric
21620b57cec5SDimitry Andric unsigned Attributes = Property->getPropertyAttributes();
21630b57cec5SDimitry Andric unsigned AttributesAsWritten = Property->getPropertyAttributesAsWritten();
21640b57cec5SDimitry Andric
21655ffd83dbSDimitry Andric if (!(AttributesAsWritten & ObjCPropertyAttribute::kind_atomic) &&
21665ffd83dbSDimitry Andric !(AttributesAsWritten & ObjCPropertyAttribute::kind_nonatomic)) {
21670b57cec5SDimitry Andric GetterMethod = Property->isClassProperty() ?
21680b57cec5SDimitry Andric IMPDecl->getClassMethod(Property->getGetterName()) :
21690b57cec5SDimitry Andric IMPDecl->getInstanceMethod(Property->getGetterName());
21700b57cec5SDimitry Andric SetterMethod = Property->isClassProperty() ?
21710b57cec5SDimitry Andric IMPDecl->getClassMethod(Property->getSetterName()) :
21720b57cec5SDimitry Andric IMPDecl->getInstanceMethod(Property->getSetterName());
2173480093f4SDimitry Andric if (GetterMethod && GetterMethod->isSynthesizedAccessorStub())
2174480093f4SDimitry Andric GetterMethod = nullptr;
2175480093f4SDimitry Andric if (SetterMethod && SetterMethod->isSynthesizedAccessorStub())
2176480093f4SDimitry Andric SetterMethod = nullptr;
21770b57cec5SDimitry Andric if (GetterMethod) {
21780b57cec5SDimitry Andric Diag(GetterMethod->getLocation(),
21790b57cec5SDimitry Andric diag::warn_default_atomic_custom_getter_setter)
21800b57cec5SDimitry Andric << Property->getIdentifier() << 0;
21810b57cec5SDimitry Andric Diag(Property->getLocation(), diag::note_property_declare);
21820b57cec5SDimitry Andric }
21830b57cec5SDimitry Andric if (SetterMethod) {
21840b57cec5SDimitry Andric Diag(SetterMethod->getLocation(),
21850b57cec5SDimitry Andric diag::warn_default_atomic_custom_getter_setter)
21860b57cec5SDimitry Andric << Property->getIdentifier() << 1;
21870b57cec5SDimitry Andric Diag(Property->getLocation(), diag::note_property_declare);
21880b57cec5SDimitry Andric }
21890b57cec5SDimitry Andric }
21900b57cec5SDimitry Andric
21910b57cec5SDimitry Andric // We only care about readwrite atomic property.
21925ffd83dbSDimitry Andric if ((Attributes & ObjCPropertyAttribute::kind_nonatomic) ||
21935ffd83dbSDimitry Andric !(Attributes & ObjCPropertyAttribute::kind_readwrite))
21940b57cec5SDimitry Andric continue;
21950b57cec5SDimitry Andric if (const ObjCPropertyImplDecl *PIDecl = IMPDecl->FindPropertyImplDecl(
21960b57cec5SDimitry Andric Property->getIdentifier(), Property->getQueryKind())) {
21970b57cec5SDimitry Andric if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
21980b57cec5SDimitry Andric continue;
2199480093f4SDimitry Andric GetterMethod = PIDecl->getGetterMethodDecl();
2200480093f4SDimitry Andric SetterMethod = PIDecl->getSetterMethodDecl();
2201480093f4SDimitry Andric if (GetterMethod && GetterMethod->isSynthesizedAccessorStub())
2202480093f4SDimitry Andric GetterMethod = nullptr;
2203480093f4SDimitry Andric if (SetterMethod && SetterMethod->isSynthesizedAccessorStub())
2204480093f4SDimitry Andric SetterMethod = nullptr;
2205480093f4SDimitry Andric if ((bool)GetterMethod ^ (bool)SetterMethod) {
22060b57cec5SDimitry Andric SourceLocation MethodLoc =
22070b57cec5SDimitry Andric (GetterMethod ? GetterMethod->getLocation()
22080b57cec5SDimitry Andric : SetterMethod->getLocation());
22090b57cec5SDimitry Andric Diag(MethodLoc, diag::warn_atomic_property_rule)
22100b57cec5SDimitry Andric << Property->getIdentifier() << (GetterMethod != nullptr)
22110b57cec5SDimitry Andric << (SetterMethod != nullptr);
22120b57cec5SDimitry Andric // fixit stuff.
22130b57cec5SDimitry Andric if (Property->getLParenLoc().isValid() &&
22145ffd83dbSDimitry Andric !(AttributesAsWritten & ObjCPropertyAttribute::kind_atomic)) {
22150b57cec5SDimitry Andric // @property () ... case.
22160b57cec5SDimitry Andric SourceLocation AfterLParen =
2217*0fca6ea1SDimitry Andric SemaRef.getLocForEndOfToken(Property->getLParenLoc());
22180b57cec5SDimitry Andric StringRef NonatomicStr = AttributesAsWritten? "nonatomic, "
22190b57cec5SDimitry Andric : "nonatomic";
22200b57cec5SDimitry Andric Diag(Property->getLocation(),
22210b57cec5SDimitry Andric diag::note_atomic_property_fixup_suggest)
22220b57cec5SDimitry Andric << FixItHint::CreateInsertion(AfterLParen, NonatomicStr);
22230b57cec5SDimitry Andric } else if (Property->getLParenLoc().isInvalid()) {
22240b57cec5SDimitry Andric //@property id etc.
22250b57cec5SDimitry Andric SourceLocation startLoc =
22260b57cec5SDimitry Andric Property->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
22270b57cec5SDimitry Andric Diag(Property->getLocation(),
22280b57cec5SDimitry Andric diag::note_atomic_property_fixup_suggest)
22290b57cec5SDimitry Andric << FixItHint::CreateInsertion(startLoc, "(nonatomic) ");
22305ffd83dbSDimitry Andric } else
22310b57cec5SDimitry Andric Diag(MethodLoc, diag::note_atomic_property_fixup_suggest);
22320b57cec5SDimitry Andric Diag(Property->getLocation(), diag::note_property_declare);
22330b57cec5SDimitry Andric }
22340b57cec5SDimitry Andric }
22350b57cec5SDimitry Andric }
22360b57cec5SDimitry Andric }
22370b57cec5SDimitry Andric
DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl * D)2238*0fca6ea1SDimitry Andric void SemaObjC::DiagnoseOwningPropertyGetterSynthesis(
2239*0fca6ea1SDimitry Andric const ObjCImplementationDecl *D) {
22400b57cec5SDimitry Andric if (getLangOpts().getGC() == LangOptions::GCOnly)
22410b57cec5SDimitry Andric return;
22420b57cec5SDimitry Andric
22430b57cec5SDimitry Andric for (const auto *PID : D->property_impls()) {
22440b57cec5SDimitry Andric const ObjCPropertyDecl *PD = PID->getPropertyDecl();
22450b57cec5SDimitry Andric if (PD && !PD->hasAttr<NSReturnsNotRetainedAttr>() &&
2246480093f4SDimitry Andric !PD->isClassProperty()) {
2247480093f4SDimitry Andric ObjCMethodDecl *IM = PID->getGetterMethodDecl();
2248480093f4SDimitry Andric if (IM && !IM->isSynthesizedAccessorStub())
2249480093f4SDimitry Andric continue;
22500b57cec5SDimitry Andric ObjCMethodDecl *method = PD->getGetterMethodDecl();
22510b57cec5SDimitry Andric if (!method)
22520b57cec5SDimitry Andric continue;
22530b57cec5SDimitry Andric ObjCMethodFamily family = method->getMethodFamily();
22540b57cec5SDimitry Andric if (family == OMF_alloc || family == OMF_copy ||
22550b57cec5SDimitry Andric family == OMF_mutableCopy || family == OMF_new) {
22560b57cec5SDimitry Andric if (getLangOpts().ObjCAutoRefCount)
22570b57cec5SDimitry Andric Diag(PD->getLocation(), diag::err_cocoa_naming_owned_rule);
22580b57cec5SDimitry Andric else
22590b57cec5SDimitry Andric Diag(PD->getLocation(), diag::warn_cocoa_naming_owned_rule);
22600b57cec5SDimitry Andric
22610b57cec5SDimitry Andric // Look for a getter explicitly declared alongside the property.
22620b57cec5SDimitry Andric // If we find one, use its location for the note.
22630b57cec5SDimitry Andric SourceLocation noteLoc = PD->getLocation();
22640b57cec5SDimitry Andric SourceLocation fixItLoc;
22650b57cec5SDimitry Andric for (auto *getterRedecl : method->redecls()) {
22660b57cec5SDimitry Andric if (getterRedecl->isImplicit())
22670b57cec5SDimitry Andric continue;
22680b57cec5SDimitry Andric if (getterRedecl->getDeclContext() != PD->getDeclContext())
22690b57cec5SDimitry Andric continue;
22700b57cec5SDimitry Andric noteLoc = getterRedecl->getLocation();
22710b57cec5SDimitry Andric fixItLoc = getterRedecl->getEndLoc();
22720b57cec5SDimitry Andric }
22730b57cec5SDimitry Andric
2274*0fca6ea1SDimitry Andric Preprocessor &PP = SemaRef.getPreprocessor();
22750b57cec5SDimitry Andric TokenValue tokens[] = {
22760b57cec5SDimitry Andric tok::kw___attribute, tok::l_paren, tok::l_paren,
22770b57cec5SDimitry Andric PP.getIdentifierInfo("objc_method_family"), tok::l_paren,
22780b57cec5SDimitry Andric PP.getIdentifierInfo("none"), tok::r_paren,
22790b57cec5SDimitry Andric tok::r_paren, tok::r_paren
22800b57cec5SDimitry Andric };
22810b57cec5SDimitry Andric StringRef spelling = "__attribute__((objc_method_family(none)))";
22820b57cec5SDimitry Andric StringRef macroName = PP.getLastMacroWithSpelling(noteLoc, tokens);
22830b57cec5SDimitry Andric if (!macroName.empty())
22840b57cec5SDimitry Andric spelling = macroName;
22850b57cec5SDimitry Andric
22860b57cec5SDimitry Andric auto noteDiag = Diag(noteLoc, diag::note_cocoa_naming_declare_family)
22870b57cec5SDimitry Andric << method->getDeclName() << spelling;
22880b57cec5SDimitry Andric if (fixItLoc.isValid()) {
22890b57cec5SDimitry Andric SmallString<64> fixItText(" ");
22900b57cec5SDimitry Andric fixItText += spelling;
22910b57cec5SDimitry Andric noteDiag << FixItHint::CreateInsertion(fixItLoc, fixItText);
22920b57cec5SDimitry Andric }
22930b57cec5SDimitry Andric }
22940b57cec5SDimitry Andric }
22950b57cec5SDimitry Andric }
22960b57cec5SDimitry Andric }
22970b57cec5SDimitry Andric
DiagnoseMissingDesignatedInitOverrides(const ObjCImplementationDecl * ImplD,const ObjCInterfaceDecl * IFD)2298*0fca6ea1SDimitry Andric void SemaObjC::DiagnoseMissingDesignatedInitOverrides(
2299*0fca6ea1SDimitry Andric const ObjCImplementationDecl *ImplD, const ObjCInterfaceDecl *IFD) {
23000b57cec5SDimitry Andric assert(IFD->hasDesignatedInitializers());
23010b57cec5SDimitry Andric const ObjCInterfaceDecl *SuperD = IFD->getSuperClass();
23020b57cec5SDimitry Andric if (!SuperD)
23030b57cec5SDimitry Andric return;
23040b57cec5SDimitry Andric
23050b57cec5SDimitry Andric SelectorSet InitSelSet;
23060b57cec5SDimitry Andric for (const auto *I : ImplD->instance_methods())
23070b57cec5SDimitry Andric if (I->getMethodFamily() == OMF_init)
23080b57cec5SDimitry Andric InitSelSet.insert(I->getSelector());
23090b57cec5SDimitry Andric
23100b57cec5SDimitry Andric SmallVector<const ObjCMethodDecl *, 8> DesignatedInits;
23110b57cec5SDimitry Andric SuperD->getDesignatedInitializers(DesignatedInits);
23120b57cec5SDimitry Andric for (SmallVector<const ObjCMethodDecl *, 8>::iterator
23130b57cec5SDimitry Andric I = DesignatedInits.begin(), E = DesignatedInits.end(); I != E; ++I) {
23140b57cec5SDimitry Andric const ObjCMethodDecl *MD = *I;
23150b57cec5SDimitry Andric if (!InitSelSet.count(MD->getSelector())) {
23160b57cec5SDimitry Andric // Don't emit a diagnostic if the overriding method in the subclass is
23170b57cec5SDimitry Andric // marked as unavailable.
23180b57cec5SDimitry Andric bool Ignore = false;
23190b57cec5SDimitry Andric if (auto *IMD = IFD->getInstanceMethod(MD->getSelector())) {
23200b57cec5SDimitry Andric Ignore = IMD->isUnavailable();
23210b57cec5SDimitry Andric } else {
23220b57cec5SDimitry Andric // Check the methods declared in the class extensions too.
23230b57cec5SDimitry Andric for (auto *Ext : IFD->visible_extensions())
23240b57cec5SDimitry Andric if (auto *IMD = Ext->getInstanceMethod(MD->getSelector())) {
23250b57cec5SDimitry Andric Ignore = IMD->isUnavailable();
23260b57cec5SDimitry Andric break;
23270b57cec5SDimitry Andric }
23280b57cec5SDimitry Andric }
23290b57cec5SDimitry Andric if (!Ignore) {
23300b57cec5SDimitry Andric Diag(ImplD->getLocation(),
23310b57cec5SDimitry Andric diag::warn_objc_implementation_missing_designated_init_override)
23320b57cec5SDimitry Andric << MD->getSelector();
23330b57cec5SDimitry Andric Diag(MD->getLocation(), diag::note_objc_designated_init_marked_here);
23340b57cec5SDimitry Andric }
23350b57cec5SDimitry Andric }
23360b57cec5SDimitry Andric }
23370b57cec5SDimitry Andric }
23380b57cec5SDimitry Andric
23390b57cec5SDimitry Andric /// AddPropertyAttrs - Propagates attributes from a property to the
23400b57cec5SDimitry Andric /// implicitly-declared getter or setter for that property.
AddPropertyAttrs(Sema & S,ObjCMethodDecl * PropertyMethod,ObjCPropertyDecl * Property)23410b57cec5SDimitry Andric static void AddPropertyAttrs(Sema &S, ObjCMethodDecl *PropertyMethod,
23420b57cec5SDimitry Andric ObjCPropertyDecl *Property) {
23430b57cec5SDimitry Andric // Should we just clone all attributes over?
23440b57cec5SDimitry Andric for (const auto *A : Property->attrs()) {
23450b57cec5SDimitry Andric if (isa<DeprecatedAttr>(A) ||
23460b57cec5SDimitry Andric isa<UnavailableAttr>(A) ||
23470b57cec5SDimitry Andric isa<AvailabilityAttr>(A))
23480b57cec5SDimitry Andric PropertyMethod->addAttr(A->clone(S.Context));
23490b57cec5SDimitry Andric }
23500b57cec5SDimitry Andric }
23510b57cec5SDimitry Andric
23520b57cec5SDimitry Andric /// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods
23530b57cec5SDimitry Andric /// have the property type and issue diagnostics if they don't.
23540b57cec5SDimitry Andric /// Also synthesize a getter/setter method if none exist (and update the
23550b57cec5SDimitry Andric /// appropriate lookup tables.
ProcessPropertyDecl(ObjCPropertyDecl * property)2356*0fca6ea1SDimitry Andric void SemaObjC::ProcessPropertyDecl(ObjCPropertyDecl *property) {
2357*0fca6ea1SDimitry Andric ASTContext &Context = getASTContext();
23580b57cec5SDimitry Andric ObjCMethodDecl *GetterMethod, *SetterMethod;
23590b57cec5SDimitry Andric ObjCContainerDecl *CD = cast<ObjCContainerDecl>(property->getDeclContext());
23600b57cec5SDimitry Andric if (CD->isInvalidDecl())
23610b57cec5SDimitry Andric return;
23620b57cec5SDimitry Andric
23630b57cec5SDimitry Andric bool IsClassProperty = property->isClassProperty();
23640b57cec5SDimitry Andric GetterMethod = IsClassProperty ?
23650b57cec5SDimitry Andric CD->getClassMethod(property->getGetterName()) :
23660b57cec5SDimitry Andric CD->getInstanceMethod(property->getGetterName());
23670b57cec5SDimitry Andric
23680b57cec5SDimitry Andric // if setter or getter is not found in class extension, it might be
23690b57cec5SDimitry Andric // in the primary class.
23700b57cec5SDimitry Andric if (!GetterMethod)
23710b57cec5SDimitry Andric if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD))
23720b57cec5SDimitry Andric if (CatDecl->IsClassExtension())
23730b57cec5SDimitry Andric GetterMethod = IsClassProperty ? CatDecl->getClassInterface()->
23740b57cec5SDimitry Andric getClassMethod(property->getGetterName()) :
23750b57cec5SDimitry Andric CatDecl->getClassInterface()->
23760b57cec5SDimitry Andric getInstanceMethod(property->getGetterName());
23770b57cec5SDimitry Andric
23780b57cec5SDimitry Andric SetterMethod = IsClassProperty ?
23790b57cec5SDimitry Andric CD->getClassMethod(property->getSetterName()) :
23800b57cec5SDimitry Andric CD->getInstanceMethod(property->getSetterName());
23810b57cec5SDimitry Andric if (!SetterMethod)
23820b57cec5SDimitry Andric if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD))
23830b57cec5SDimitry Andric if (CatDecl->IsClassExtension())
23840b57cec5SDimitry Andric SetterMethod = IsClassProperty ? CatDecl->getClassInterface()->
23850b57cec5SDimitry Andric getClassMethod(property->getSetterName()) :
23860b57cec5SDimitry Andric CatDecl->getClassInterface()->
23870b57cec5SDimitry Andric getInstanceMethod(property->getSetterName());
23880b57cec5SDimitry Andric DiagnosePropertyAccessorMismatch(property, GetterMethod,
23890b57cec5SDimitry Andric property->getLocation());
23900b57cec5SDimitry Andric
23915ffd83dbSDimitry Andric // synthesizing accessors must not result in a direct method that is not
23925ffd83dbSDimitry Andric // monomorphic
23935ffd83dbSDimitry Andric if (!GetterMethod) {
23945ffd83dbSDimitry Andric if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD)) {
23955ffd83dbSDimitry Andric auto *ExistingGetter = CatDecl->getClassInterface()->lookupMethod(
23965ffd83dbSDimitry Andric property->getGetterName(), !IsClassProperty, true, false, CatDecl);
23975ffd83dbSDimitry Andric if (ExistingGetter) {
23985ffd83dbSDimitry Andric if (ExistingGetter->isDirectMethod() || property->isDirectProperty()) {
23995ffd83dbSDimitry Andric Diag(property->getLocation(), diag::err_objc_direct_duplicate_decl)
24005ffd83dbSDimitry Andric << property->isDirectProperty() << 1 /* property */
24015ffd83dbSDimitry Andric << ExistingGetter->isDirectMethod()
24025ffd83dbSDimitry Andric << ExistingGetter->getDeclName();
24035ffd83dbSDimitry Andric Diag(ExistingGetter->getLocation(), diag::note_previous_declaration);
24045ffd83dbSDimitry Andric }
24055ffd83dbSDimitry Andric }
24065ffd83dbSDimitry Andric }
24075ffd83dbSDimitry Andric }
24085ffd83dbSDimitry Andric
24095ffd83dbSDimitry Andric if (!property->isReadOnly() && !SetterMethod) {
24105ffd83dbSDimitry Andric if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD)) {
24115ffd83dbSDimitry Andric auto *ExistingSetter = CatDecl->getClassInterface()->lookupMethod(
24125ffd83dbSDimitry Andric property->getSetterName(), !IsClassProperty, true, false, CatDecl);
24135ffd83dbSDimitry Andric if (ExistingSetter) {
24145ffd83dbSDimitry Andric if (ExistingSetter->isDirectMethod() || property->isDirectProperty()) {
24155ffd83dbSDimitry Andric Diag(property->getLocation(), diag::err_objc_direct_duplicate_decl)
24165ffd83dbSDimitry Andric << property->isDirectProperty() << 1 /* property */
24175ffd83dbSDimitry Andric << ExistingSetter->isDirectMethod()
24185ffd83dbSDimitry Andric << ExistingSetter->getDeclName();
24195ffd83dbSDimitry Andric Diag(ExistingSetter->getLocation(), diag::note_previous_declaration);
24205ffd83dbSDimitry Andric }
24215ffd83dbSDimitry Andric }
24225ffd83dbSDimitry Andric }
24235ffd83dbSDimitry Andric }
24245ffd83dbSDimitry Andric
24250b57cec5SDimitry Andric if (!property->isReadOnly() && SetterMethod) {
24260b57cec5SDimitry Andric if (Context.getCanonicalType(SetterMethod->getReturnType()) !=
24270b57cec5SDimitry Andric Context.VoidTy)
24280b57cec5SDimitry Andric Diag(SetterMethod->getLocation(), diag::err_setter_type_void);
24290b57cec5SDimitry Andric if (SetterMethod->param_size() != 1 ||
24300b57cec5SDimitry Andric !Context.hasSameUnqualifiedType(
24310b57cec5SDimitry Andric (*SetterMethod->param_begin())->getType().getNonReferenceType(),
24320b57cec5SDimitry Andric property->getType().getNonReferenceType())) {
24330b57cec5SDimitry Andric Diag(property->getLocation(),
24340b57cec5SDimitry Andric diag::warn_accessor_property_type_mismatch)
24350b57cec5SDimitry Andric << property->getDeclName()
24360b57cec5SDimitry Andric << SetterMethod->getSelector();
24370b57cec5SDimitry Andric Diag(SetterMethod->getLocation(), diag::note_declared_at);
24380b57cec5SDimitry Andric }
24390b57cec5SDimitry Andric }
24400b57cec5SDimitry Andric
24410b57cec5SDimitry Andric // Synthesize getter/setter methods if none exist.
24420b57cec5SDimitry Andric // Find the default getter and if one not found, add one.
24430b57cec5SDimitry Andric // FIXME: The synthesized property we set here is misleading. We almost always
24440b57cec5SDimitry Andric // synthesize these methods unless the user explicitly provided prototypes
24450b57cec5SDimitry Andric // (which is odd, but allowed). Sema should be typechecking that the
24460b57cec5SDimitry Andric // declarations jive in that situation (which it is not currently).
24470b57cec5SDimitry Andric if (!GetterMethod) {
24480b57cec5SDimitry Andric // No instance/class method of same name as property getter name was found.
24490b57cec5SDimitry Andric // Declare a getter method and add it to the list of methods
24500b57cec5SDimitry Andric // for this class.
24510b57cec5SDimitry Andric SourceLocation Loc = property->getLocation();
24520b57cec5SDimitry Andric
24530b57cec5SDimitry Andric // The getter returns the declared property type with all qualifiers
24540b57cec5SDimitry Andric // removed.
24550b57cec5SDimitry Andric QualType resultTy = property->getType().getAtomicUnqualifiedType();
24560b57cec5SDimitry Andric
24570b57cec5SDimitry Andric // If the property is null_resettable, the getter returns nonnull.
24580b57cec5SDimitry Andric if (property->getPropertyAttributes() &
24595ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_null_resettable) {
24600b57cec5SDimitry Andric QualType modifiedTy = resultTy;
24610b57cec5SDimitry Andric if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)) {
24620b57cec5SDimitry Andric if (*nullability == NullabilityKind::Unspecified)
24630b57cec5SDimitry Andric resultTy = Context.getAttributedType(attr::TypeNonNull,
24640b57cec5SDimitry Andric modifiedTy, modifiedTy);
24650b57cec5SDimitry Andric }
24660b57cec5SDimitry Andric }
24670b57cec5SDimitry Andric
2468480093f4SDimitry Andric GetterMethod = ObjCMethodDecl::Create(
2469480093f4SDimitry Andric Context, Loc, Loc, property->getGetterName(), resultTy, nullptr, CD,
24700b57cec5SDimitry Andric !IsClassProperty, /*isVariadic=*/false,
2471480093f4SDimitry Andric /*isPropertyAccessor=*/true, /*isSynthesizedAccessorStub=*/false,
24720b57cec5SDimitry Andric /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
2473480093f4SDimitry Andric (property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
24745f757f3fSDimitry Andric ? ObjCImplementationControl::Optional
24755f757f3fSDimitry Andric : ObjCImplementationControl::Required);
24760b57cec5SDimitry Andric CD->addDecl(GetterMethod);
24770b57cec5SDimitry Andric
2478*0fca6ea1SDimitry Andric AddPropertyAttrs(SemaRef, GetterMethod, property);
24790b57cec5SDimitry Andric
2480480093f4SDimitry Andric if (property->isDirectProperty())
2481480093f4SDimitry Andric GetterMethod->addAttr(ObjCDirectAttr::CreateImplicit(Context, Loc));
2482480093f4SDimitry Andric
24830b57cec5SDimitry Andric if (property->hasAttr<NSReturnsNotRetainedAttr>())
24840b57cec5SDimitry Andric GetterMethod->addAttr(NSReturnsNotRetainedAttr::CreateImplicit(Context,
24850b57cec5SDimitry Andric Loc));
24860b57cec5SDimitry Andric
24870b57cec5SDimitry Andric if (property->hasAttr<ObjCReturnsInnerPointerAttr>())
24880b57cec5SDimitry Andric GetterMethod->addAttr(
24890b57cec5SDimitry Andric ObjCReturnsInnerPointerAttr::CreateImplicit(Context, Loc));
24900b57cec5SDimitry Andric
24910b57cec5SDimitry Andric if (const SectionAttr *SA = property->getAttr<SectionAttr>())
2492a7dea167SDimitry Andric GetterMethod->addAttr(SectionAttr::CreateImplicit(
249306c3fb27SDimitry Andric Context, SA->getName(), Loc, SectionAttr::GNU_section));
24940b57cec5SDimitry Andric
2495*0fca6ea1SDimitry Andric SemaRef.ProcessAPINotes(GetterMethod);
2496*0fca6ea1SDimitry Andric
24970b57cec5SDimitry Andric if (getLangOpts().ObjCAutoRefCount)
24980b57cec5SDimitry Andric CheckARCMethodDecl(GetterMethod);
24990b57cec5SDimitry Andric } else
25000b57cec5SDimitry Andric // A user declared getter will be synthesize when @synthesize of
25010b57cec5SDimitry Andric // the property with the same name is seen in the @implementation
25020b57cec5SDimitry Andric GetterMethod->setPropertyAccessor(true);
2503480093f4SDimitry Andric
2504480093f4SDimitry Andric GetterMethod->createImplicitParams(Context,
2505480093f4SDimitry Andric GetterMethod->getClassInterface());
25060b57cec5SDimitry Andric property->setGetterMethodDecl(GetterMethod);
25070b57cec5SDimitry Andric
25080b57cec5SDimitry Andric // Skip setter if property is read-only.
25090b57cec5SDimitry Andric if (!property->isReadOnly()) {
25100b57cec5SDimitry Andric // Find the default setter and if one not found, add one.
25110b57cec5SDimitry Andric if (!SetterMethod) {
25120b57cec5SDimitry Andric // No instance/class method of same name as property setter name was
25130b57cec5SDimitry Andric // found.
25140b57cec5SDimitry Andric // Declare a setter method and add it to the list of methods
25150b57cec5SDimitry Andric // for this class.
25160b57cec5SDimitry Andric SourceLocation Loc = property->getLocation();
25170b57cec5SDimitry Andric
25185f757f3fSDimitry Andric SetterMethod = ObjCMethodDecl::Create(
25195f757f3fSDimitry Andric Context, Loc, Loc, property->getSetterName(), Context.VoidTy, nullptr,
25205f757f3fSDimitry Andric CD, !IsClassProperty,
25210b57cec5SDimitry Andric /*isVariadic=*/false,
25220b57cec5SDimitry Andric /*isPropertyAccessor=*/true,
2523480093f4SDimitry Andric /*isSynthesizedAccessorStub=*/false,
25240b57cec5SDimitry Andric /*isImplicitlyDeclared=*/true,
25250b57cec5SDimitry Andric /*isDefined=*/false,
25265f757f3fSDimitry Andric (property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
25275f757f3fSDimitry Andric ? ObjCImplementationControl::Optional
25285f757f3fSDimitry Andric : ObjCImplementationControl::Required);
25290b57cec5SDimitry Andric
25300b57cec5SDimitry Andric // Remove all qualifiers from the setter's parameter type.
25310b57cec5SDimitry Andric QualType paramTy =
25320b57cec5SDimitry Andric property->getType().getUnqualifiedType().getAtomicUnqualifiedType();
25330b57cec5SDimitry Andric
25340b57cec5SDimitry Andric // If the property is null_resettable, the setter accepts a
25350b57cec5SDimitry Andric // nullable value.
25360b57cec5SDimitry Andric if (property->getPropertyAttributes() &
25375ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_null_resettable) {
25380b57cec5SDimitry Andric QualType modifiedTy = paramTy;
25390b57cec5SDimitry Andric if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)){
25400b57cec5SDimitry Andric if (*nullability == NullabilityKind::Unspecified)
25410b57cec5SDimitry Andric paramTy = Context.getAttributedType(attr::TypeNullable,
25420b57cec5SDimitry Andric modifiedTy, modifiedTy);
25430b57cec5SDimitry Andric }
25440b57cec5SDimitry Andric }
25450b57cec5SDimitry Andric
25460b57cec5SDimitry Andric // Invent the arguments for the setter. We don't bother making a
25470b57cec5SDimitry Andric // nice name for the argument.
25480b57cec5SDimitry Andric ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod,
25490b57cec5SDimitry Andric Loc, Loc,
25500b57cec5SDimitry Andric property->getIdentifier(),
25510b57cec5SDimitry Andric paramTy,
25520b57cec5SDimitry Andric /*TInfo=*/nullptr,
25530b57cec5SDimitry Andric SC_None,
25540b57cec5SDimitry Andric nullptr);
2555bdd1243dSDimitry Andric SetterMethod->setMethodParams(Context, Argument, std::nullopt);
25560b57cec5SDimitry Andric
2557*0fca6ea1SDimitry Andric AddPropertyAttrs(SemaRef, SetterMethod, property);
25580b57cec5SDimitry Andric
2559480093f4SDimitry Andric if (property->isDirectProperty())
2560480093f4SDimitry Andric SetterMethod->addAttr(ObjCDirectAttr::CreateImplicit(Context, Loc));
2561480093f4SDimitry Andric
25620b57cec5SDimitry Andric CD->addDecl(SetterMethod);
25630b57cec5SDimitry Andric if (const SectionAttr *SA = property->getAttr<SectionAttr>())
2564a7dea167SDimitry Andric SetterMethod->addAttr(SectionAttr::CreateImplicit(
256506c3fb27SDimitry Andric Context, SA->getName(), Loc, SectionAttr::GNU_section));
2566*0fca6ea1SDimitry Andric
2567*0fca6ea1SDimitry Andric SemaRef.ProcessAPINotes(SetterMethod);
2568*0fca6ea1SDimitry Andric
25690b57cec5SDimitry Andric // It's possible for the user to have set a very odd custom
25700b57cec5SDimitry Andric // setter selector that causes it to have a method family.
25710b57cec5SDimitry Andric if (getLangOpts().ObjCAutoRefCount)
25720b57cec5SDimitry Andric CheckARCMethodDecl(SetterMethod);
25730b57cec5SDimitry Andric } else
25740b57cec5SDimitry Andric // A user declared setter will be synthesize when @synthesize of
25750b57cec5SDimitry Andric // the property with the same name is seen in the @implementation
25760b57cec5SDimitry Andric SetterMethod->setPropertyAccessor(true);
2577480093f4SDimitry Andric
2578480093f4SDimitry Andric SetterMethod->createImplicitParams(Context,
2579480093f4SDimitry Andric SetterMethod->getClassInterface());
25800b57cec5SDimitry Andric property->setSetterMethodDecl(SetterMethod);
25810b57cec5SDimitry Andric }
25820b57cec5SDimitry Andric // Add any synthesized methods to the global pool. This allows us to
25830b57cec5SDimitry Andric // handle the following, which is supported by GCC (and part of the design).
25840b57cec5SDimitry Andric //
25850b57cec5SDimitry Andric // @interface Foo
25860b57cec5SDimitry Andric // @property double bar;
25870b57cec5SDimitry Andric // @end
25880b57cec5SDimitry Andric //
25890b57cec5SDimitry Andric // void thisIsUnfortunate() {
25900b57cec5SDimitry Andric // id foo;
25910b57cec5SDimitry Andric // double bar = [foo bar];
25920b57cec5SDimitry Andric // }
25930b57cec5SDimitry Andric //
25940b57cec5SDimitry Andric if (!IsClassProperty) {
25950b57cec5SDimitry Andric if (GetterMethod)
25960b57cec5SDimitry Andric AddInstanceMethodToGlobalPool(GetterMethod);
25970b57cec5SDimitry Andric if (SetterMethod)
25980b57cec5SDimitry Andric AddInstanceMethodToGlobalPool(SetterMethod);
25990b57cec5SDimitry Andric } else {
26000b57cec5SDimitry Andric if (GetterMethod)
26010b57cec5SDimitry Andric AddFactoryMethodToGlobalPool(GetterMethod);
26020b57cec5SDimitry Andric if (SetterMethod)
26030b57cec5SDimitry Andric AddFactoryMethodToGlobalPool(SetterMethod);
26040b57cec5SDimitry Andric }
26050b57cec5SDimitry Andric
26060b57cec5SDimitry Andric ObjCInterfaceDecl *CurrentClass = dyn_cast<ObjCInterfaceDecl>(CD);
26070b57cec5SDimitry Andric if (!CurrentClass) {
26080b57cec5SDimitry Andric if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(CD))
26090b57cec5SDimitry Andric CurrentClass = Cat->getClassInterface();
26100b57cec5SDimitry Andric else if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(CD))
26110b57cec5SDimitry Andric CurrentClass = Impl->getClassInterface();
26120b57cec5SDimitry Andric }
26130b57cec5SDimitry Andric if (GetterMethod)
2614*0fca6ea1SDimitry Andric CheckObjCMethodOverrides(GetterMethod, CurrentClass, SemaObjC::RTC_Unknown);
26150b57cec5SDimitry Andric if (SetterMethod)
2616*0fca6ea1SDimitry Andric CheckObjCMethodOverrides(SetterMethod, CurrentClass, SemaObjC::RTC_Unknown);
26170b57cec5SDimitry Andric }
26180b57cec5SDimitry Andric
CheckObjCPropertyAttributes(Decl * PDecl,SourceLocation Loc,unsigned & Attributes,bool propertyInPrimaryClass)2619*0fca6ea1SDimitry Andric void SemaObjC::CheckObjCPropertyAttributes(Decl *PDecl, SourceLocation Loc,
26200b57cec5SDimitry Andric unsigned &Attributes,
26210b57cec5SDimitry Andric bool propertyInPrimaryClass) {
26220b57cec5SDimitry Andric // FIXME: Improve the reported location.
26230b57cec5SDimitry Andric if (!PDecl || PDecl->isInvalidDecl())
26240b57cec5SDimitry Andric return;
26250b57cec5SDimitry Andric
26265ffd83dbSDimitry Andric if ((Attributes & ObjCPropertyAttribute::kind_readonly) &&
26275ffd83dbSDimitry Andric (Attributes & ObjCPropertyAttribute::kind_readwrite))
26280b57cec5SDimitry Andric Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
26290b57cec5SDimitry Andric << "readonly" << "readwrite";
26300b57cec5SDimitry Andric
26310b57cec5SDimitry Andric ObjCPropertyDecl *PropertyDecl = cast<ObjCPropertyDecl>(PDecl);
26320b57cec5SDimitry Andric QualType PropertyTy = PropertyDecl->getType();
26330b57cec5SDimitry Andric
26340b57cec5SDimitry Andric // Check for copy or retain on non-object types.
26355ffd83dbSDimitry Andric if ((Attributes &
26365ffd83dbSDimitry Andric (ObjCPropertyAttribute::kind_weak | ObjCPropertyAttribute::kind_copy |
26375ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_retain |
26385ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_strong)) &&
26390b57cec5SDimitry Andric !PropertyTy->isObjCRetainableType() &&
26400b57cec5SDimitry Andric !PropertyDecl->hasAttr<ObjCNSObjectAttr>()) {
26410b57cec5SDimitry Andric Diag(Loc, diag::err_objc_property_requires_object)
26425ffd83dbSDimitry Andric << (Attributes & ObjCPropertyAttribute::kind_weak
26435ffd83dbSDimitry Andric ? "weak"
26445ffd83dbSDimitry Andric : Attributes & ObjCPropertyAttribute::kind_copy
26455ffd83dbSDimitry Andric ? "copy"
26465ffd83dbSDimitry Andric : "retain (or strong)");
26475ffd83dbSDimitry Andric Attributes &=
26485ffd83dbSDimitry Andric ~(ObjCPropertyAttribute::kind_weak | ObjCPropertyAttribute::kind_copy |
26495ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_retain |
26505ffd83dbSDimitry Andric ObjCPropertyAttribute::kind_strong);
26510b57cec5SDimitry Andric PropertyDecl->setInvalidDecl();
26520b57cec5SDimitry Andric }
26530b57cec5SDimitry Andric
26540b57cec5SDimitry Andric // Check for assign on object types.
26555ffd83dbSDimitry Andric if ((Attributes & ObjCPropertyAttribute::kind_assign) &&
26565ffd83dbSDimitry Andric !(Attributes & ObjCPropertyAttribute::kind_unsafe_unretained) &&
26570b57cec5SDimitry Andric PropertyTy->isObjCRetainableType() &&
26580b57cec5SDimitry Andric !PropertyTy->isObjCARCImplicitlyUnretainedType()) {
26590b57cec5SDimitry Andric Diag(Loc, diag::warn_objc_property_assign_on_object);
26600b57cec5SDimitry Andric }
26610b57cec5SDimitry Andric
26620b57cec5SDimitry Andric // Check for more than one of { assign, copy, retain }.
26635ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_assign) {
26645ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_copy) {
26650b57cec5SDimitry Andric Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
26660b57cec5SDimitry Andric << "assign" << "copy";
26675ffd83dbSDimitry Andric Attributes &= ~ObjCPropertyAttribute::kind_copy;
26680b57cec5SDimitry Andric }
26695ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_retain) {
26700b57cec5SDimitry Andric Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
26710b57cec5SDimitry Andric << "assign" << "retain";
26725ffd83dbSDimitry Andric Attributes &= ~ObjCPropertyAttribute::kind_retain;
26730b57cec5SDimitry Andric }
26745ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_strong) {
26750b57cec5SDimitry Andric Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
26760b57cec5SDimitry Andric << "assign" << "strong";
26775ffd83dbSDimitry Andric Attributes &= ~ObjCPropertyAttribute::kind_strong;
26780b57cec5SDimitry Andric }
26790b57cec5SDimitry Andric if (getLangOpts().ObjCAutoRefCount &&
26805ffd83dbSDimitry Andric (Attributes & ObjCPropertyAttribute::kind_weak)) {
26810b57cec5SDimitry Andric Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
26820b57cec5SDimitry Andric << "assign" << "weak";
26835ffd83dbSDimitry Andric Attributes &= ~ObjCPropertyAttribute::kind_weak;
26840b57cec5SDimitry Andric }
26850b57cec5SDimitry Andric if (PropertyDecl->hasAttr<IBOutletCollectionAttr>())
26860b57cec5SDimitry Andric Diag(Loc, diag::warn_iboutletcollection_property_assign);
26875ffd83dbSDimitry Andric } else if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained) {
26885ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_copy) {
26890b57cec5SDimitry Andric Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
26900b57cec5SDimitry Andric << "unsafe_unretained" << "copy";
26915ffd83dbSDimitry Andric Attributes &= ~ObjCPropertyAttribute::kind_copy;
26920b57cec5SDimitry Andric }
26935ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_retain) {
26940b57cec5SDimitry Andric Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
26950b57cec5SDimitry Andric << "unsafe_unretained" << "retain";
26965ffd83dbSDimitry Andric Attributes &= ~ObjCPropertyAttribute::kind_retain;
26970b57cec5SDimitry Andric }
26985ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_strong) {
26990b57cec5SDimitry Andric Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
27000b57cec5SDimitry Andric << "unsafe_unretained" << "strong";
27015ffd83dbSDimitry Andric Attributes &= ~ObjCPropertyAttribute::kind_strong;
27020b57cec5SDimitry Andric }
27030b57cec5SDimitry Andric if (getLangOpts().ObjCAutoRefCount &&
27045ffd83dbSDimitry Andric (Attributes & ObjCPropertyAttribute::kind_weak)) {
27050b57cec5SDimitry Andric Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
27060b57cec5SDimitry Andric << "unsafe_unretained" << "weak";
27075ffd83dbSDimitry Andric Attributes &= ~ObjCPropertyAttribute::kind_weak;
27080b57cec5SDimitry Andric }
27095ffd83dbSDimitry Andric } else if (Attributes & ObjCPropertyAttribute::kind_copy) {
27105ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_retain) {
27110b57cec5SDimitry Andric Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
27120b57cec5SDimitry Andric << "copy" << "retain";
27135ffd83dbSDimitry Andric Attributes &= ~ObjCPropertyAttribute::kind_retain;
27140b57cec5SDimitry Andric }
27155ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_strong) {
27160b57cec5SDimitry Andric Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
27170b57cec5SDimitry Andric << "copy" << "strong";
27185ffd83dbSDimitry Andric Attributes &= ~ObjCPropertyAttribute::kind_strong;
27190b57cec5SDimitry Andric }
27205ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_weak) {
27210b57cec5SDimitry Andric Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
27220b57cec5SDimitry Andric << "copy" << "weak";
27235ffd83dbSDimitry Andric Attributes &= ~ObjCPropertyAttribute::kind_weak;
27240b57cec5SDimitry Andric }
27255ffd83dbSDimitry Andric } else if ((Attributes & ObjCPropertyAttribute::kind_retain) &&
27265ffd83dbSDimitry Andric (Attributes & ObjCPropertyAttribute::kind_weak)) {
27275ffd83dbSDimitry Andric Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "retain"
27285ffd83dbSDimitry Andric << "weak";
27295ffd83dbSDimitry Andric Attributes &= ~ObjCPropertyAttribute::kind_retain;
27305ffd83dbSDimitry Andric } else if ((Attributes & ObjCPropertyAttribute::kind_strong) &&
27315ffd83dbSDimitry Andric (Attributes & ObjCPropertyAttribute::kind_weak)) {
27325ffd83dbSDimitry Andric Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "strong"
27335ffd83dbSDimitry Andric << "weak";
27345ffd83dbSDimitry Andric Attributes &= ~ObjCPropertyAttribute::kind_weak;
27350b57cec5SDimitry Andric }
27360b57cec5SDimitry Andric
27375ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_weak) {
27380b57cec5SDimitry Andric // 'weak' and 'nonnull' are mutually exclusive.
2739bdd1243dSDimitry Andric if (auto nullability = PropertyTy->getNullability()) {
27400b57cec5SDimitry Andric if (*nullability == NullabilityKind::NonNull)
27410b57cec5SDimitry Andric Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
27420b57cec5SDimitry Andric << "nonnull" << "weak";
27430b57cec5SDimitry Andric }
27440b57cec5SDimitry Andric }
27450b57cec5SDimitry Andric
27465ffd83dbSDimitry Andric if ((Attributes & ObjCPropertyAttribute::kind_atomic) &&
27475ffd83dbSDimitry Andric (Attributes & ObjCPropertyAttribute::kind_nonatomic)) {
27485ffd83dbSDimitry Andric Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "atomic"
27495ffd83dbSDimitry Andric << "nonatomic";
27505ffd83dbSDimitry Andric Attributes &= ~ObjCPropertyAttribute::kind_atomic;
27510b57cec5SDimitry Andric }
27520b57cec5SDimitry Andric
27530b57cec5SDimitry Andric // Warn if user supplied no assignment attribute, property is
27540b57cec5SDimitry Andric // readwrite, and this is an object type.
27550b57cec5SDimitry Andric if (!getOwnershipRule(Attributes) && PropertyTy->isObjCRetainableType()) {
27565ffd83dbSDimitry Andric if (Attributes & ObjCPropertyAttribute::kind_readonly) {
27570b57cec5SDimitry Andric // do nothing
27580b57cec5SDimitry Andric } else if (getLangOpts().ObjCAutoRefCount) {
27590b57cec5SDimitry Andric // With arc, @property definitions should default to strong when
27600b57cec5SDimitry Andric // not specified.
27615ffd83dbSDimitry Andric PropertyDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_strong);
27620b57cec5SDimitry Andric } else if (PropertyTy->isObjCObjectPointerType()) {
27635ffd83dbSDimitry Andric bool isAnyClassTy = (PropertyTy->isObjCClassType() ||
27640b57cec5SDimitry Andric PropertyTy->isObjCQualifiedClassType());
27650b57cec5SDimitry Andric // In non-gc, non-arc mode, 'Class' is treated as a 'void *' no need to
27660b57cec5SDimitry Andric // issue any warning.
27670b57cec5SDimitry Andric if (isAnyClassTy && getLangOpts().getGC() == LangOptions::NonGC)
27680b57cec5SDimitry Andric ;
27690b57cec5SDimitry Andric else if (propertyInPrimaryClass) {
27700b57cec5SDimitry Andric // Don't issue warning on property with no life time in class
27710b57cec5SDimitry Andric // extension as it is inherited from property in primary class.
27720b57cec5SDimitry Andric // Skip this warning in gc-only mode.
27730b57cec5SDimitry Andric if (getLangOpts().getGC() != LangOptions::GCOnly)
27740b57cec5SDimitry Andric Diag(Loc, diag::warn_objc_property_no_assignment_attribute);
27750b57cec5SDimitry Andric
27760b57cec5SDimitry Andric // If non-gc code warn that this is likely inappropriate.
27770b57cec5SDimitry Andric if (getLangOpts().getGC() == LangOptions::NonGC)
27780b57cec5SDimitry Andric Diag(Loc, diag::warn_objc_property_default_assign_on_object);
27790b57cec5SDimitry Andric }
27800b57cec5SDimitry Andric }
27810b57cec5SDimitry Andric
27820b57cec5SDimitry Andric // FIXME: Implement warning dependent on NSCopying being
27835f757f3fSDimitry Andric // implemented.
27840b57cec5SDimitry Andric }
27850b57cec5SDimitry Andric
27865ffd83dbSDimitry Andric if (!(Attributes & ObjCPropertyAttribute::kind_copy) &&
27875ffd83dbSDimitry Andric !(Attributes & ObjCPropertyAttribute::kind_readonly) &&
27885ffd83dbSDimitry Andric getLangOpts().getGC() == LangOptions::GCOnly &&
27895ffd83dbSDimitry Andric PropertyTy->isBlockPointerType())
27900b57cec5SDimitry Andric Diag(Loc, diag::warn_objc_property_copy_missing_on_block);
27915ffd83dbSDimitry Andric else if ((Attributes & ObjCPropertyAttribute::kind_retain) &&
27925ffd83dbSDimitry Andric !(Attributes & ObjCPropertyAttribute::kind_readonly) &&
27935ffd83dbSDimitry Andric !(Attributes & ObjCPropertyAttribute::kind_strong) &&
27940b57cec5SDimitry Andric PropertyTy->isBlockPointerType())
27950b57cec5SDimitry Andric Diag(Loc, diag::warn_objc_property_retain_of_block);
27960b57cec5SDimitry Andric
27975ffd83dbSDimitry Andric if ((Attributes & ObjCPropertyAttribute::kind_readonly) &&
27985ffd83dbSDimitry Andric (Attributes & ObjCPropertyAttribute::kind_setter))
27990b57cec5SDimitry Andric Diag(Loc, diag::warn_objc_readonly_property_has_setter);
28000b57cec5SDimitry Andric }
2801