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 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. 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 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 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 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 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 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 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. 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 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 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 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'. 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 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 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 * 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. 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 * 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 /// 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 /// 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 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 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. 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'. 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 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. 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 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 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 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 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 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 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 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. 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. 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 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