Index: clang/include/clang/AST/DeclObjC.h =================================================================== --- clang/include/clang/AST/DeclObjC.h +++ clang/include/clang/AST/DeclObjC.h @@ -2779,6 +2779,13 @@ /// Null for \@dynamic. Required for \@synthesize. ObjCIvarDecl *PropertyIvarDecl; + /// A redeclaration of the getter with this implementation's + /// interface as a decl context. + ObjCMethodDecl *GetterMethodDecl = nullptr; + /// A redeclaration of the setter with this implementation's + /// interface as a decl context. + ObjCMethodDecl *SetterMethodDecl = nullptr; + /// Null for \@dynamic. Non-null if property must be copy-constructed in /// getter. Expr *GetterCXXConstructor = nullptr; @@ -2845,6 +2852,12 @@ return IvarLoc.isValid() && IvarLoc != getLocation(); } + ObjCMethodDecl *getGetterMethodDecl() const { return GetterMethodDecl; } + void setGetterMethodDecl(ObjCMethodDecl *MD) { GetterMethodDecl = MD; } + + ObjCMethodDecl *getSetterMethodDecl() const { return SetterMethodDecl; } + void setSetterMethodDecl(ObjCMethodDecl *MD) { SetterMethodDecl = MD; } + Expr *getGetterCXXConstructor() const { return GetterCXXConstructor; } Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -8504,6 +8504,27 @@ tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC = nullptr); +private: + struct SynthesizedObjCPropertyAccessor { + ObjCPropertyImplDecl *PropertyImpl; + ObjCMethodDecl *AccessorDecl; + SourceLocation AtLoc; + SourceLocation PropertyLoc; + bool IsSetter; + }; + + /// Helper to redeclare an accessor inside the implementation. + void RedeclarePropertyAccessor(ObjCImplementationDecl *Impl, + SynthesizedObjCPropertyAccessor Accessor); + + /// Synthesized property accessors are redeclared in the + /// implementation, but only if they haven't been overridden by an + /// explicit definition. + llvm::DenseMap> + SynthesizedObjCPropertyAccessors; + +public: Decl *ActOnPropertyImplDecl(Scope *S, SourceLocation AtLoc, SourceLocation PropertyLoc, Index: clang/lib/AST/DeclObjC.cpp =================================================================== --- clang/lib/AST/DeclObjC.cpp +++ clang/lib/AST/DeclObjC.cpp @@ -1285,10 +1285,9 @@ SmallVectorImpl &Overridden) const { const ObjCMethodDecl *Method = this; - if (Method->isRedeclaration()) { + if (Method->isRedeclaration()) Method = cast(Method->getDeclContext())-> getMethod(Method->getSelector(), Method->isInstanceMethod()); - } if (Method->isOverriding()) { collectOverriddenMethodsSlow(Method, Overridden); @@ -1306,6 +1305,7 @@ if (isPropertyAccessor()) { const auto *Container = cast(getParent()); + bool IsGetter = (NumArgs == 0); bool IsInstance = isInstanceMethod(); @@ -1358,6 +1358,28 @@ } } + assert(!getBody() && "expected an accessor stub"); + // Go back to the interface. + if (auto *ImplDecl = dyn_cast(Container)) { + ClassDecl = ImplDecl->getClassInterface(); + if (const auto *Found = findMatchingProperty(ClassDecl)) + return Found; + for (const auto *Ext : ClassDecl->visible_extensions()) { + if (Ext == Container) + continue; + + if (const auto *Found = findMatchingProperty(Ext)) + return Found; + } + for (const auto *Cat : ClassDecl->known_categories()) { + if (Cat == Container) + continue; + + if (const auto *Found = findMatchingProperty(Cat)) + return Found; + } + } + llvm_unreachable("Marked as a property accessor but no property found!"); } Index: clang/lib/Analysis/BodyFarm.cpp =================================================================== --- clang/lib/Analysis/BodyFarm.cpp +++ clang/lib/Analysis/BodyFarm.cpp @@ -809,15 +809,6 @@ if (!D->isImplicit()) return nullptr; - Optional &Val = Bodies[D]; - if (Val.hasValue()) - return Val.getValue(); - Val = nullptr; - - const ObjCPropertyDecl *Prop = D->findPropertyDecl(); - if (!Prop) - return nullptr; - // For now, we only synthesize getters. // Synthesizing setters would cause false negatives in the // RetainCountChecker because the method body would bind the parameter @@ -830,6 +821,27 @@ if (D->param_size() != 0) return nullptr; + const ObjCPropertyDecl *Prop = D->findPropertyDecl(); + if (!Prop) + return nullptr; + + D = Prop->getGetterMethodDecl(); + + // If the property was defined in an extension, search the extensions for + // overrides. + const ObjCInterfaceDecl *OID = D->getClassInterface(); + if (dyn_cast(D->getParent()) != OID) + for (auto *Ext : OID->known_extensions()) { + auto *OMD = Ext->getInstanceMethod(D->getSelector()); + if (OMD && !OMD->isImplicit()) + return nullptr; + } + + Optional &Val = Bodies[D]; + if (Val.hasValue()) + return Val.getValue(); + Val = nullptr; + Val = createObjCPropertyGetter(C, Prop); return Val.getValue(); Index: clang/lib/CodeGen/CGObjC.cpp =================================================================== --- clang/lib/CodeGen/CGObjC.cpp +++ clang/lib/CodeGen/CGObjC.cpp @@ -954,8 +954,7 @@ const ObjCPropertyImplDecl *PID) { llvm::Constant *AtomicHelperFn = CodeGenFunction(CGM).GenerateObjCAtomicGetterCopyHelperFunction(PID); - const ObjCPropertyDecl *PD = PID->getPropertyDecl(); - ObjCMethodDecl *OMD = PD->getGetterMethodDecl(); + ObjCMethodDecl *OMD = PID->getGetterMethodDecl(); assert(OMD && "Invalid call to generate getter (empty method)"); StartObjCMethod(OMD, IMP->getClassInterface()); @@ -1041,7 +1040,7 @@ const ObjCPropertyDecl *prop = propImpl->getPropertyDecl(); QualType propType = prop->getType(); - ObjCMethodDecl *getterMethod = prop->getGetterMethodDecl(); + ObjCMethodDecl *getterMethod = propImpl->getGetterMethodDecl(); ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl(); @@ -1311,9 +1310,8 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl, const ObjCPropertyImplDecl *propImpl, llvm::Constant *AtomicHelperFn) { - const ObjCPropertyDecl *prop = propImpl->getPropertyDecl(); ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl(); - ObjCMethodDecl *setterMethod = prop->getSetterMethodDecl(); + ObjCMethodDecl *setterMethod = propImpl->getSetterMethodDecl(); // Just use the setter expression if Sema gave us one and it's // non-trivial. @@ -1490,8 +1488,7 @@ const ObjCPropertyImplDecl *PID) { llvm::Constant *AtomicHelperFn = CodeGenFunction(CGM).GenerateObjCAtomicSetterCopyHelperFunction(PID); - const ObjCPropertyDecl *PD = PID->getPropertyDecl(); - ObjCMethodDecl *OMD = PD->getSetterMethodDecl(); + ObjCMethodDecl *OMD = PID->getSetterMethodDecl(); assert(OMD && "Invalid call to generate setter (empty method)"); StartObjCMethod(OMD, IMP->getClassInterface()); Index: clang/lib/CodeGen/CGObjCGNU.cpp =================================================================== --- clang/lib/CodeGen/CGObjCGNU.cpp +++ clang/lib/CodeGen/CGObjCGNU.cpp @@ -1879,13 +1879,12 @@ for (auto *propImpl : OID->property_impls()) if (propImpl->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) { - ObjCPropertyDecl *prop = propImpl->getPropertyDecl(); auto addIfExists = [&](const ObjCMethodDecl* OMD) { if (OMD) InstanceMethods.push_back(OMD); }; - addIfExists(prop->getGetterMethodDecl()); - addIfExists(prop->getSetterMethodDecl()); + addIfExists(propImpl->getGetterMethodDecl()); + addIfExists(propImpl->getSetterMethodDecl()); } if (InstanceMethods.size() == 0) @@ -3493,13 +3492,12 @@ for (auto *propertyImpl : OID->property_impls()) if (propertyImpl->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) { - ObjCPropertyDecl *property = propertyImpl->getPropertyDecl(); auto addPropertyMethod = [&](const ObjCMethodDecl *accessor) { if (accessor) InstanceMethods.push_back(accessor); }; - addPropertyMethod(property->getGetterMethodDecl()); - addPropertyMethod(property->getSetterMethodDecl()); + addPropertyMethod(propertyImpl->getGetterMethodDecl()); + addPropertyMethod(propertyImpl->getSetterMethodDecl()); } llvm::Constant *Properties = GeneratePropertyList(OID, ClassDecl); Index: clang/lib/CodeGen/CGObjCMac.cpp =================================================================== --- clang/lib/CodeGen/CGObjCMac.cpp +++ clang/lib/CodeGen/CGObjCMac.cpp @@ -3561,12 +3561,10 @@ for (const auto *PID : ID->property_impls()) { if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) { - ObjCPropertyDecl *PD = PID->getPropertyDecl(); - - if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) + if (ObjCMethodDecl *MD = PID->getGetterMethodDecl()) if (GetMethodDefinition(MD)) Methods[InstanceMethods].push_back(MD); - if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) + if (ObjCMethodDecl *MD = PID->getSetterMethodDecl()) if (GetMethodDefinition(MD)) Methods[InstanceMethods].push_back(MD); } @@ -6233,19 +6231,6 @@ } else { for (const auto *MD : ID->instance_methods()) methods.push_back(MD); - - for (const auto *PID : ID->property_impls()) { - if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize){ - ObjCPropertyDecl *PD = PID->getPropertyDecl(); - - if (auto MD = PD->getGetterMethodDecl()) - if (GetMethodDefinition(MD)) - methods.push_back(MD); - if (auto MD = PD->getSetterMethodDecl()) - if (GetMethodDefinition(MD)) - methods.push_back(MD); - } - } } values.add(emitMethodList(ID->getObjCRuntimeNameAsString(), @@ -6708,9 +6693,8 @@ // method_count values.addInt(ObjCTypes.IntTy, methods.size()); auto methodArray = values.beginArray(ObjCTypes.MethodTy); - for (auto MD : methods) { + for (auto MD : methods) emitMethodConstant(methodArray, MD, forProtocol); - } methodArray.finishAndAddTo(values); llvm::GlobalVariable *GV = finishAndCreateGlobal(values, prefix + name, CGM); Index: clang/lib/CodeGen/CodeGenFunction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenFunction.cpp +++ clang/lib/CodeGen/CodeGenFunction.cpp @@ -635,8 +635,7 @@ return CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM); } -void CodeGenFunction::StartFunction(GlobalDecl GD, - QualType RetTy, +void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, llvm::Function *Fn, const CGFunctionInfo &FnInfo, const FunctionArgList &Args, Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -5052,11 +5052,12 @@ // we want, that just indicates if the decl came from a // property. What we want to know is if the method is defined in // this implementation. - if (!D->getInstanceMethod(PD->getGetterName())) + auto *Getter = D->getInstanceMethod(PD->getGetterName()); + if (!Getter || !Getter->getBody()) CodeGenFunction(*this).GenerateObjCGetter( - const_cast(D), PID); - if (!PD->isReadOnly() && - !D->getInstanceMethod(PD->getSetterName())) + const_cast(D), PID); + auto *Setter = D->getInstanceMethod(PD->getSetterName()); + if (!PD->isReadOnly() && (!Setter || !Setter->getBody())) CodeGenFunction(*this).GenerateObjCSetter( const_cast(D), PID); } Index: clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp =================================================================== --- clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -909,9 +909,9 @@ static bool mustSynthesizeSetterGetterMethod(ObjCImplementationDecl *IMP, ObjCPropertyDecl *PD, bool getter) { - return getter ? !IMP->getInstanceMethod(PD->getGetterName()) - : !IMP->getInstanceMethod(PD->getSetterName()); - + auto *OMD = IMP->getInstanceMethod(getter ? PD->getGetterName() + : PD->getSetterName()); + return !OMD || !OMD->getBody(); } void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, @@ -953,7 +953,7 @@ "id objc_getProperty(id, SEL, long, bool);\n"; } RewriteObjCMethodDecl(OID->getContainingInterface(), - PD->getGetterMethodDecl(), Getr); + PID->getGetterMethodDecl(), Getr); Getr += "{ "; // Synthesize an explicit cast to gain access to the ivar. // See objc-act.c:objc_synthesize_new_getter() for details. @@ -961,7 +961,7 @@ // return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1) Getr += "typedef "; const FunctionType *FPRetType = nullptr; - RewriteTypeIntoString(PD->getGetterMethodDecl()->getReturnType(), Getr, + RewriteTypeIntoString(PID->getGetterMethodDecl()->getReturnType(), Getr, FPRetType); Getr += " _TYPE"; if (FPRetType) { @@ -1013,7 +1013,7 @@ } RewriteObjCMethodDecl(OID->getContainingInterface(), - PD->getSetterMethodDecl(), Setr); + PID->getSetterMethodDecl(), Setr); Setr += "{ "; // Synthesize an explicit cast to initialize the ivar. // See objc-act.c:objc_synthesize_new_setter() for details. @@ -1346,6 +1346,8 @@ InsertText(CID->getBeginLoc(), "// "); for (auto *OMD : IMD ? IMD->instance_methods() : CID->instance_methods()) { + if (!OMD->getBody()) + continue; std::string ResultStr; RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); SourceLocation LocStart = OMD->getBeginLoc(); @@ -1357,6 +1359,8 @@ } for (auto *OMD : IMD ? IMD->class_methods() : CID->class_methods()) { + if (!OMD->getBody()) + continue; std::string ResultStr; RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); SourceLocation LocStart = OMD->getBeginLoc(); @@ -7032,12 +7036,12 @@ ObjCPropertyDecl *PD = Prop->getPropertyDecl(); if (!PD) continue; - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl()) if (mustSynthesizeSetterGetterMethod(IDecl, PD, true /*getter*/)) InstanceMethods.push_back(Getter); if (PD->isReadOnly()) continue; - if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) + if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl()) if (mustSynthesizeSetterGetterMethod(IDecl, PD, false /*setter*/)) InstanceMethods.push_back(Setter); } @@ -7282,11 +7286,11 @@ ObjCPropertyDecl *PD = Prop->getPropertyDecl(); if (!PD) continue; - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl()) InstanceMethods.push_back(Getter); if (PD->isReadOnly()) continue; - if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) + if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl()) InstanceMethods.push_back(Setter); } Index: clang/lib/Frontend/Rewrite/RewriteObjC.cpp =================================================================== --- clang/lib/Frontend/Rewrite/RewriteObjC.cpp +++ clang/lib/Frontend/Rewrite/RewriteObjC.cpp @@ -786,8 +786,9 @@ if (!OID) return; + unsigned Attributes = PD->getPropertyAttributes(); - if (!PD->getGetterMethodDecl()->isDefined()) { + if (PID->getGetterMethodDecl() && !PID->getGetterMethodDecl()->isDefined()) { bool GenGetProperty = !(Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) && (Attributes & (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_copy)); @@ -799,7 +800,7 @@ "id objc_getProperty(id, SEL, long, bool);\n"; } RewriteObjCMethodDecl(OID->getContainingInterface(), - PD->getGetterMethodDecl(), Getr); + PID->getGetterMethodDecl(), Getr); Getr += "{ "; // Synthesize an explicit cast to gain access to the ivar. // See objc-act.c:objc_synthesize_new_getter() for details. @@ -807,7 +808,7 @@ // return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1) Getr += "typedef "; const FunctionType *FPRetType = nullptr; - RewriteTypeIntoString(PD->getGetterMethodDecl()->getReturnType(), Getr, + RewriteTypeIntoString(PID->getGetterMethodDecl()->getReturnType(), Getr, FPRetType); Getr += " _TYPE"; if (FPRetType) { @@ -843,7 +844,8 @@ InsertText(onePastSemiLoc, Getr); } - if (PD->isReadOnly() || PD->getSetterMethodDecl()->isDefined()) + if (PD->isReadOnly() || !PID->getSetterMethodDecl() || + PID->getSetterMethodDecl()->isDefined()) return; // Generate the 'setter' function. @@ -858,7 +860,7 @@ } RewriteObjCMethodDecl(OID->getContainingInterface(), - PD->getSetterMethodDecl(), Setr); + PID->getSetterMethodDecl(), Setr); Setr += "{ "; // Synthesize an explicit cast to initialize the ivar. // See objc-act.c:objc_synthesize_new_setter() for details. @@ -1167,6 +1169,8 @@ InsertText(IMD ? IMD->getBeginLoc() : CID->getBeginLoc(), "// "); for (auto *OMD : IMD ? IMD->instance_methods() : CID->instance_methods()) { + if (!OMD->getBody()) + continue; std::string ResultStr; RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); SourceLocation LocStart = OMD->getBeginLoc(); @@ -1178,6 +1182,8 @@ } for (auto *OMD : IMD ? IMD->class_methods() : CID->class_methods()) { + if (!OMD->getBody()) + continue; std::string ResultStr; RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); SourceLocation LocStart = OMD->getBeginLoc(); @@ -5354,12 +5360,12 @@ ObjCPropertyDecl *PD = Prop->getPropertyDecl(); if (!PD) continue; - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl()) if (!Getter->isDefined()) InstanceMethods.push_back(Getter); if (PD->isReadOnly()) continue; - if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) + if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl()) if (!Setter->isDefined()) InstanceMethods.push_back(Setter); } @@ -5632,11 +5638,11 @@ ObjCPropertyDecl *PD = Prop->getPropertyDecl(); if (!PD) continue; - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl()) InstanceMethods.push_back(Getter); if (PD->isReadOnly()) continue; - if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) + if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl()) InstanceMethods.push_back(Setter); } RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(), Index: clang/lib/Index/IndexDecl.cpp =================================================================== --- clang/lib/Index/IndexDecl.cpp +++ clang/lib/Index/IndexDecl.cpp @@ -513,7 +513,6 @@ } bool VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) { - ObjCPropertyDecl *PD = D->getPropertyDecl(); auto *Container = cast(D->getDeclContext()); SourceLocation Loc = D->getLocation(); SymbolRoleSet Roles = 0; @@ -533,12 +532,12 @@ assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize); SymbolRoleSet AccessorMethodRoles = SymbolRoleSet(SymbolRole::Dynamic) | SymbolRoleSet(SymbolRole::Implicit); - if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) { + if (ObjCMethodDecl *MD = D->getGetterMethodDecl()) { if (MD->isPropertyAccessor() && !hasUserDefined(MD, Container)) IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container); } - if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) { + if (ObjCMethodDecl *MD = D->getSetterMethodDecl()) { if (MD->isPropertyAccessor() && !hasUserDefined(MD, Container)) IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container); Index: clang/lib/Sema/SemaDeclObjC.cpp =================================================================== --- clang/lib/Sema/SemaDeclObjC.cpp +++ clang/lib/Sema/SemaDeclObjC.cpp @@ -2828,6 +2828,9 @@ "Expected to find the method through lookup as well"); // ImpMethodDecl may be null as in a @dynamic property. if (ImpMethodDecl) { + // Skip property accessor function stubs. + if (I->isPropertyAccessor() && !ImpMethodDecl->getBody()) + continue; if (!WarnCategoryMethodImpl) WarnConflictingTypedMethods(ImpMethodDecl, I, isa(CDecl)); @@ -2854,6 +2857,9 @@ "Expected to find the method through lookup as well"); // ImpMethodDecl may be null as in a @dynamic property. if (ImpMethodDecl) { + // Skip property accessor function stubs. + if (I->isPropertyAccessor() && !ImpMethodDecl->getBody()) + continue; if (!WarnCategoryMethodImpl) WarnConflictingTypedMethods(ImpMethodDecl, I, isa(CDecl)); @@ -3903,6 +3909,15 @@ || isa(ClassDecl); bool checkIdenticalMethods = isa(ClassDecl); + // Redeclare synthesized property accessors, if they haven't been overridden. + auto Accessors = SynthesizedObjCPropertyAccessors.find(OCD); + if (Accessors != SynthesizedObjCPropertyAccessors.end()) + for (auto &A : Accessors->second) { + auto *OID = cast(OCD); + if (!OID->getInstanceMethod(A.AccessorDecl->getSelector())) + RedeclarePropertyAccessor(OID, A); + } + // FIXME: Remove these and use the ObjCContainerDecl/DeclContext. llvm::DenseMap InsMap; llvm::DenseMap ClsMap; @@ -5063,6 +5078,9 @@ if (!IV) continue; + if (!CurMethod->getBody()) + continue; + UnusedBackingIvarChecker Checker(*this, CurMethod, IV); Checker.TraverseStmt(CurMethod->getBody()); if (Checker.AccessedIvar) Index: clang/lib/Sema/SemaObjCProperty.cpp =================================================================== --- clang/lib/Sema/SemaObjCProperty.cpp +++ clang/lib/Sema/SemaObjCProperty.cpp @@ -1037,6 +1037,33 @@ return false; } +void Sema::RedeclarePropertyAccessor(ObjCImplementationDecl *Impl, + SynthesizedObjCPropertyAccessor Accessor) { + ObjCMethodDecl *Decl = Accessor.AccessorDecl; + ObjCMethodDecl *ImplDecl = ObjCMethodDecl::Create( + Context, Accessor.AtLoc, Accessor.PropertyLoc, Decl->getSelector(), + Decl->getReturnType(), Decl->getReturnTypeSourceInfo(), Impl, + Decl->isInstanceMethod(), Decl->isVariadic(), Decl->isPropertyAccessor(), + Decl->isImplicit(), Decl->isDefined(), Decl->getImplementationControl(), + Decl->hasRelatedResultType()); + ImplDecl->getMethodFamily(); + if (Decl->hasAttrs()) + ImplDecl->setAttrs(Decl->getAttrs()); + ImplDecl->setSelfDecl(Decl->getSelfDecl()); + ImplDecl->setCmdDecl(Decl->getCmdDecl()); + SmallVector SelLocs; + Decl->getSelectorLocs(SelLocs); + ImplDecl->setMethodParams(Context, Decl->parameters(), SelLocs); + ImplDecl->setLexicalDeclContext(Impl); + ImplDecl->setDefined(false); + Impl->makeDeclVisibleInContext(ImplDecl); + Impl->addDecl(ImplDecl); + if (!Accessor.IsSetter) + Accessor.PropertyImpl->setGetterMethodDecl(ImplDecl); + else + Accessor.PropertyImpl->setSetterMethodDecl(ImplDecl); +} + /// ActOnPropertyImplDecl - This routine performs semantic checks and /// builds the AST node for a property implementation declaration; declared /// as \@synthesize or \@dynamic. @@ -1404,6 +1431,12 @@ if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) { getterMethod->createImplicitParams(Context, IDecl); + + // Redeclare the getter within the implementation as DeclContext. + if (Synthesize) + SynthesizedObjCPropertyAccessors[ClassImpDecl].push_back( + {PIDecl, getterMethod, AtLoc, PropertyLoc, false}); + if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr && Ivar->getType()->isRecordType()) { // For Objective-C++, need to synthesize the AST for the IVAR object to be @@ -1456,8 +1489,15 @@ break; } } + if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) { setterMethod->createImplicitParams(Context, IDecl); + + // Redeclare the setter within the implementation as DeclContext. + if (Synthesize) + SynthesizedObjCPropertyAccessors[ClassImpDecl].push_back( + {PIDecl, setterMethod, AtLoc, PropertyLoc, true}); + if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr && Ivar->getType()->isRecordType()) { // FIXME. Eventually we want to do this for Objective-C as well. @@ -2083,7 +2123,6 @@ void Sema::diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl) { for (const auto *propertyImpl : impDecl->property_impls()) { const auto *property = propertyImpl->getPropertyDecl(); - // Warn about null_resettable properties with synthesized setters, // because the setter won't properly handle nil. if (propertyImpl->getPropertyImplementation() @@ -2094,8 +2133,12 @@ property->getSetterMethodDecl()) { auto *getterMethod = property->getGetterMethodDecl(); auto *setterMethod = property->getSetterMethodDecl(); - if (!impDecl->getInstanceMethod(setterMethod->getSelector()) && - !impDecl->getInstanceMethod(getterMethod->getSelector())) { + auto *getterImpl = + impDecl->getInstanceMethod(getterMethod->getSelector()); + auto *setterImpl = + impDecl->getInstanceMethod(setterMethod->getSelector()); + if ((!getterImpl || !getterImpl->getBody()) && + (!setterImpl || !setterImpl->getBody())) { SourceLocation loc = propertyImpl->getLocation(); if (loc.isInvalid()) loc = impDecl->getBeginLoc(); @@ -2138,6 +2181,10 @@ SetterMethod = Property->isClassProperty() ? IMPDecl->getClassMethod(Property->getSetterName()) : IMPDecl->getInstanceMethod(Property->getSetterName()); + if (GetterMethod && !GetterMethod->getBody()) + GetterMethod = nullptr; + if (SetterMethod && !SetterMethod->getBody()) + SetterMethod = nullptr; LookedUpGetterSetter = true; if (GetterMethod) { Diag(GetterMethod->getLocation(), @@ -2168,6 +2215,10 @@ SetterMethod = Property->isClassProperty() ? IMPDecl->getClassMethod(Property->getSetterName()) : IMPDecl->getInstanceMethod(Property->getSetterName()); + if (GetterMethod && !GetterMethod->getBody()) + GetterMethod = nullptr; + if (SetterMethod && !SetterMethod->getBody()) + SetterMethod = nullptr; } if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) { SourceLocation MethodLoc = @@ -2210,8 +2261,10 @@ for (const auto *PID : D->property_impls()) { const ObjCPropertyDecl *PD = PID->getPropertyDecl(); if (PD && !PD->hasAttr() && - !PD->isClassProperty() && - !D->getInstanceMethod(PD->getGetterName())) { + !PD->isClassProperty()) { + ObjCMethodDecl *IM = D->getInstanceMethod(PD->getGetterName()); + if (IM && IM->getBody()) + continue; ObjCMethodDecl *method = PD->getGetterMethodDecl(); if (!method) continue; Index: clang/lib/Serialization/ASTReaderDecl.cpp =================================================================== --- clang/lib/Serialization/ASTReaderDecl.cpp +++ clang/lib/Serialization/ASTReaderDecl.cpp @@ -1313,6 +1313,8 @@ D->setPropertyDecl(ReadDeclAs()); D->PropertyIvarDecl = ReadDeclAs(); D->IvarLoc = ReadSourceLocation(); + D->setGetterMethodDecl(ReadDeclAs()); + D->setSetterMethodDecl(ReadDeclAs()); D->setGetterCXXConstructor(Record.readExpr()); D->setSetterCXXAssignment(Record.readExpr()); } Index: clang/lib/Serialization/ASTWriterDecl.cpp =================================================================== --- clang/lib/Serialization/ASTWriterDecl.cpp +++ clang/lib/Serialization/ASTWriterDecl.cpp @@ -884,6 +884,8 @@ Record.AddDeclRef(D->getPropertyDecl()); Record.AddDeclRef(D->getPropertyIvarDecl()); Record.AddSourceLocation(D->getPropertyIvarDeclLoc()); + Record.AddDeclRef(D->getGetterMethodDecl()); + Record.AddDeclRef(D->getSetterMethodDecl()); Record.AddStmt(D->getGetterCXXConstructor()); Record.AddStmt(D->getSetterCXXAssignment()); Code = serialization::DECL_OBJC_PROPERTY_IMPL; Index: clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp +++ clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp @@ -144,7 +144,8 @@ continue; const Stmt *Body = M->getBody(); - assert(Body); + if (!Body) + continue; MethodCrawler MC(IvarToPropMap, M->getCanonicalDecl(), InterD, BR, this, DCtx); Index: clang/lib/StaticAnalyzer/Core/CallEvent.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -1080,7 +1080,7 @@ const ObjCPropertyDecl *ObjCMethodCall::getAccessedProperty() const { // Look for properties accessed with property syntax (foo.bar = ...) - if ( getMessageKind() == OCM_PropertyAccess) { + if (getMessageKind() == OCM_PropertyAccess) { const PseudoObjectExpr *POE = getContainingPseudoObjectExpr(); assert(POE && "Property access without PseudoObjectExpr?"); Index: clang/test/AST/ast-dump-decl-json.m =================================================================== --- clang/test/AST/ast-dump-decl-json.m +++ clang/test/AST/ast-dump-decl-json.m @@ -1332,7 +1332,7 @@ // CHECK-NEXT: "col": 13, // CHECK-NEXT: "tokLen": 3 // CHECK-NEXT: } -// CHECK-NEXT: }, +// CHECK-NEXT: }, // CHECK-NEXT: "name": "bar", // CHECK-NEXT: "implKind": "synthesize", // CHECK-NEXT: "propertyDecl": { @@ -1348,7 +1348,155 @@ // CHECK-NEXT: "qualType": "int" // CHECK-NEXT: } // CHECK-NEXT: } -// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ObjCMethodDecl", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "line": 70, +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "col": 13, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "name": "getterFoo", +// CHECK-NEXT: "returnType": { +// CHECK-NEXT: "qualType": "int" +// CHECK-NEXT: }, +// CHECK-NEXT: "instance": true +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ObjCMethodDecl", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "col": 13, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "name": "setterFoo:", +// CHECK-NEXT: "returnType": { +// CHECK-NEXT: "qualType": "void" +// CHECK-NEXT: }, +// CHECK-NEXT: "instance": true, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParmVarDecl", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "line": 63, +// CHECK-NEXT: "col": 52, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "col": 52, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "col": 52, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "name": "foo", +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "int" +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ObjCMethodDecl", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "line": 71, +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "col": 13, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "name": "bar", +// CHECK-NEXT: "returnType": { +// CHECK-NEXT: "qualType": "int" +// CHECK-NEXT: }, +// CHECK-NEXT: "instance": true +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ObjCMethodDecl", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "col": 13, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "name": "setBar:", +// CHECK-NEXT: "returnType": { +// CHECK-NEXT: "qualType": "void" +// CHECK-NEXT: }, +// CHECK-NEXT: "instance": true, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParmVarDecl", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "line": 64, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "name": "bar", +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "int" +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } // CHECK-NEXT: ] // CHECK-NEXT: } Index: clang/test/Analysis/Inputs/expected-plists/nullability-notes.m.plist =================================================================== --- clang/test/Analysis/Inputs/expected-plists/nullability-notes.m.plist +++ clang/test/Analysis/Inputs/expected-plists/nullability-notes.m.plist @@ -188,7 +188,6 @@ 0 - 10 14 16 17 Index: clang/test/CodeGenObjC/debug-info-synthesis.m =================================================================== --- clang/test/CodeGenObjC/debug-info-synthesis.m +++ clang/test/CodeGenObjC/debug-info-synthesis.m @@ -30,8 +30,8 @@ } } -// CHECK: ![[FILE:.*]] = !DIFile(filename: "{{[^"]+}}foo.h" +// CHECK: ![[FILE:.*]] = !DIFile(filename: "foo.m" // CHECK: !DISubprogram(name: "-[Foo setDict:]" // CHECK-SAME: file: ![[FILE]], -// CHECK-SAME: line: 8, +// CHECK-SAME: line: 7, // CHECK-SAME: DISPFlagLocalToUnit | DISPFlagDefinition Index: clang/test/CodeGenObjC/debug-property-synth.m =================================================================== --- clang/test/CodeGenObjC/debug-property-synth.m +++ clang/test/CodeGenObjC/debug-property-synth.m @@ -7,6 +7,10 @@ @interface I { int _p1; } +@property int p1; +@end + +@implementation I // Test that the linetable entries for the synthesized getter and // setter are correct. // @@ -22,10 +26,6 @@ // CHECK: ![[DBG1]] = !DILocation(line: [[@LINE+3]], // CHECK: !DISubprogram(name: "-[I setP1:]",{{.*}} line: [[@LINE+2]],{{.*}} DISPFlagLocalToUnit | DISPFlagDefinition // CHECK: ![[DBG2]] = !DILocation(line: [[@LINE+1]], -@property int p1; -@end - -@implementation I @synthesize p1 = _p1; @end Index: clang/test/CodeGenObjC/debuginfo-properties.m =================================================================== --- clang/test/CodeGenObjC/debuginfo-properties.m +++ clang/test/CodeGenObjC/debuginfo-properties.m @@ -11,19 +11,6 @@ @protocol HasASelection @property (nonatomic, retain) Selection* selection; -// CHECK: !DISubprogram(name: "-[MyClass selection]" -// CHECK-SAME: line: [[@LINE-2]] -// CHECK-SAME: DISPFlagLocalToUnit | DISPFlagDefinition -// CHECK: !DISubprogram(name: "-[MyClass setSelection:]" -// CHECK-SAME: line: [[@LINE-5]] -// CHECK-SAME: DISPFlagLocalToUnit | DISPFlagDefinition -// CHECK: !DISubprogram(name: "-[OtherClass selection]" -// CHECK-SAME: line: [[@LINE-8]] -// CHECK-SAME: DISPFlagLocalToUnit | DISPFlagDefinition -// CHECK: !DISubprogram(name: "-[OtherClass setSelection:]" -// CHECK-SAME: line: [[@LINE-11]] -// CHECK-SAME: DISPFlagLocalToUnit | DISPFlagDefinition - @end @interface MyClass : NSObject { @@ -33,6 +20,12 @@ @implementation MyClass @synthesize selection = _selection; +// CHECK: !DISubprogram(name: "-[MyClass selection]" +// CHECK-SAME: line: [[@LINE-2]] +// CHECK-SAME: DISPFlagLocalToUnit | DISPFlagDefinition +// CHECK: !DISubprogram(name: "-[MyClass setSelection:]" +// CHECK-SAME: line: [[@LINE-5]] +// CHECK-SAME: DISPFlagLocalToUnit | DISPFlagDefinition @end @interface OtherClass : NSObject { @@ -41,4 +34,10 @@ @end @implementation OtherClass @synthesize selection = _selection; +// CHECK: !DISubprogram(name: "-[OtherClass selection]" +// CHECK-SAME: line: [[@LINE-2]] +// CHECK-SAME: DISPFlagLocalToUnit | DISPFlagDefinition +// CHECK: !DISubprogram(name: "-[OtherClass setSelection:]" +// CHECK-SAME: line: [[@LINE-5]] +// CHECK-SAME: DISPFlagLocalToUnit | DISPFlagDefinition @end Index: clang/test/CodeGenObjC/instance-method-metadata.m =================================================================== --- clang/test/CodeGenObjC/instance-method-metadata.m +++ clang/test/CodeGenObjC/instance-method-metadata.m @@ -1,6 +1,5 @@ // REQUIRES: x86-registered-target -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -S -o %t %s -// RUN: FileCheck < %t %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -S %s -o - | FileCheck %s // rdar://9072317