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