diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 01c2f1809771b..adea10b33188b 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -1590,6 +1590,9 @@ class DeclContext { /// True if this method is the getter or setter for an explicit property. uint64_t IsPropertyAccessor : 1; + /// True if this method is a synthesized property accessor stub. + uint64_t IsSynthesizedAccessorStub : 1; + /// Method has a definition. uint64_t IsDefined : 1; diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index 8d85ac36d8611..e5d3ebfadc06b 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -172,6 +172,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext { Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo, DeclContext *contextDecl, bool isInstance = true, bool isVariadic = false, bool isPropertyAccessor = false, + bool isSynthesizedAccessorStub = false, bool isImplicitlyDeclared = false, bool isDefined = false, ImplementationControl impControl = None, bool HasRelatedResultType = false); @@ -232,6 +233,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext { Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo, DeclContext *contextDecl, bool isInstance = true, bool isVariadic = false, bool isPropertyAccessor = false, + bool isSynthesizedAccessorStub = false, bool isImplicitlyDeclared = false, bool isDefined = false, ImplementationControl impControl = None, bool HasRelatedResultType = false); @@ -436,6 +438,14 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext { ObjCMethodDeclBits.IsPropertyAccessor = isAccessor; } + bool isSynthesizedAccessorStub() const { + return ObjCMethodDeclBits.IsSynthesizedAccessorStub; + } + + void setSynthesizedAccessorStub(bool isSynthesizedAccessorStub) { + ObjCMethodDeclBits.IsSynthesizedAccessorStub = isSynthesizedAccessorStub; + } + bool isDefined() const { return ObjCMethodDeclBits.IsDefined; } void setDefined(bool isDefined) { ObjCMethodDeclBits.IsDefined = isDefined; } @@ -2779,6 +2789,11 @@ class ObjCPropertyImplDecl : public Decl { /// 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 +2860,12 @@ class ObjCPropertyImplDecl : public Decl { 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; } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 9477e414cf554..46b978074f3df 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -3963,10 +3963,10 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { ObjCMethodDecl *ToMethod; if (GetImportedOrCreateDecl( - ToMethod, D, Importer.getToContext(), Loc, - ToEndLoc, Name.getObjCSelector(), ToReturnType, - ToReturnTypeSourceInfo, DC, D->isInstanceMethod(), D->isVariadic(), - D->isPropertyAccessor(), D->isImplicit(), D->isDefined(), + ToMethod, D, Importer.getToContext(), Loc, ToEndLoc, + Name.getObjCSelector(), ToReturnType, ToReturnTypeSourceInfo, DC, + D->isInstanceMethod(), D->isVariadic(), D->isPropertyAccessor(), + D->isSynthesizedAccessorStub(), D->isImplicit(), D->isDefined(), D->getImplementationControl(), D->hasRelatedResultType())) return ToMethod; diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index bf748fbab8e96..26017e4193dd0 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -775,14 +775,12 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateMethod( // ObjCMethodDecl //===----------------------------------------------------------------------===// -ObjCMethodDecl::ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc, - Selector SelInfo, QualType T, - TypeSourceInfo *ReturnTInfo, - DeclContext *contextDecl, bool isInstance, - bool isVariadic, bool isPropertyAccessor, - bool isImplicitlyDeclared, bool isDefined, - ImplementationControl impControl, - bool HasRelatedResultType) +ObjCMethodDecl::ObjCMethodDecl( + SourceLocation beginLoc, SourceLocation endLoc, Selector SelInfo, + QualType T, TypeSourceInfo *ReturnTInfo, DeclContext *contextDecl, + bool isInstance, bool isVariadic, bool isPropertyAccessor, + bool isSynthesizedAccessorStub, bool isImplicitlyDeclared, bool isDefined, + ImplementationControl impControl, bool HasRelatedResultType) : NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo), DeclContext(ObjCMethod), MethodDeclType(T), ReturnTInfo(ReturnTInfo), DeclEndLoc(endLoc) { @@ -793,6 +791,7 @@ ObjCMethodDecl::ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc, setInstanceMethod(isInstance); setVariadic(isVariadic); setPropertyAccessor(isPropertyAccessor); + setSynthesizedAccessorStub(isSynthesizedAccessorStub); setDefined(isDefined); setIsRedeclaration(false); setHasRedeclaration(false); @@ -810,12 +809,13 @@ ObjCMethodDecl *ObjCMethodDecl::Create( ASTContext &C, SourceLocation beginLoc, SourceLocation endLoc, Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo, DeclContext *contextDecl, bool isInstance, bool isVariadic, - bool isPropertyAccessor, bool isImplicitlyDeclared, bool isDefined, - ImplementationControl impControl, bool HasRelatedResultType) { + bool isPropertyAccessor, bool isSynthesizedAccessorStub, + bool isImplicitlyDeclared, bool isDefined, ImplementationControl impControl, + bool HasRelatedResultType) { return new (C, contextDecl) ObjCMethodDecl( beginLoc, endLoc, SelInfo, T, ReturnTInfo, contextDecl, isInstance, - isVariadic, isPropertyAccessor, isImplicitlyDeclared, isDefined, - impControl, HasRelatedResultType); + isVariadic, isPropertyAccessor, isSynthesizedAccessorStub, + isImplicitlyDeclared, isDefined, impControl, HasRelatedResultType); } ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) { @@ -1306,6 +1306,11 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const { if (isPropertyAccessor()) { const auto *Container = cast(getParent()); + // For accessor stubs, go back to the interface. + if (auto *ImplDecl = dyn_cast(Container)) + if (isSynthesizedAccessorStub()) + Container = ImplDecl->getClassInterface(); + bool IsGetter = (NumArgs == 0); bool IsInstance = isInstanceMethod(); @@ -1358,6 +1363,15 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const { } } + assert(isSynthesizedAccessorStub() && "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!"); } diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp index 43f9e715b3de2..be065ed9330fa 100644 --- a/clang/lib/Analysis/BodyFarm.cpp +++ b/clang/lib/Analysis/BodyFarm.cpp @@ -830,6 +830,16 @@ Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) { 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(); diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index 1fa72678081af..c509149af3f95 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -954,8 +954,7 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, 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 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl, 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 @@ void 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 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, 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()); diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp index d2c089d0360e1..c27023748588d 100644 --- a/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/clang/lib/CodeGen/CGObjCGNU.cpp @@ -1880,13 +1880,12 @@ class CGObjCGNUstep2 : public CGObjCGNUstep { 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 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { 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); diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index 8e28b2f05c167..d08a26f538bb0 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -3559,12 +3559,10 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { 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 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer( } 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 @@ CGObjCNonFragileABIMac::emitMethodList(Twine name, MethodListType kind, // 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); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index b7f70b8aa5c00..3cb73f6d97ce7 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -690,8 +690,7 @@ static llvm::Constant *getPrologueSignature(CodeGenModule &CGM, 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, diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index be8f389e1809c..a8cec419059e2 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -5113,11 +5113,12 @@ void CodeGenModule::EmitObjCPropertyImplementations(const // 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->isSynthesizedAccessorStub()) 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->isSynthesizedAccessorStub())) CodeGenFunction(*this).GenerateObjCSetter( const_cast(D), PID); } @@ -5154,12 +5155,13 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { if (needsDestructMethod(D)) { IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct"); Selector cxxSelector = getContext().Selectors.getSelector(0, &II); - ObjCMethodDecl *DTORMethod = - ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(), - cxxSelector, getContext().VoidTy, nullptr, D, - /*isInstance=*/true, /*isVariadic=*/false, - /*isPropertyAccessor=*/true, /*isImplicitlyDeclared=*/true, - /*isDefined=*/false, ObjCMethodDecl::Required); + ObjCMethodDecl *DTORMethod = ObjCMethodDecl::Create( + getContext(), D->getLocation(), D->getLocation(), cxxSelector, + getContext().VoidTy, nullptr, D, + /*isInstance=*/true, /*isVariadic=*/false, + /*isPropertyAccessor=*/true, /*isSynthesizedAccessorStub=*/false, + /*isImplicitlyDeclared=*/true, + /*isDefined=*/false, ObjCMethodDecl::Required); D->addInstanceMethod(DTORMethod); CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false); D->setHasDestructors(true); @@ -5174,17 +5176,13 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { IdentifierInfo *II = &getContext().Idents.get(".cxx_construct"); Selector cxxSelector = getContext().Selectors.getSelector(0, &II); // The constructor returns 'self'. - ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(), - D->getLocation(), - D->getLocation(), - cxxSelector, - getContext().getObjCIdType(), - nullptr, D, /*isInstance=*/true, - /*isVariadic=*/false, - /*isPropertyAccessor=*/true, - /*isImplicitlyDeclared=*/true, - /*isDefined=*/false, - ObjCMethodDecl::Required); + ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create( + getContext(), D->getLocation(), D->getLocation(), cxxSelector, + getContext().getObjCIdType(), nullptr, D, /*isInstance=*/true, + /*isVariadic=*/false, + /*isPropertyAccessor=*/true, /*isSynthesizedAccessorStub=*/false, + /*isImplicitlyDeclared=*/true, + /*isDefined=*/false, ObjCMethodDecl::Required); D->addInstanceMethod(CTORMethod); CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true); D->setHasNonZeroConstructors(true); diff --git a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp index 45495065ada64..831f95e8c6be4 100644 --- a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -908,9 +908,9 @@ RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) { 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->isSynthesizedAccessorStub(); } void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, @@ -952,7 +952,7 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, "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. @@ -960,7 +960,7 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, // 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) { @@ -1012,7 +1012,7 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, } 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 @@ void RewriteModernObjC::RewriteImplementationDecl(Decl *OID) { 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 @@ void RewriteModernObjC::RewriteImplementationDecl(Decl *OID) { } 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(); @@ -7031,12 +7035,12 @@ void RewriteModernObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, 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); } @@ -7281,11 +7285,11 @@ void RewriteModernObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl, 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); } diff --git a/clang/lib/Frontend/Rewrite/RewriteObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteObjC.cpp index 6a22da178fbc9..0cb7592b99820 100644 --- a/clang/lib/Frontend/Rewrite/RewriteObjC.cpp +++ b/clang/lib/Frontend/Rewrite/RewriteObjC.cpp @@ -786,8 +786,9 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, 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 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, "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 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, // 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 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, 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 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, } 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 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) { 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 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) { } 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 @@ void RewriteObjCFragileABI::RewriteObjCClassMetaData(ObjCImplementationDecl *IDe 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 @@ void RewriteObjCFragileABI::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *ID 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(), diff --git a/clang/lib/Index/IndexDecl.cpp b/clang/lib/Index/IndexDecl.cpp index 5bbbb0d32bf45..985098fc61654 100644 --- a/clang/lib/Index/IndexDecl.cpp +++ b/clang/lib/Index/IndexDecl.cpp @@ -42,15 +42,6 @@ class IndexingDeclVisitor : public ConstDeclVisitor { 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) { @@ -78,6 +69,17 @@ class IndexingDeclVisitor : public ConstDeclVisitor { } } + /// 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() && + !MD->isSynthesizedAccessorStub(); + } + + void handleDeclarator(const DeclaratorDecl *D, const NamedDecl *Parent = nullptr, bool isIBType = false) { @@ -534,13 +536,11 @@ class IndexingDeclVisitor : public ConstDeclVisitor { SymbolRoleSet AccessorMethodRoles = SymbolRoleSet(SymbolRole::Dynamic) | SymbolRoleSet(SymbolRole::Implicit); if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) { - if (MD->isPropertyAccessor() && - !hasUserDefined(MD, Container)) + if (MD->isPropertyAccessor() && !hasUserDefined(MD, Container)) IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container); } if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) { - if (MD->isPropertyAccessor() && - !hasUserDefined(MD, Container)) + if (MD->isPropertyAccessor() && !hasUserDefined(MD, Container)) IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container); } if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) { diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index db594bbd21ddc..30a1b95d42409 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -2828,6 +2828,9 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, "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 (ImpMethodDecl->isSynthesizedAccessorStub()) + continue; if (!WarnCategoryMethodImpl) WarnConflictingTypedMethods(ImpMethodDecl, I, isa(CDecl)); @@ -2854,6 +2857,9 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, "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 (ImpMethodDecl->isSynthesizedAccessorStub()) + continue; if (!WarnCategoryMethodImpl) WarnConflictingTypedMethods(ImpMethodDecl, I, isa(CDecl)); @@ -3903,6 +3909,25 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef allMethods, || isa(ClassDecl); bool checkIdenticalMethods = isa(ClassDecl); + // Make synthesized accessor stub functions visible. + // ActOnPropertyImplDecl() creates them as not visible in case + // they are overridden by an explicit method that is encountered + // later. + if (auto *OID = dyn_cast(CurContext)) { + for (auto PropImpl : OID->property_impls()) { + if (auto *Getter = PropImpl->getGetterMethodDecl()) + if (Getter->isSynthesizedAccessorStub()) { + OID->makeDeclVisibleInContext(Getter); + OID->addDecl(Getter); + } + if (auto *Setter = PropImpl->getSetterMethodDecl()) + if (Setter->isSynthesizedAccessorStub()) { + OID->makeDeclVisibleInContext(Setter); + OID->addDecl(Setter); + } + } + } + // FIXME: Remove these and use the ObjCContainerDecl/DeclContext. llvm::DenseMap InsMap; llvm::DenseMap ClsMap; @@ -4001,8 +4026,8 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef allMethods, 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 +4576,7 @@ Decl *Sema::ActOnMethodDeclaration( Diag(MethodLoc, diag::err_missing_method_context); return nullptr; } + Decl *ClassDecl = cast(CurContext); QualType resultDeclType; @@ -4574,7 +4600,7 @@ Decl *Sema::ActOnMethodDeclaration( ObjCMethodDecl *ObjCMethod = ObjCMethodDecl::Create( Context, MethodLoc, EndLoc, Sel, resultDeclType, ReturnTInfo, CurContext, MethodType == tok::minus, isVariadic, - /*isPropertyAccessor=*/false, + /*isPropertyAccessor=*/false, /*isSynthesizedAccessorStub=*/false, /*isImplicitlyDeclared=*/false, /*isDefined=*/false, MethodDeclKind == tok::objc_optional ? ObjCMethodDecl::Optional : ObjCMethodDecl::Required, @@ -4666,6 +4692,27 @@ Decl *Sema::ActOnMethodDeclaration( 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->isSynthesizedAccessorStub() && "autosynth stub expected"); + PropertyImpl->setSetterMethodDecl(ObjCMethod); + } + if (auto *Getter = PropertyImpl->getGetterMethodDecl()) + if (Getter->getSelector() == Sel && + Getter->isInstanceMethod() == ObjCMethod->isInstanceMethod()) { + assert(Getter->isSynthesizedAccessorStub() && "autosynth stub expected"); + PropertyImpl->setGetterMethodDecl(ObjCMethod); + break; + } + } + // Merge information from the @interface declaration into the // @implementation. if (ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface()) { @@ -5063,6 +5110,9 @@ void Sema::DiagnoseUnusedBackingIvarInAccessor(Scope *S, if (!IV) continue; + if (CurMethod->isSynthesizedAccessorStub()) + continue; + UnusedBackingIvarChecker Checker(*this, CurMethod, IV); Checker.TraverseStmt(CurMethod->getBody()); if (Checker.AccessedIvar) diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index e18621e42a6b1..207812c8848b7 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -288,6 +288,7 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc, S.NSNumberPointer, ReturnTInfo, S.NSNumberDecl, /*isInstance=*/false, /*isVariadic=*/false, /*isPropertyAccessor=*/false, + /*isSynthesizedAccessorStub=*/false, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, ObjCMethodDecl::Required, /*HasRelatedResultType=*/false); @@ -563,6 +564,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { NSStringPointer, ReturnTInfo, NSStringDecl, /*isInstance=*/false, /*isVariadic=*/false, /*isPropertyAccessor=*/false, + /*isSynthesizedAccessorStub=*/false, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, ObjCMethodDecl::Required, /*HasRelatedResultType=*/false); @@ -671,20 +673,15 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { // Debugger needs to work even if NSValue hasn't been defined. TypeSourceInfo *ReturnTInfo = nullptr; ObjCMethodDecl *M = ObjCMethodDecl::Create( - Context, - SourceLocation(), - SourceLocation(), - ValueWithBytesObjCType, - NSValuePointer, - ReturnTInfo, - NSValueDecl, - /*isInstance=*/false, - /*isVariadic=*/false, - /*isPropertyAccessor=*/false, - /*isImplicitlyDeclared=*/true, - /*isDefined=*/false, - ObjCMethodDecl::Required, - /*HasRelatedResultType=*/false); + Context, SourceLocation(), SourceLocation(), ValueWithBytesObjCType, + NSValuePointer, ReturnTInfo, NSValueDecl, + /*isInstance=*/false, + /*isVariadic=*/false, + /*isPropertyAccessor=*/false, + /*isSynthesizedAccessorStub=*/false, + /*isImplicitlyDeclared=*/true, + /*isDefined=*/false, ObjCMethodDecl::Required, + /*HasRelatedResultType=*/false); SmallVector Params; @@ -815,7 +812,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) { Context, SourceLocation(), SourceLocation(), Sel, IdT, ReturnTInfo, Context.getTranslationUnitDecl(), false /*Instance*/, false /*isVariadic*/, - /*isPropertyAccessor=*/false, + /*isPropertyAccessor=*/false, /*isSynthesizedAccessorStub=*/false, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, ObjCMethodDecl::Required, false); SmallVector Params; @@ -916,16 +913,14 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, NSAPI::NSDict_dictionaryWithObjectsForKeysCount); ObjCMethodDecl *Method = NSDictionaryDecl->lookupClassMethod(Sel); if (!Method && getLangOpts().DebuggerObjCLiteral) { - Method = ObjCMethodDecl::Create(Context, - SourceLocation(), SourceLocation(), Sel, - IdT, - nullptr /*TypeSourceInfo */, - Context.getTranslationUnitDecl(), - false /*Instance*/, false/*isVariadic*/, - /*isPropertyAccessor=*/false, - /*isImplicitlyDeclared=*/true, /*isDefined=*/false, - ObjCMethodDecl::Required, - false); + Method = ObjCMethodDecl::Create( + Context, SourceLocation(), SourceLocation(), Sel, IdT, + nullptr /*TypeSourceInfo */, Context.getTranslationUnitDecl(), + false /*Instance*/, false /*isVariadic*/, + /*isPropertyAccessor=*/false, + /*isSynthesizedAccessorStub=*/false, + /*isImplicitlyDeclared=*/true, /*isDefined=*/false, + ObjCMethodDecl::Required, false); SmallVector Params; ParmVarDecl *objects = ParmVarDecl::Create(Context, Method, SourceLocation(), diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index ac810745d2f5f..427def1b94ea1 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -1037,6 +1037,31 @@ static bool hasWrittenStorageAttribute(ObjCPropertyDecl *Prop, return false; } +/// Create a synthesized property accessor stub inside the \@implementation. +static ObjCMethodDecl * +RedeclarePropertyAccessor(ASTContext &Context, ObjCImplementationDecl *Impl, + ObjCMethodDecl *AccessorDecl, SourceLocation AtLoc, + SourceLocation PropertyLoc) { + ObjCMethodDecl *Decl = AccessorDecl; + ObjCMethodDecl *ImplDecl = ObjCMethodDecl::Create( + Context, AtLoc, PropertyLoc, Decl->getSelector(), Decl->getReturnType(), + Decl->getReturnTypeSourceInfo(), Impl, Decl->isInstanceMethod(), + Decl->isVariadic(), Decl->isPropertyAccessor(), /* isSynthesized*/ true, + 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 +1429,18 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, 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, 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 +1493,20 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, 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, 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 +1901,12 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl, 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 +2134,6 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, 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 +2142,16 @@ void Sema::diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl) 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->isSynthesizedAccessorStub()) && + (!setterImpl || setterImpl->isSynthesizedAccessorStub())) { 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 +2188,10 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, SetterMethod = Property->isClassProperty() ? IMPDecl->getClassMethod(Property->getSetterName()) : IMPDecl->getInstanceMethod(Property->getSetterName()); + if (GetterMethod && GetterMethod->isSynthesizedAccessorStub()) + GetterMethod = nullptr; + if (SetterMethod && SetterMethod->isSynthesizedAccessorStub()) + SetterMethod = nullptr; LookedUpGetterSetter = true; if (GetterMethod) { Diag(GetterMethod->getLocation(), @@ -2161,15 +2215,13 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, 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->isSynthesizedAccessorStub()) + GetterMethod = nullptr; + if (SetterMethod && SetterMethod->isSynthesizedAccessorStub()) + SetterMethod = nullptr; + if ((bool)GetterMethod ^ (bool)SetterMethod) { SourceLocation MethodLoc = (GetterMethod ? GetterMethod->getLocation() : SetterMethod->getLocation()); @@ -2210,8 +2262,10 @@ void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D 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->isSynthesizedAccessorStub()) + continue; ObjCMethodDecl *method = PD->getGetterMethodDecl(); if (!method) continue; @@ -2396,16 +2450,14 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { } } - GetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc, - property->getGetterName(), - resultTy, nullptr, CD, - !IsClassProperty, /*isVariadic=*/false, - /*isPropertyAccessor=*/true, - /*isImplicitlyDeclared=*/true, /*isDefined=*/false, - (property->getPropertyImplementation() == - ObjCPropertyDecl::Optional) ? - ObjCMethodDecl::Optional : - ObjCMethodDecl::Required); + GetterMethod = ObjCMethodDecl::Create( + Context, Loc, Loc, property->getGetterName(), resultTy, nullptr, CD, + !IsClassProperty, /*isVariadic=*/false, + /*isPropertyAccessor=*/true, /*isSynthesizedAccessorStub=*/false, + /*isImplicitlyDeclared=*/true, /*isDefined=*/false, + (property->getPropertyImplementation() == ObjCPropertyDecl::Optional) + ? ObjCMethodDecl::Optional + : ObjCMethodDecl::Required); CD->addDecl(GetterMethod); AddPropertyAttrs(*this, GetterMethod, property); @@ -2447,6 +2499,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { nullptr, CD, !IsClassProperty, /*isVariadic=*/false, /*isPropertyAccessor=*/true, + /*isSynthesizedAccessorStub=*/false, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, (property->getPropertyImplementation() == diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp index 06bcd8d00ded7..602806968ced2 100644 --- a/clang/lib/Sema/SemaPseudoObject.cpp +++ b/clang/lib/Sema/SemaPseudoObject.cpp @@ -1190,16 +1190,15 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() { true /*instance*/); if (!AtIndexGetter && S.getLangOpts().DebuggerObjCLiteral) { - AtIndexGetter = ObjCMethodDecl::Create(S.Context, SourceLocation(), - SourceLocation(), AtIndexGetterSelector, - S.Context.getObjCIdType() /*ReturnType*/, - nullptr /*TypeSourceInfo */, - S.Context.getTranslationUnitDecl(), - true /*Instance*/, false/*isVariadic*/, - /*isPropertyAccessor=*/false, - /*isImplicitlyDeclared=*/true, /*isDefined=*/false, - ObjCMethodDecl::Required, - false); + AtIndexGetter = ObjCMethodDecl::Create( + S.Context, SourceLocation(), SourceLocation(), AtIndexGetterSelector, + S.Context.getObjCIdType() /*ReturnType*/, nullptr /*TypeSourceInfo */, + S.Context.getTranslationUnitDecl(), true /*Instance*/, + false /*isVariadic*/, + /*isPropertyAccessor=*/false, + /*isSynthesizedAccessorStub=*/false, + /*isImplicitlyDeclared=*/true, /*isDefined=*/false, + ObjCMethodDecl::Required, false); ParmVarDecl *Argument = ParmVarDecl::Create(S.Context, AtIndexGetter, SourceLocation(), SourceLocation(), arrayRef ? &S.Context.Idents.get("index") @@ -1303,6 +1302,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() { ReturnType, ReturnTInfo, S.Context.getTranslationUnitDecl(), true /*Instance*/, false /*isVariadic*/, /*isPropertyAccessor=*/false, + /*isSynthesizedAccessorStub=*/false, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, ObjCMethodDecl::Required, false); SmallVector Params; diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 9aa8c77c62319..21d3da90de11c 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -1019,6 +1019,7 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { MD->setInstanceMethod(Record.readInt()); MD->setVariadic(Record.readInt()); MD->setPropertyAccessor(Record.readInt()); + MD->setSynthesizedAccessorStub(Record.readInt()); MD->setDefined(Record.readInt()); MD->setOverriding(Record.readInt()); MD->setHasSkippedBody(Record.readInt()); @@ -1313,6 +1314,8 @@ void ASTDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { D->setPropertyDecl(ReadDeclAs()); D->PropertyIvarDecl = ReadDeclAs(); D->IvarLoc = ReadSourceLocation(); + D->setGetterMethodDecl(ReadDeclAs()); + D->setSetterMethodDecl(ReadDeclAs()); D->setGetterCXXConstructor(Record.readExpr()); D->setSetterCXXAssignment(Record.readExpr()); } diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 039b57f88e736..b9ee8e817190f 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -673,6 +673,7 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) { Record.push_back(D->isInstanceMethod()); Record.push_back(D->isVariadic()); Record.push_back(D->isPropertyAccessor()); + Record.push_back(D->isSynthesizedAccessorStub()); Record.push_back(D->isDefined()); Record.push_back(D->isOverriding()); Record.push_back(D->hasSkippedBody()); @@ -884,6 +885,8 @@ void ASTDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { 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; diff --git a/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp b/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp index 0058f3d3881fc..0c46447e19853 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp @@ -144,6 +144,8 @@ void DirectIvarAssignment::checkASTDecl(const ObjCImplementationDecl *D, continue; const Stmt *Body = M->getBody(); + if (M->isSynthesizedAccessorStub()) + continue; assert(Body); MethodCrawler MC(IvarToPropMap, M->getCanonicalDecl(), InterD, BR, this, diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index d95f809bec1aa..e7408b805fa85 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -1080,7 +1080,7 @@ ObjCMessageKind ObjCMethodCall::getMessageKind() const { 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?"); diff --git a/clang/test/AST/ast-dump-decl-json.m b/clang/test/AST/ast-dump-decl-json.m index 235533d0bff9b..168b1f5ab29dc 100644 --- a/clang/test/AST/ast-dump-decl-json.m +++ b/clang/test/AST/ast-dump-decl-json.m @@ -1475,7 +1475,173 @@ void f() { // 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: "offset": 1109, +// CHECK-NEXT: "line": 70, +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 1109, +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 1121, +// 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: "offset": 1109, +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 1109, +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 1121, +// 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: "offset": 1033, +// CHECK-NEXT: "line": 63, +// CHECK-NEXT: "col": 52, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 1033, +// CHECK-NEXT: "col": 52, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 1033, +// 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: "offset": 1128, +// CHECK-NEXT: "line": 71, +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 1128, +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 1140, +// 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: "offset": 1128, +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 1128, +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 1140, +// 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: "offset": 1052, +// CHECK-NEXT: "line": 64, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 1052, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 1052, +// 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: } diff --git a/clang/test/Analysis/Inputs/expected-plists/nullability-notes.m.plist b/clang/test/Analysis/Inputs/expected-plists/nullability-notes.m.plist index 314af1e4c952b..5e915d63ffde8 100644 --- a/clang/test/Analysis/Inputs/expected-plists/nullability-notes.m.plist +++ b/clang/test/Analysis/Inputs/expected-plists/nullability-notes.m.plist @@ -188,7 +188,6 @@ 0 - 10 14 16 17 diff --git a/clang/test/CodeGenObjC/debug-info-synthesis.m b/clang/test/CodeGenObjC/debug-info-synthesis.m index f954256282814..7fbbc6dd3182e 100644 --- a/clang/test/CodeGenObjC/debug-info-synthesis.m +++ b/clang/test/CodeGenObjC/debug-info-synthesis.m @@ -30,8 +30,8 @@ int main(int argc, char *argv[]) { } } -// 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 diff --git a/clang/test/CodeGenObjC/debug-property-synth.m b/clang/test/CodeGenObjC/debug-property-synth.m index 124c61ea88cde..ddcf4d998c5cd 100644 --- a/clang/test/CodeGenObjC/debug-property-synth.m +++ b/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 @@ @interface I { // 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 diff --git a/clang/test/CodeGenObjC/debuginfo-properties.m b/clang/test/CodeGenObjC/debuginfo-properties.m index c0de620abd966..53f5e2de890bd 100644 --- a/clang/test/CodeGenObjC/debuginfo-properties.m +++ b/clang/test/CodeGenObjC/debuginfo-properties.m @@ -11,19 +11,6 @@ @interface NSObject {} @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 @@ @interface MyClass : NSObject { @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 @@ @interface OtherClass : NSObject { @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 diff --git a/clang/test/CodeGenObjC/instance-method-metadata.m b/clang/test/CodeGenObjC/instance-method-metadata.m index 96f499c9fa94a..e08de8fdacec2 100644 --- a/clang/test/CodeGenObjC/instance-method-metadata.m +++ b/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 diff --git a/clang/test/SemaObjC/iboutlet.m b/clang/test/SemaObjC/iboutlet.m index 7bd86d4668b3a..1d8ec9965c2af 100644 --- a/clang/test/SemaObjC/iboutlet.m +++ b/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 diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 48e8b61515812..ada5d7551d731 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -629,6 +629,11 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) { 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->isSynthesizedAccessorStub()) + continue; const Optional V = handleDeclForVisitation(D); if (!V.hasValue()) continue;