Index: clang/include/clang/AST/DeclObjC.h =================================================================== --- clang/include/clang/AST/DeclObjC.h +++ clang/include/clang/AST/DeclObjC.h @@ -2779,6 +2779,11 @@ /// Null for \@dynamic. Required for \@synthesize. ObjCIvarDecl *PropertyIvarDecl; + /// The getter's definition, which has an empty body if synthesized. + ObjCMethodDecl *GetterMethodDecl = nullptr; + /// The getter's definition, which has an empty body if synthesized. + ObjCMethodDecl *SetterMethodDecl = nullptr; + /// Null for \@dynamic. Non-null if property must be copy-constructed in /// getter. Expr *GetterCXXConstructor = nullptr; @@ -2845,6 +2850,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/lib/AST/DeclObjC.cpp =================================================================== --- clang/lib/AST/DeclObjC.cpp +++ clang/lib/AST/DeclObjC.cpp @@ -1306,6 +1306,11 @@ if (isPropertyAccessor()) { const auto *Container = cast(getParent()); + // For accessor stubs, go back to the interface. + if (auto *ImplDecl = dyn_cast(Container)) + if (!getBody()) + Container = ImplDecl->getClassInterface(); + bool IsGetter = (NumArgs == 0); bool IsInstance = isInstanceMethod(); @@ -1358,6 +1363,15 @@ } } + assert(!getBody() && "expected an accessor stub"); + 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 @@ -830,6 +830,16 @@ if (D->param_size() != 0) return nullptr; +// // 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; +// } + 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 @@ -1880,13 +1880,12 @@ for (auto *propImpl : OID->property_impls()) if (propImpl->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) { - ObjCPropertyDecl *prop = propImpl->getPropertyDecl(); - auto addIfExists = [&](const ObjCMethodDecl* OMD) { - if (OMD) + auto addIfExists = [&](const ObjCMethodDecl *OMD) { + if (OMD && OMD->hasBody()) InstanceMethods.push_back(OMD); }; - addIfExists(prop->getGetterMethodDecl()); - addIfExists(prop->getSetterMethodDecl()); + addIfExists(propImpl->getGetterMethodDecl()); + addIfExists(propImpl->getSetterMethodDecl()); } if (InstanceMethods.size() == 0) @@ -3494,13 +3493,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 @@ -3559,12 +3559,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); } @@ -6232,19 +6230,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(), @@ -6707,9 +6692,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 @@ -5108,11 +5108,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 = PID->getGetterMethodDecl(); + if (!Getter || !Getter->getBody()) CodeGenFunction(*this).GenerateObjCGetter( - const_cast(D), PID); - if (!PD->isReadOnly() && - !D->getInstanceMethod(PD->getSetterName())) + const_cast(D), PID); + auto *Setter = PID->getSetterMethodDecl(); + 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. @@ -1168,6 +1170,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(); @@ -1179,6 +1183,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(); @@ -5355,12 +5361,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); } @@ -5633,11 +5639,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 @@ -42,15 +42,6 @@ return true; } - /// Returns true if the given method has been defined explicitly by the - /// user. - static bool hasUserDefined(const ObjCMethodDecl *D, - const ObjCImplDecl *Container) { - const ObjCMethodDecl *MD = Container->getMethod(D->getSelector(), - D->isInstanceMethod()); - return MD && !MD->isImplicit() && MD->isThisDeclarationADefinition(); - } - void handleTemplateArgumentLoc(const TemplateArgumentLoc &TALoc, const NamedDecl *Parent, const DeclContext *DC) { @@ -534,17 +525,16 @@ SymbolRoleSet AccessorMethodRoles = SymbolRoleSet(SymbolRole::Dynamic) | SymbolRoleSet(SymbolRole::Implicit); if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) { - if (MD->isPropertyAccessor() && - !hasUserDefined(MD, Container)) + if (MD->isPropertyAccessor() && !D->getGetterMethodDecl()->hasBody()) IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container); } if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) { - if (MD->isPropertyAccessor() && - !hasUserDefined(MD, Container)) + if (MD->isPropertyAccessor() && !D->getSetterMethodDecl()->hasBody()) IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container); } if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) { if (IvarD->getSynthesize()) { + IvarD->dump(); // For synthesized ivars, use the location of its name in the // corresponding @synthesize. If there isn't one, use the containing // @implementation's location, rather than the property's location, 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,23 @@ || isa(ClassDecl); bool checkIdenticalMethods = isa(ClassDecl); + // Make synthesized accessor stub functions visible. This is + // deferred in case they are overridden by an explicit method. + if (auto *OID = dyn_cast(CurContext)) { + for (auto PropImpl : OID->property_impls()) { + if (auto *Getter = PropImpl->getGetterMethodDecl()) + if (Getter->isImplicit() && !Getter->hasBody()) { + OID->makeDeclVisibleInContext(Getter); + OID->addDecl(Getter); + } + if (auto *Setter = PropImpl->getSetterMethodDecl()) + if (Setter->isImplicit() && !Setter->hasBody()) { + OID->makeDeclVisibleInContext(Setter); + OID->addDecl(Setter); + } + } + } + // FIXME: Remove these and use the ObjCContainerDecl/DeclContext. llvm::DenseMap InsMap; llvm::DenseMap ClsMap; @@ -4001,8 +4024,8 @@ continue; for (const auto *Ext : IDecl->visible_extensions()) { - if (ObjCMethodDecl *GetterMethod - = Ext->getInstanceMethod(Property->getGetterName())) + if (ObjCMethodDecl *GetterMethod = + Ext->getInstanceMethod(Property->getGetterName())) GetterMethod->setPropertyAccessor(true); if (!Property->isReadOnly()) if (ObjCMethodDecl *SetterMethod @@ -4551,6 +4574,7 @@ Diag(MethodLoc, diag::err_missing_method_context); return nullptr; } + Decl *ClassDecl = cast(CurContext); QualType resultDeclType; @@ -4666,6 +4690,27 @@ ImpDecl->addClassMethod(ObjCMethod); } + // If this method overrides a previous @synthesize declaration, + // register it with the property. Linear search through all + // properties here, because the autosynthesized stub hasn't been + // made visible yet, so it can be overriden by a later + // user-specified implementation. + for (ObjCPropertyImplDecl *PropertyImpl : ImpDecl->property_impls()) { + if (auto *Setter = PropertyImpl->getSetterMethodDecl()) + if (Setter->getSelector() == Sel && + Setter->isInstanceMethod() == ObjCMethod->isInstanceMethod()) { + assert(!Setter->hasBody() && "autosynth stub expected"); + PropertyImpl->setSetterMethodDecl(ObjCMethod); + } + if (auto *Getter = PropertyImpl->getGetterMethodDecl()) + if (Getter->getSelector() == Sel && + Getter->isInstanceMethod() == ObjCMethod->isInstanceMethod()) { + assert(!Getter->hasBody() && "autosynth stub expected"); + PropertyImpl->setGetterMethodDecl(ObjCMethod); + break; + } + } + // Merge information from the @interface declaration into the // @implementation. if (ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface()) { @@ -5063,6 +5108,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,32 @@ return false; } +static ObjCMethodDecl * +RedeclarePropertyAccessor(ASTContext &Context, ObjCImplementationDecl *Impl, + ObjCPropertyImplDecl *PropertyImpl, + ObjCMethodDecl *AccessorDecl, SourceLocation AtLoc, + SourceLocation PropertyLoc) { + ObjCMethodDecl *Decl = AccessorDecl; + // llvm::errs()<<"redeclare: "; Decl->dump(); + ObjCMethodDecl *ImplDecl = ObjCMethodDecl::Create( + Context, AtLoc, 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); + return ImplDecl; +} + /// ActOnPropertyImplDecl - This routine performs semantic checks and /// builds the AST node for a property implementation declaration; declared /// as \@synthesize or \@dynamic. @@ -1404,6 +1430,18 @@ if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) { getterMethod->createImplicitParams(Context, IDecl); + + // Redeclare the getter within the implementation as DeclContext. + if (Synthesize) { + // If the method hasn't been overridden, create a synthesized implementation. + ObjCMethodDecl *OMD = ClassImpDecl->getMethod( + getterMethod->getSelector(), getterMethod->isInstanceMethod()); + if (!OMD) + OMD = RedeclarePropertyAccessor(Context, IC, PIDecl, getterMethod, + AtLoc, PropertyLoc); + PIDecl->setGetterMethodDecl(OMD); + } + if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr && Ivar->getType()->isRecordType()) { // For Objective-C++, need to synthesize the AST for the IVAR object to be @@ -1456,8 +1494,20 @@ break; } } + if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) { setterMethod->createImplicitParams(Context, IDecl); + + // Redeclare the setter within the implementation as DeclContext. + if (Synthesize) { + ObjCMethodDecl *OMD = ClassImpDecl->getMethod( + setterMethod->getSelector(), setterMethod->isInstanceMethod()); + if (!OMD) + OMD = RedeclarePropertyAccessor(Context, IC, PIDecl, setterMethod, + AtLoc, PropertyLoc); + PIDecl->setSetterMethodDecl(OMD); + } + if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr && Ivar->getType()->isRecordType()) { // FIXME. Eventually we want to do this for Objective-C as well. @@ -1852,10 +1902,12 @@ if (IMPDecl->FindPropertyImplDecl( Prop->getIdentifier(), Prop->getQueryKind())) continue; - if (IMPDecl->getInstanceMethod(Prop->getGetterName())) { + ObjCMethodDecl *ImpMethod = IMPDecl->getInstanceMethod(Prop->getGetterName()); + if (ImpMethod && !ImpMethod->getBody()) { if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly) continue; - if (IMPDecl->getInstanceMethod(Prop->getSetterName())) + ImpMethod = IMPDecl->getInstanceMethod(Prop->getSetterName()); + if (ImpMethod && !ImpMethod->getBody()) continue; } if (ObjCPropertyImplDecl *PID = @@ -2083,7 +2135,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() @@ -2092,16 +2143,16 @@ ObjCPropertyDecl::OBJC_PR_null_resettable) && property->getGetterMethodDecl() && property->getSetterMethodDecl()) { - auto *getterMethod = property->getGetterMethodDecl(); - auto *setterMethod = property->getSetterMethodDecl(); - if (!impDecl->getInstanceMethod(setterMethod->getSelector()) && - !impDecl->getInstanceMethod(getterMethod->getSelector())) { + auto *getterImpl = propertyImpl->getGetterMethodDecl(); + auto *setterImpl = propertyImpl->getSetterMethodDecl(); + if ((!getterImpl || !getterImpl->getBody()) && + (!setterImpl || !setterImpl->getBody())) { SourceLocation loc = propertyImpl->getLocation(); if (loc.isInvalid()) loc = impDecl->getBeginLoc(); Diag(loc, diag::warn_null_resettable_setter) - << setterMethod->getSelector() << property->getDeclName(); + << setterImpl->getSelector() << property->getDeclName(); } } } @@ -2138,6 +2189,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(), @@ -2161,15 +2216,13 @@ Property->getIdentifier(), Property->getQueryKind())) { if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) continue; - if (!LookedUpGetterSetter) { - GetterMethod = Property->isClassProperty() ? - IMPDecl->getClassMethod(Property->getGetterName()) : - IMPDecl->getInstanceMethod(Property->getGetterName()); - SetterMethod = Property->isClassProperty() ? - IMPDecl->getClassMethod(Property->getSetterName()) : - IMPDecl->getInstanceMethod(Property->getSetterName()); - } - if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) { + GetterMethod = PIDecl->getGetterMethodDecl(); + SetterMethod = PIDecl->getSetterMethodDecl(); + if (GetterMethod && !GetterMethod->getBody()) + GetterMethod = nullptr; + if (SetterMethod && !SetterMethod->getBody()) + SetterMethod = nullptr; + if ((bool)GetterMethod ^ (bool)SetterMethod) { SourceLocation MethodLoc = (GetterMethod ? GetterMethod->getLocation() : SetterMethod->getLocation()); @@ -2210,8 +2263,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 = PID->getGetterMethodDecl(); + 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 Index: clang/test/SemaObjC/iboutlet.m =================================================================== --- clang/test/SemaObjC/iboutlet.m +++ clang/test/SemaObjC/iboutlet.m @@ -11,7 +11,7 @@ IBInspectable @property (readonly) IBOutlet NSView *myView1; // expected-warning {{readonly IBOutlet property 'myView1' when auto-synthesized may not work correctly with 'nib' loader}} expected-note {{property should be changed to be readwrite}} -@property (getter = MyGetter, READONLY) IBOutlet NSView *myView2; // expected-warning {{readonly IBOutlet property 'myView2' when auto-synthesized may not work correctly with 'nib' loader}} +@property (getter = MyGetter2, READONLY) IBOutlet NSView *myView2; // expected-warning {{readonly IBOutlet property 'myView2' when auto-synthesized may not work correctly with 'nib' loader}} @end Index: clang/tools/libclang/CIndex.cpp =================================================================== --- clang/tools/libclang/CIndex.cpp +++ clang/tools/libclang/CIndex.cpp @@ -629,6 +629,11 @@ Decl *D = *I; if (D->getLexicalDeclContext() != DC) continue; + // Filter out synthesized property accessor redeclarations. + if (isa(DC)) + if (auto *OMD = dyn_cast(D)) + if (OMD->isImplicit() && !OMD->hasBody()) + continue; const Optional V = handleDeclForVisitation(D); if (!V.hasValue()) continue;