Redeclare Objective-C property accessors inside the ObjCImplDecl in which they are synthesized.

This patch is motivated by (and factored out from)
https://reviews.llvm.org/D66121 which is a debug info bugfix. Starting
with DWARF 5 all Objective-C methods are nested inside their
containing type, and that patch implements this for synthesized
Objective-C properties.

1. SemaObjCProperty populates a list of synthesized accessors that may
   need to inserted into an ObjCImplDecl.

2. SemaDeclObjC::ActOnEnd inserts forward-declarations for all
   accessors for which no override was provided into their
   ObjCImplDecl. This patch does *not* synthesize AST function
   *bodies*. Moving that code from the static analyzer into Sema may
   be a good idea though.

3. Places that expect all methods to have bodies have been updated.

I did not update the static analyzer's inliner for synthesized
properties to point back to the property declaration (see
test/Analysis/Inputs/expected-plists/nullability-notes.m.plist), which
I believed to be more bug than a feature.

Differential Revision: https://reviews.llvm.org/D68108

rdar://problem/53782400
This commit is contained in:
Adrian Prantl 2019-11-04 14:28:14 -08:00
parent 8d22100f66
commit 2073dd2da7
29 changed files with 505 additions and 197 deletions

View File

@ -1590,6 +1590,9 @@ class DeclContext {
/// True if this method is the getter or setter for an explicit property. /// True if this method is the getter or setter for an explicit property.
uint64_t IsPropertyAccessor : 1; uint64_t IsPropertyAccessor : 1;
/// True if this method is a synthesized property accessor stub.
uint64_t IsSynthesizedAccessorStub : 1;
/// Method has a definition. /// Method has a definition.
uint64_t IsDefined : 1; uint64_t IsDefined : 1;

View File

@ -172,6 +172,7 @@ private:
Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo, Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo,
DeclContext *contextDecl, bool isInstance = true, DeclContext *contextDecl, bool isInstance = true,
bool isVariadic = false, bool isPropertyAccessor = false, bool isVariadic = false, bool isPropertyAccessor = false,
bool isSynthesizedAccessorStub = false,
bool isImplicitlyDeclared = false, bool isDefined = false, bool isImplicitlyDeclared = false, bool isDefined = false,
ImplementationControl impControl = None, ImplementationControl impControl = None,
bool HasRelatedResultType = false); bool HasRelatedResultType = false);
@ -232,6 +233,7 @@ public:
Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo, Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo,
DeclContext *contextDecl, bool isInstance = true, DeclContext *contextDecl, bool isInstance = true,
bool isVariadic = false, bool isPropertyAccessor = false, bool isVariadic = false, bool isPropertyAccessor = false,
bool isSynthesizedAccessorStub = false,
bool isImplicitlyDeclared = false, bool isDefined = false, bool isImplicitlyDeclared = false, bool isDefined = false,
ImplementationControl impControl = None, ImplementationControl impControl = None,
bool HasRelatedResultType = false); bool HasRelatedResultType = false);
@ -436,6 +438,14 @@ public:
ObjCMethodDeclBits.IsPropertyAccessor = isAccessor; ObjCMethodDeclBits.IsPropertyAccessor = isAccessor;
} }
bool isSynthesizedAccessorStub() const {
return ObjCMethodDeclBits.IsSynthesizedAccessorStub;
}
void setSynthesizedAccessorStub(bool isSynthesizedAccessorStub) {
ObjCMethodDeclBits.IsSynthesizedAccessorStub = isSynthesizedAccessorStub;
}
bool isDefined() const { return ObjCMethodDeclBits.IsDefined; } bool isDefined() const { return ObjCMethodDeclBits.IsDefined; }
void setDefined(bool isDefined) { ObjCMethodDeclBits.IsDefined = isDefined; } void setDefined(bool isDefined) { ObjCMethodDeclBits.IsDefined = isDefined; }
@ -2779,6 +2789,11 @@ private:
/// Null for \@dynamic. Required for \@synthesize. /// Null for \@dynamic. Required for \@synthesize.
ObjCIvarDecl *PropertyIvarDecl; 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 /// Null for \@dynamic. Non-null if property must be copy-constructed in
/// getter. /// getter.
Expr *GetterCXXConstructor = nullptr; Expr *GetterCXXConstructor = nullptr;
@ -2845,6 +2860,12 @@ public:
return IvarLoc.isValid() && IvarLoc != getLocation(); 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 { Expr *getGetterCXXConstructor() const {
return GetterCXXConstructor; return GetterCXXConstructor;
} }

View File

@ -3963,10 +3963,10 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
ObjCMethodDecl *ToMethod; ObjCMethodDecl *ToMethod;
if (GetImportedOrCreateDecl( if (GetImportedOrCreateDecl(
ToMethod, D, Importer.getToContext(), Loc, ToMethod, D, Importer.getToContext(), Loc, ToEndLoc,
ToEndLoc, Name.getObjCSelector(), ToReturnType, Name.getObjCSelector(), ToReturnType, ToReturnTypeSourceInfo, DC,
ToReturnTypeSourceInfo, DC, D->isInstanceMethod(), D->isVariadic(), D->isInstanceMethod(), D->isVariadic(), D->isPropertyAccessor(),
D->isPropertyAccessor(), D->isImplicit(), D->isDefined(), D->isSynthesizedAccessorStub(), D->isImplicit(), D->isDefined(),
D->getImplementationControl(), D->hasRelatedResultType())) D->getImplementationControl(), D->hasRelatedResultType()))
return ToMethod; return ToMethod;

View File

@ -775,14 +775,12 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateMethod(
// ObjCMethodDecl // ObjCMethodDecl
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
ObjCMethodDecl::ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc, ObjCMethodDecl::ObjCMethodDecl(
Selector SelInfo, QualType T, SourceLocation beginLoc, SourceLocation endLoc, Selector SelInfo,
TypeSourceInfo *ReturnTInfo, QualType T, TypeSourceInfo *ReturnTInfo, DeclContext *contextDecl,
DeclContext *contextDecl, bool isInstance, bool isInstance, bool isVariadic, bool isPropertyAccessor,
bool isVariadic, bool isPropertyAccessor, bool isSynthesizedAccessorStub, bool isImplicitlyDeclared, bool isDefined,
bool isImplicitlyDeclared, bool isDefined, ImplementationControl impControl, bool HasRelatedResultType)
ImplementationControl impControl,
bool HasRelatedResultType)
: NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo), : NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo),
DeclContext(ObjCMethod), MethodDeclType(T), ReturnTInfo(ReturnTInfo), DeclContext(ObjCMethod), MethodDeclType(T), ReturnTInfo(ReturnTInfo),
DeclEndLoc(endLoc) { DeclEndLoc(endLoc) {
@ -793,6 +791,7 @@ ObjCMethodDecl::ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc,
setInstanceMethod(isInstance); setInstanceMethod(isInstance);
setVariadic(isVariadic); setVariadic(isVariadic);
setPropertyAccessor(isPropertyAccessor); setPropertyAccessor(isPropertyAccessor);
setSynthesizedAccessorStub(isSynthesizedAccessorStub);
setDefined(isDefined); setDefined(isDefined);
setIsRedeclaration(false); setIsRedeclaration(false);
setHasRedeclaration(false); setHasRedeclaration(false);
@ -810,12 +809,13 @@ ObjCMethodDecl *ObjCMethodDecl::Create(
ASTContext &C, SourceLocation beginLoc, SourceLocation endLoc, ASTContext &C, SourceLocation beginLoc, SourceLocation endLoc,
Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo, Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo,
DeclContext *contextDecl, bool isInstance, bool isVariadic, DeclContext *contextDecl, bool isInstance, bool isVariadic,
bool isPropertyAccessor, bool isImplicitlyDeclared, bool isDefined, bool isPropertyAccessor, bool isSynthesizedAccessorStub,
ImplementationControl impControl, bool HasRelatedResultType) { bool isImplicitlyDeclared, bool isDefined, ImplementationControl impControl,
bool HasRelatedResultType) {
return new (C, contextDecl) ObjCMethodDecl( return new (C, contextDecl) ObjCMethodDecl(
beginLoc, endLoc, SelInfo, T, ReturnTInfo, contextDecl, isInstance, beginLoc, endLoc, SelInfo, T, ReturnTInfo, contextDecl, isInstance,
isVariadic, isPropertyAccessor, isImplicitlyDeclared, isDefined, isVariadic, isPropertyAccessor, isSynthesizedAccessorStub,
impControl, HasRelatedResultType); isImplicitlyDeclared, isDefined, impControl, HasRelatedResultType);
} }
ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) { ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
@ -1306,6 +1306,11 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
if (isPropertyAccessor()) { if (isPropertyAccessor()) {
const auto *Container = cast<ObjCContainerDecl>(getParent()); const auto *Container = cast<ObjCContainerDecl>(getParent());
// For accessor stubs, go back to the interface.
if (auto *ImplDecl = dyn_cast<ObjCImplDecl>(Container))
if (isSynthesizedAccessorStub())
Container = ImplDecl->getClassInterface();
bool IsGetter = (NumArgs == 0); bool IsGetter = (NumArgs == 0);
bool IsInstance = isInstanceMethod(); 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!"); llvm_unreachable("Marked as a property accessor but no property found!");
} }

View File

@ -830,6 +830,16 @@ Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) {
if (D->param_size() != 0) if (D->param_size() != 0)
return nullptr; return nullptr;
// If the property was defined in an extension, search the extensions for
// overrides.
const ObjCInterfaceDecl *OID = D->getClassInterface();
if (dyn_cast<ObjCInterfaceDecl>(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); Val = createObjCPropertyGetter(C, Prop);
return Val.getValue(); return Val.getValue();

View File

@ -954,8 +954,7 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID) { const ObjCPropertyImplDecl *PID) {
llvm::Constant *AtomicHelperFn = llvm::Constant *AtomicHelperFn =
CodeGenFunction(CGM).GenerateObjCAtomicGetterCopyHelperFunction(PID); CodeGenFunction(CGM).GenerateObjCAtomicGetterCopyHelperFunction(PID);
const ObjCPropertyDecl *PD = PID->getPropertyDecl(); ObjCMethodDecl *OMD = PID->getGetterMethodDecl();
ObjCMethodDecl *OMD = PD->getGetterMethodDecl();
assert(OMD && "Invalid call to generate getter (empty method)"); assert(OMD && "Invalid call to generate getter (empty method)");
StartObjCMethod(OMD, IMP->getClassInterface()); StartObjCMethod(OMD, IMP->getClassInterface());
@ -1041,7 +1040,7 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
const ObjCPropertyDecl *prop = propImpl->getPropertyDecl(); const ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
QualType propType = prop->getType(); QualType propType = prop->getType();
ObjCMethodDecl *getterMethod = prop->getGetterMethodDecl(); ObjCMethodDecl *getterMethod = propImpl->getGetterMethodDecl();
ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl(); ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
@ -1311,9 +1310,8 @@ void
CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl, CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
const ObjCPropertyImplDecl *propImpl, const ObjCPropertyImplDecl *propImpl,
llvm::Constant *AtomicHelperFn) { llvm::Constant *AtomicHelperFn) {
const ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl(); 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 // Just use the setter expression if Sema gave us one and it's
// non-trivial. // non-trivial.
@ -1490,8 +1488,7 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID) { const ObjCPropertyImplDecl *PID) {
llvm::Constant *AtomicHelperFn = llvm::Constant *AtomicHelperFn =
CodeGenFunction(CGM).GenerateObjCAtomicSetterCopyHelperFunction(PID); CodeGenFunction(CGM).GenerateObjCAtomicSetterCopyHelperFunction(PID);
const ObjCPropertyDecl *PD = PID->getPropertyDecl(); ObjCMethodDecl *OMD = PID->getSetterMethodDecl();
ObjCMethodDecl *OMD = PD->getSetterMethodDecl();
assert(OMD && "Invalid call to generate setter (empty method)"); assert(OMD && "Invalid call to generate setter (empty method)");
StartObjCMethod(OMD, IMP->getClassInterface()); StartObjCMethod(OMD, IMP->getClassInterface());

View File

@ -1880,13 +1880,12 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
for (auto *propImpl : OID->property_impls()) for (auto *propImpl : OID->property_impls())
if (propImpl->getPropertyImplementation() == if (propImpl->getPropertyImplementation() ==
ObjCPropertyImplDecl::Synthesize) { ObjCPropertyImplDecl::Synthesize) {
ObjCPropertyDecl *prop = propImpl->getPropertyDecl(); auto addIfExists = [&](const ObjCMethodDecl *OMD) {
auto addIfExists = [&](const ObjCMethodDecl* OMD) { if (OMD && OMD->hasBody())
if (OMD)
InstanceMethods.push_back(OMD); InstanceMethods.push_back(OMD);
}; };
addIfExists(prop->getGetterMethodDecl()); addIfExists(propImpl->getGetterMethodDecl());
addIfExists(prop->getSetterMethodDecl()); addIfExists(propImpl->getSetterMethodDecl());
} }
if (InstanceMethods.size() == 0) if (InstanceMethods.size() == 0)
@ -3494,13 +3493,12 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
for (auto *propertyImpl : OID->property_impls()) for (auto *propertyImpl : OID->property_impls())
if (propertyImpl->getPropertyImplementation() == if (propertyImpl->getPropertyImplementation() ==
ObjCPropertyImplDecl::Synthesize) { ObjCPropertyImplDecl::Synthesize) {
ObjCPropertyDecl *property = propertyImpl->getPropertyDecl();
auto addPropertyMethod = [&](const ObjCMethodDecl *accessor) { auto addPropertyMethod = [&](const ObjCMethodDecl *accessor) {
if (accessor) if (accessor)
InstanceMethods.push_back(accessor); InstanceMethods.push_back(accessor);
}; };
addPropertyMethod(property->getGetterMethodDecl()); addPropertyMethod(propertyImpl->getGetterMethodDecl());
addPropertyMethod(property->getSetterMethodDecl()); addPropertyMethod(propertyImpl->getSetterMethodDecl());
} }
llvm::Constant *Properties = GeneratePropertyList(OID, ClassDecl); llvm::Constant *Properties = GeneratePropertyList(OID, ClassDecl);

View File

@ -3559,12 +3559,10 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
for (const auto *PID : ID->property_impls()) { for (const auto *PID : ID->property_impls()) {
if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) { if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) {
ObjCPropertyDecl *PD = PID->getPropertyDecl(); if (ObjCMethodDecl *MD = PID->getGetterMethodDecl())
if (ObjCMethodDecl *MD = PD->getGetterMethodDecl())
if (GetMethodDefinition(MD)) if (GetMethodDefinition(MD))
Methods[InstanceMethods].push_back(MD); Methods[InstanceMethods].push_back(MD);
if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) if (ObjCMethodDecl *MD = PID->getSetterMethodDecl())
if (GetMethodDefinition(MD)) if (GetMethodDefinition(MD))
Methods[InstanceMethods].push_back(MD); Methods[InstanceMethods].push_back(MD);
} }
@ -6232,19 +6230,6 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
} else { } else {
for (const auto *MD : ID->instance_methods()) for (const auto *MD : ID->instance_methods())
methods.push_back(MD); 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(), values.add(emitMethodList(ID->getObjCRuntimeNameAsString(),
@ -6707,9 +6692,8 @@ CGObjCNonFragileABIMac::emitMethodList(Twine name, MethodListType kind,
// method_count // method_count
values.addInt(ObjCTypes.IntTy, methods.size()); values.addInt(ObjCTypes.IntTy, methods.size());
auto methodArray = values.beginArray(ObjCTypes.MethodTy); auto methodArray = values.beginArray(ObjCTypes.MethodTy);
for (auto MD : methods) { for (auto MD : methods)
emitMethodConstant(methodArray, MD, forProtocol); emitMethodConstant(methodArray, MD, forProtocol);
}
methodArray.finishAndAddTo(values); methodArray.finishAndAddTo(values);
llvm::GlobalVariable *GV = finishAndCreateGlobal(values, prefix + name, CGM); llvm::GlobalVariable *GV = finishAndCreateGlobal(values, prefix + name, CGM);

View File

@ -690,8 +690,7 @@ static llvm::Constant *getPrologueSignature(CodeGenModule &CGM,
return CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM); return CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM);
} }
void CodeGenFunction::StartFunction(GlobalDecl GD, void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
QualType RetTy,
llvm::Function *Fn, llvm::Function *Fn,
const CGFunctionInfo &FnInfo, const CGFunctionInfo &FnInfo,
const FunctionArgList &Args, const FunctionArgList &Args,

View File

@ -5113,11 +5113,12 @@ void CodeGenModule::EmitObjCPropertyImplementations(const
// we want, that just indicates if the decl came from a // we want, that just indicates if the decl came from a
// property. What we want to know is if the method is defined in // property. What we want to know is if the method is defined in
// this implementation. // this implementation.
if (!D->getInstanceMethod(PD->getGetterName())) auto *Getter = PID->getGetterMethodDecl();
if (!Getter || Getter->isSynthesizedAccessorStub())
CodeGenFunction(*this).GenerateObjCGetter( CodeGenFunction(*this).GenerateObjCGetter(
const_cast<ObjCImplementationDecl *>(D), PID); const_cast<ObjCImplementationDecl *>(D), PID);
if (!PD->isReadOnly() && auto *Setter = PID->getSetterMethodDecl();
!D->getInstanceMethod(PD->getSetterName())) if (!PD->isReadOnly() && (!Setter || Setter->isSynthesizedAccessorStub()))
CodeGenFunction(*this).GenerateObjCSetter( CodeGenFunction(*this).GenerateObjCSetter(
const_cast<ObjCImplementationDecl *>(D), PID); const_cast<ObjCImplementationDecl *>(D), PID);
} }
@ -5154,12 +5155,13 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
if (needsDestructMethod(D)) { if (needsDestructMethod(D)) {
IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct"); IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct");
Selector cxxSelector = getContext().Selectors.getSelector(0, &II); Selector cxxSelector = getContext().Selectors.getSelector(0, &II);
ObjCMethodDecl *DTORMethod = ObjCMethodDecl *DTORMethod = ObjCMethodDecl::Create(
ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(), getContext(), D->getLocation(), D->getLocation(), cxxSelector,
cxxSelector, getContext().VoidTy, nullptr, D, getContext().VoidTy, nullptr, D,
/*isInstance=*/true, /*isVariadic=*/false, /*isInstance=*/true, /*isVariadic=*/false,
/*isPropertyAccessor=*/true, /*isImplicitlyDeclared=*/true, /*isPropertyAccessor=*/true, /*isSynthesizedAccessorStub=*/false,
/*isDefined=*/false, ObjCMethodDecl::Required); /*isImplicitlyDeclared=*/true,
/*isDefined=*/false, ObjCMethodDecl::Required);
D->addInstanceMethod(DTORMethod); D->addInstanceMethod(DTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false); CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false);
D->setHasDestructors(true); D->setHasDestructors(true);
@ -5174,17 +5176,13 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
IdentifierInfo *II = &getContext().Idents.get(".cxx_construct"); IdentifierInfo *II = &getContext().Idents.get(".cxx_construct");
Selector cxxSelector = getContext().Selectors.getSelector(0, &II); Selector cxxSelector = getContext().Selectors.getSelector(0, &II);
// The constructor returns 'self'. // The constructor returns 'self'.
ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(), ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(
D->getLocation(), getContext(), D->getLocation(), D->getLocation(), cxxSelector,
D->getLocation(), getContext().getObjCIdType(), nullptr, D, /*isInstance=*/true,
cxxSelector, /*isVariadic=*/false,
getContext().getObjCIdType(), /*isPropertyAccessor=*/true, /*isSynthesizedAccessorStub=*/false,
nullptr, D, /*isInstance=*/true, /*isImplicitlyDeclared=*/true,
/*isVariadic=*/false, /*isDefined=*/false, ObjCMethodDecl::Required);
/*isPropertyAccessor=*/true,
/*isImplicitlyDeclared=*/true,
/*isDefined=*/false,
ObjCMethodDecl::Required);
D->addInstanceMethod(CTORMethod); D->addInstanceMethod(CTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true); CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true);
D->setHasNonZeroConstructors(true); D->setHasNonZeroConstructors(true);

View File

@ -908,9 +908,9 @@ RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) {
static bool mustSynthesizeSetterGetterMethod(ObjCImplementationDecl *IMP, static bool mustSynthesizeSetterGetterMethod(ObjCImplementationDecl *IMP,
ObjCPropertyDecl *PD, ObjCPropertyDecl *PD,
bool getter) { bool getter) {
return getter ? !IMP->getInstanceMethod(PD->getGetterName()) auto *OMD = IMP->getInstanceMethod(getter ? PD->getGetterName()
: !IMP->getInstanceMethod(PD->getSetterName()); : PD->getSetterName());
return !OMD || OMD->isSynthesizedAccessorStub();
} }
void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
@ -952,7 +952,7 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
"id objc_getProperty(id, SEL, long, bool);\n"; "id objc_getProperty(id, SEL, long, bool);\n";
} }
RewriteObjCMethodDecl(OID->getContainingInterface(), RewriteObjCMethodDecl(OID->getContainingInterface(),
PD->getGetterMethodDecl(), Getr); PID->getGetterMethodDecl(), Getr);
Getr += "{ "; Getr += "{ ";
// Synthesize an explicit cast to gain access to the ivar. // Synthesize an explicit cast to gain access to the ivar.
// See objc-act.c:objc_synthesize_new_getter() for details. // 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) // return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1)
Getr += "typedef "; Getr += "typedef ";
const FunctionType *FPRetType = nullptr; const FunctionType *FPRetType = nullptr;
RewriteTypeIntoString(PD->getGetterMethodDecl()->getReturnType(), Getr, RewriteTypeIntoString(PID->getGetterMethodDecl()->getReturnType(), Getr,
FPRetType); FPRetType);
Getr += " _TYPE"; Getr += " _TYPE";
if (FPRetType) { if (FPRetType) {
@ -1012,7 +1012,7 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
} }
RewriteObjCMethodDecl(OID->getContainingInterface(), RewriteObjCMethodDecl(OID->getContainingInterface(),
PD->getSetterMethodDecl(), Setr); PID->getSetterMethodDecl(), Setr);
Setr += "{ "; Setr += "{ ";
// Synthesize an explicit cast to initialize the ivar. // Synthesize an explicit cast to initialize the ivar.
// See objc-act.c:objc_synthesize_new_setter() for details. // See objc-act.c:objc_synthesize_new_setter() for details.
@ -1346,6 +1346,8 @@ void RewriteModernObjC::RewriteImplementationDecl(Decl *OID) {
InsertText(CID->getBeginLoc(), "// "); InsertText(CID->getBeginLoc(), "// ");
for (auto *OMD : IMD ? IMD->instance_methods() : CID->instance_methods()) { for (auto *OMD : IMD ? IMD->instance_methods() : CID->instance_methods()) {
if (!OMD->getBody())
continue;
std::string ResultStr; std::string ResultStr;
RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr);
SourceLocation LocStart = OMD->getBeginLoc(); SourceLocation LocStart = OMD->getBeginLoc();
@ -1357,6 +1359,8 @@ void RewriteModernObjC::RewriteImplementationDecl(Decl *OID) {
} }
for (auto *OMD : IMD ? IMD->class_methods() : CID->class_methods()) { for (auto *OMD : IMD ? IMD->class_methods() : CID->class_methods()) {
if (!OMD->getBody())
continue;
std::string ResultStr; std::string ResultStr;
RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr);
SourceLocation LocStart = OMD->getBeginLoc(); SourceLocation LocStart = OMD->getBeginLoc();
@ -7031,12 +7035,12 @@ void RewriteModernObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
ObjCPropertyDecl *PD = Prop->getPropertyDecl(); ObjCPropertyDecl *PD = Prop->getPropertyDecl();
if (!PD) if (!PD)
continue; continue;
if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl())
if (mustSynthesizeSetterGetterMethod(IDecl, PD, true /*getter*/)) if (mustSynthesizeSetterGetterMethod(IDecl, PD, true /*getter*/))
InstanceMethods.push_back(Getter); InstanceMethods.push_back(Getter);
if (PD->isReadOnly()) if (PD->isReadOnly())
continue; continue;
if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl())
if (mustSynthesizeSetterGetterMethod(IDecl, PD, false /*setter*/)) if (mustSynthesizeSetterGetterMethod(IDecl, PD, false /*setter*/))
InstanceMethods.push_back(Setter); InstanceMethods.push_back(Setter);
} }
@ -7281,11 +7285,11 @@ void RewriteModernObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
ObjCPropertyDecl *PD = Prop->getPropertyDecl(); ObjCPropertyDecl *PD = Prop->getPropertyDecl();
if (!PD) if (!PD)
continue; continue;
if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl())
InstanceMethods.push_back(Getter); InstanceMethods.push_back(Getter);
if (PD->isReadOnly()) if (PD->isReadOnly())
continue; continue;
if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl())
InstanceMethods.push_back(Setter); InstanceMethods.push_back(Setter);
} }

View File

@ -786,8 +786,9 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
if (!OID) if (!OID)
return; return;
unsigned Attributes = PD->getPropertyAttributes(); unsigned Attributes = PD->getPropertyAttributes();
if (!PD->getGetterMethodDecl()->isDefined()) { if (PID->getGetterMethodDecl() && !PID->getGetterMethodDecl()->isDefined()) {
bool GenGetProperty = !(Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) && bool GenGetProperty = !(Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) &&
(Attributes & (ObjCPropertyDecl::OBJC_PR_retain | (Attributes & (ObjCPropertyDecl::OBJC_PR_retain |
ObjCPropertyDecl::OBJC_PR_copy)); ObjCPropertyDecl::OBJC_PR_copy));
@ -799,7 +800,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
"id objc_getProperty(id, SEL, long, bool);\n"; "id objc_getProperty(id, SEL, long, bool);\n";
} }
RewriteObjCMethodDecl(OID->getContainingInterface(), RewriteObjCMethodDecl(OID->getContainingInterface(),
PD->getGetterMethodDecl(), Getr); PID->getGetterMethodDecl(), Getr);
Getr += "{ "; Getr += "{ ";
// Synthesize an explicit cast to gain access to the ivar. // Synthesize an explicit cast to gain access to the ivar.
// See objc-act.c:objc_synthesize_new_getter() for details. // 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) // return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1)
Getr += "typedef "; Getr += "typedef ";
const FunctionType *FPRetType = nullptr; const FunctionType *FPRetType = nullptr;
RewriteTypeIntoString(PD->getGetterMethodDecl()->getReturnType(), Getr, RewriteTypeIntoString(PID->getGetterMethodDecl()->getReturnType(), Getr,
FPRetType); FPRetType);
Getr += " _TYPE"; Getr += " _TYPE";
if (FPRetType) { if (FPRetType) {
@ -843,7 +844,8 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
InsertText(onePastSemiLoc, Getr); InsertText(onePastSemiLoc, Getr);
} }
if (PD->isReadOnly() || PD->getSetterMethodDecl()->isDefined()) if (PD->isReadOnly() || !PID->getSetterMethodDecl() ||
PID->getSetterMethodDecl()->isDefined())
return; return;
// Generate the 'setter' function. // Generate the 'setter' function.
@ -858,7 +860,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
} }
RewriteObjCMethodDecl(OID->getContainingInterface(), RewriteObjCMethodDecl(OID->getContainingInterface(),
PD->getSetterMethodDecl(), Setr); PID->getSetterMethodDecl(), Setr);
Setr += "{ "; Setr += "{ ";
// Synthesize an explicit cast to initialize the ivar. // Synthesize an explicit cast to initialize the ivar.
// See objc-act.c:objc_synthesize_new_setter() for details. // 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(), "// "); InsertText(IMD ? IMD->getBeginLoc() : CID->getBeginLoc(), "// ");
for (auto *OMD : IMD ? IMD->instance_methods() : CID->instance_methods()) { for (auto *OMD : IMD ? IMD->instance_methods() : CID->instance_methods()) {
if (!OMD->getBody())
continue;
std::string ResultStr; std::string ResultStr;
RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr);
SourceLocation LocStart = OMD->getBeginLoc(); SourceLocation LocStart = OMD->getBeginLoc();
@ -1179,6 +1183,8 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
} }
for (auto *OMD : IMD ? IMD->class_methods() : CID->class_methods()) { for (auto *OMD : IMD ? IMD->class_methods() : CID->class_methods()) {
if (!OMD->getBody())
continue;
std::string ResultStr; std::string ResultStr;
RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr);
SourceLocation LocStart = OMD->getBeginLoc(); SourceLocation LocStart = OMD->getBeginLoc();
@ -5355,12 +5361,12 @@ void RewriteObjCFragileABI::RewriteObjCClassMetaData(ObjCImplementationDecl *IDe
ObjCPropertyDecl *PD = Prop->getPropertyDecl(); ObjCPropertyDecl *PD = Prop->getPropertyDecl();
if (!PD) if (!PD)
continue; continue;
if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl())
if (!Getter->isDefined()) if (!Getter->isDefined())
InstanceMethods.push_back(Getter); InstanceMethods.push_back(Getter);
if (PD->isReadOnly()) if (PD->isReadOnly())
continue; continue;
if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl())
if (!Setter->isDefined()) if (!Setter->isDefined())
InstanceMethods.push_back(Setter); InstanceMethods.push_back(Setter);
} }
@ -5633,11 +5639,11 @@ void RewriteObjCFragileABI::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *ID
ObjCPropertyDecl *PD = Prop->getPropertyDecl(); ObjCPropertyDecl *PD = Prop->getPropertyDecl();
if (!PD) if (!PD)
continue; continue;
if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl())
InstanceMethods.push_back(Getter); InstanceMethods.push_back(Getter);
if (PD->isReadOnly()) if (PD->isReadOnly())
continue; continue;
if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl())
InstanceMethods.push_back(Setter); InstanceMethods.push_back(Setter);
} }
RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(), RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(),

View File

@ -42,15 +42,6 @@ public:
return true; 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, void handleTemplateArgumentLoc(const TemplateArgumentLoc &TALoc,
const NamedDecl *Parent, const NamedDecl *Parent,
const DeclContext *DC) { const DeclContext *DC) {
@ -78,6 +69,17 @@ public:
} }
} }
/// 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, void handleDeclarator(const DeclaratorDecl *D,
const NamedDecl *Parent = nullptr, const NamedDecl *Parent = nullptr,
bool isIBType = false) { bool isIBType = false) {
@ -534,13 +536,11 @@ public:
SymbolRoleSet AccessorMethodRoles = SymbolRoleSet AccessorMethodRoles =
SymbolRoleSet(SymbolRole::Dynamic) | SymbolRoleSet(SymbolRole::Implicit); SymbolRoleSet(SymbolRole::Dynamic) | SymbolRoleSet(SymbolRole::Implicit);
if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) { if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) {
if (MD->isPropertyAccessor() && if (MD->isPropertyAccessor() && !hasUserDefined(MD, Container))
!hasUserDefined(MD, Container))
IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container); IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container);
} }
if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) { if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) {
if (MD->isPropertyAccessor() && if (MD->isPropertyAccessor() && !hasUserDefined(MD, Container))
!hasUserDefined(MD, Container))
IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container); IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container);
} }
if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) { if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) {

View File

@ -2828,6 +2828,9 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
"Expected to find the method through lookup as well"); "Expected to find the method through lookup as well");
// ImpMethodDecl may be null as in a @dynamic property. // ImpMethodDecl may be null as in a @dynamic property.
if (ImpMethodDecl) { if (ImpMethodDecl) {
// Skip property accessor function stubs.
if (ImpMethodDecl->isSynthesizedAccessorStub())
continue;
if (!WarnCategoryMethodImpl) if (!WarnCategoryMethodImpl)
WarnConflictingTypedMethods(ImpMethodDecl, I, WarnConflictingTypedMethods(ImpMethodDecl, I,
isa<ObjCProtocolDecl>(CDecl)); isa<ObjCProtocolDecl>(CDecl));
@ -2854,6 +2857,9 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
"Expected to find the method through lookup as well"); "Expected to find the method through lookup as well");
// ImpMethodDecl may be null as in a @dynamic property. // ImpMethodDecl may be null as in a @dynamic property.
if (ImpMethodDecl) { if (ImpMethodDecl) {
// Skip property accessor function stubs.
if (ImpMethodDecl->isSynthesizedAccessorStub())
continue;
if (!WarnCategoryMethodImpl) if (!WarnCategoryMethodImpl)
WarnConflictingTypedMethods(ImpMethodDecl, I, WarnConflictingTypedMethods(ImpMethodDecl, I,
isa<ObjCProtocolDecl>(CDecl)); isa<ObjCProtocolDecl>(CDecl));
@ -3903,6 +3909,25 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
|| isa<ObjCProtocolDecl>(ClassDecl); || isa<ObjCProtocolDecl>(ClassDecl);
bool checkIdenticalMethods = isa<ObjCImplementationDecl>(ClassDecl); bool checkIdenticalMethods = isa<ObjCImplementationDecl>(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<ObjCImplementationDecl>(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. // FIXME: Remove these and use the ObjCContainerDecl/DeclContext.
llvm::DenseMap<Selector, const ObjCMethodDecl*> InsMap; llvm::DenseMap<Selector, const ObjCMethodDecl*> InsMap;
llvm::DenseMap<Selector, const ObjCMethodDecl*> ClsMap; llvm::DenseMap<Selector, const ObjCMethodDecl*> ClsMap;
@ -4001,8 +4026,8 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
continue; continue;
for (const auto *Ext : IDecl->visible_extensions()) { for (const auto *Ext : IDecl->visible_extensions()) {
if (ObjCMethodDecl *GetterMethod if (ObjCMethodDecl *GetterMethod =
= Ext->getInstanceMethod(Property->getGetterName())) Ext->getInstanceMethod(Property->getGetterName()))
GetterMethod->setPropertyAccessor(true); GetterMethod->setPropertyAccessor(true);
if (!Property->isReadOnly()) if (!Property->isReadOnly())
if (ObjCMethodDecl *SetterMethod if (ObjCMethodDecl *SetterMethod
@ -4551,6 +4576,7 @@ Decl *Sema::ActOnMethodDeclaration(
Diag(MethodLoc, diag::err_missing_method_context); Diag(MethodLoc, diag::err_missing_method_context);
return nullptr; return nullptr;
} }
Decl *ClassDecl = cast<ObjCContainerDecl>(CurContext); Decl *ClassDecl = cast<ObjCContainerDecl>(CurContext);
QualType resultDeclType; QualType resultDeclType;
@ -4574,7 +4600,7 @@ Decl *Sema::ActOnMethodDeclaration(
ObjCMethodDecl *ObjCMethod = ObjCMethodDecl::Create( ObjCMethodDecl *ObjCMethod = ObjCMethodDecl::Create(
Context, MethodLoc, EndLoc, Sel, resultDeclType, ReturnTInfo, CurContext, Context, MethodLoc, EndLoc, Sel, resultDeclType, ReturnTInfo, CurContext,
MethodType == tok::minus, isVariadic, MethodType == tok::minus, isVariadic,
/*isPropertyAccessor=*/false, /*isPropertyAccessor=*/false, /*isSynthesizedAccessorStub=*/false,
/*isImplicitlyDeclared=*/false, /*isDefined=*/false, /*isImplicitlyDeclared=*/false, /*isDefined=*/false,
MethodDeclKind == tok::objc_optional ? ObjCMethodDecl::Optional MethodDeclKind == tok::objc_optional ? ObjCMethodDecl::Optional
: ObjCMethodDecl::Required, : ObjCMethodDecl::Required,
@ -4666,6 +4692,27 @@ Decl *Sema::ActOnMethodDeclaration(
ImpDecl->addClassMethod(ObjCMethod); 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 // Merge information from the @interface declaration into the
// @implementation. // @implementation.
if (ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface()) { if (ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface()) {
@ -5063,6 +5110,9 @@ void Sema::DiagnoseUnusedBackingIvarInAccessor(Scope *S,
if (!IV) if (!IV)
continue; continue;
if (CurMethod->isSynthesizedAccessorStub())
continue;
UnusedBackingIvarChecker Checker(*this, CurMethod, IV); UnusedBackingIvarChecker Checker(*this, CurMethod, IV);
Checker.TraverseStmt(CurMethod->getBody()); Checker.TraverseStmt(CurMethod->getBody());
if (Checker.AccessedIvar) if (Checker.AccessedIvar)

View File

@ -288,6 +288,7 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
S.NSNumberPointer, ReturnTInfo, S.NSNumberDecl, S.NSNumberPointer, ReturnTInfo, S.NSNumberDecl,
/*isInstance=*/false, /*isVariadic=*/false, /*isInstance=*/false, /*isVariadic=*/false,
/*isPropertyAccessor=*/false, /*isPropertyAccessor=*/false,
/*isSynthesizedAccessorStub=*/false,
/*isImplicitlyDeclared=*/true, /*isImplicitlyDeclared=*/true,
/*isDefined=*/false, ObjCMethodDecl::Required, /*isDefined=*/false, ObjCMethodDecl::Required,
/*HasRelatedResultType=*/false); /*HasRelatedResultType=*/false);
@ -563,6 +564,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
NSStringPointer, ReturnTInfo, NSStringDecl, NSStringPointer, ReturnTInfo, NSStringDecl,
/*isInstance=*/false, /*isVariadic=*/false, /*isInstance=*/false, /*isVariadic=*/false,
/*isPropertyAccessor=*/false, /*isPropertyAccessor=*/false,
/*isSynthesizedAccessorStub=*/false,
/*isImplicitlyDeclared=*/true, /*isImplicitlyDeclared=*/true,
/*isDefined=*/false, ObjCMethodDecl::Required, /*isDefined=*/false, ObjCMethodDecl::Required,
/*HasRelatedResultType=*/false); /*HasRelatedResultType=*/false);
@ -671,20 +673,15 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
// Debugger needs to work even if NSValue hasn't been defined. // Debugger needs to work even if NSValue hasn't been defined.
TypeSourceInfo *ReturnTInfo = nullptr; TypeSourceInfo *ReturnTInfo = nullptr;
ObjCMethodDecl *M = ObjCMethodDecl::Create( ObjCMethodDecl *M = ObjCMethodDecl::Create(
Context, Context, SourceLocation(), SourceLocation(), ValueWithBytesObjCType,
SourceLocation(), NSValuePointer, ReturnTInfo, NSValueDecl,
SourceLocation(), /*isInstance=*/false,
ValueWithBytesObjCType, /*isVariadic=*/false,
NSValuePointer, /*isPropertyAccessor=*/false,
ReturnTInfo, /*isSynthesizedAccessorStub=*/false,
NSValueDecl, /*isImplicitlyDeclared=*/true,
/*isInstance=*/false, /*isDefined=*/false, ObjCMethodDecl::Required,
/*isVariadic=*/false, /*HasRelatedResultType=*/false);
/*isPropertyAccessor=*/false,
/*isImplicitlyDeclared=*/true,
/*isDefined=*/false,
ObjCMethodDecl::Required,
/*HasRelatedResultType=*/false);
SmallVector<ParmVarDecl *, 2> Params; SmallVector<ParmVarDecl *, 2> Params;
@ -815,7 +812,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
Context, SourceLocation(), SourceLocation(), Sel, IdT, ReturnTInfo, Context, SourceLocation(), SourceLocation(), Sel, IdT, ReturnTInfo,
Context.getTranslationUnitDecl(), false /*Instance*/, Context.getTranslationUnitDecl(), false /*Instance*/,
false /*isVariadic*/, false /*isVariadic*/,
/*isPropertyAccessor=*/false, /*isPropertyAccessor=*/false, /*isSynthesizedAccessorStub=*/false,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false, /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
ObjCMethodDecl::Required, false); ObjCMethodDecl::Required, false);
SmallVector<ParmVarDecl *, 2> Params; SmallVector<ParmVarDecl *, 2> Params;
@ -916,16 +913,14 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
NSAPI::NSDict_dictionaryWithObjectsForKeysCount); NSAPI::NSDict_dictionaryWithObjectsForKeysCount);
ObjCMethodDecl *Method = NSDictionaryDecl->lookupClassMethod(Sel); ObjCMethodDecl *Method = NSDictionaryDecl->lookupClassMethod(Sel);
if (!Method && getLangOpts().DebuggerObjCLiteral) { if (!Method && getLangOpts().DebuggerObjCLiteral) {
Method = ObjCMethodDecl::Create(Context, Method = ObjCMethodDecl::Create(
SourceLocation(), SourceLocation(), Sel, Context, SourceLocation(), SourceLocation(), Sel, IdT,
IdT, nullptr /*TypeSourceInfo */, Context.getTranslationUnitDecl(),
nullptr /*TypeSourceInfo */, false /*Instance*/, false /*isVariadic*/,
Context.getTranslationUnitDecl(), /*isPropertyAccessor=*/false,
false /*Instance*/, false/*isVariadic*/, /*isSynthesizedAccessorStub=*/false,
/*isPropertyAccessor=*/false, /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false, ObjCMethodDecl::Required, false);
ObjCMethodDecl::Required,
false);
SmallVector<ParmVarDecl *, 3> Params; SmallVector<ParmVarDecl *, 3> Params;
ParmVarDecl *objects = ParmVarDecl::Create(Context, Method, ParmVarDecl *objects = ParmVarDecl::Create(Context, Method,
SourceLocation(), SourceLocation(),

View File

@ -1037,6 +1037,31 @@ static bool hasWrittenStorageAttribute(ObjCPropertyDecl *Prop,
return false; 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<SourceLocation, 1> 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 /// ActOnPropertyImplDecl - This routine performs semantic checks and
/// builds the AST node for a property implementation declaration; declared /// builds the AST node for a property implementation declaration; declared
/// as \@synthesize or \@dynamic. /// as \@synthesize or \@dynamic.
@ -1404,6 +1429,18 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) { if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) {
getterMethod->createImplicitParams(Context, IDecl); 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 && if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr &&
Ivar->getType()->isRecordType()) { Ivar->getType()->isRecordType()) {
// For Objective-C++, need to synthesize the AST for the IVAR object to be // For Objective-C++, need to synthesize the AST for the IVAR object to be
@ -1456,8 +1493,20 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
break; break;
} }
} }
if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) { if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) {
setterMethod->createImplicitParams(Context, IDecl); 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 && if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr &&
Ivar->getType()->isRecordType()) { Ivar->getType()->isRecordType()) {
// FIXME. Eventually we want to do this for Objective-C as well. // 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( if (IMPDecl->FindPropertyImplDecl(
Prop->getIdentifier(), Prop->getQueryKind())) Prop->getIdentifier(), Prop->getQueryKind()))
continue; continue;
if (IMPDecl->getInstanceMethod(Prop->getGetterName())) { ObjCMethodDecl *ImpMethod = IMPDecl->getInstanceMethod(Prop->getGetterName());
if (ImpMethod && !ImpMethod->getBody()) {
if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly) if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly)
continue; continue;
if (IMPDecl->getInstanceMethod(Prop->getSetterName())) ImpMethod = IMPDecl->getInstanceMethod(Prop->getSetterName());
if (ImpMethod && !ImpMethod->getBody())
continue; continue;
} }
if (ObjCPropertyImplDecl *PID = if (ObjCPropertyImplDecl *PID =
@ -2083,7 +2134,6 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
void Sema::diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl) { void Sema::diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl) {
for (const auto *propertyImpl : impDecl->property_impls()) { for (const auto *propertyImpl : impDecl->property_impls()) {
const auto *property = propertyImpl->getPropertyDecl(); const auto *property = propertyImpl->getPropertyDecl();
// Warn about null_resettable properties with synthesized setters, // Warn about null_resettable properties with synthesized setters,
// because the setter won't properly handle nil. // because the setter won't properly handle nil.
if (propertyImpl->getPropertyImplementation() if (propertyImpl->getPropertyImplementation()
@ -2092,16 +2142,16 @@ void Sema::diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl)
ObjCPropertyDecl::OBJC_PR_null_resettable) && ObjCPropertyDecl::OBJC_PR_null_resettable) &&
property->getGetterMethodDecl() && property->getGetterMethodDecl() &&
property->getSetterMethodDecl()) { property->getSetterMethodDecl()) {
auto *getterMethod = property->getGetterMethodDecl(); auto *getterImpl = propertyImpl->getGetterMethodDecl();
auto *setterMethod = property->getSetterMethodDecl(); auto *setterImpl = propertyImpl->getSetterMethodDecl();
if (!impDecl->getInstanceMethod(setterMethod->getSelector()) && if ((!getterImpl || getterImpl->isSynthesizedAccessorStub()) &&
!impDecl->getInstanceMethod(getterMethod->getSelector())) { (!setterImpl || setterImpl->isSynthesizedAccessorStub())) {
SourceLocation loc = propertyImpl->getLocation(); SourceLocation loc = propertyImpl->getLocation();
if (loc.isInvalid()) if (loc.isInvalid())
loc = impDecl->getBeginLoc(); loc = impDecl->getBeginLoc();
Diag(loc, diag::warn_null_resettable_setter) 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() ? SetterMethod = Property->isClassProperty() ?
IMPDecl->getClassMethod(Property->getSetterName()) : IMPDecl->getClassMethod(Property->getSetterName()) :
IMPDecl->getInstanceMethod(Property->getSetterName()); IMPDecl->getInstanceMethod(Property->getSetterName());
if (GetterMethod && GetterMethod->isSynthesizedAccessorStub())
GetterMethod = nullptr;
if (SetterMethod && SetterMethod->isSynthesizedAccessorStub())
SetterMethod = nullptr;
LookedUpGetterSetter = true; LookedUpGetterSetter = true;
if (GetterMethod) { if (GetterMethod) {
Diag(GetterMethod->getLocation(), Diag(GetterMethod->getLocation(),
@ -2161,15 +2215,13 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
Property->getIdentifier(), Property->getQueryKind())) { Property->getIdentifier(), Property->getQueryKind())) {
if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
continue; continue;
if (!LookedUpGetterSetter) { GetterMethod = PIDecl->getGetterMethodDecl();
GetterMethod = Property->isClassProperty() ? SetterMethod = PIDecl->getSetterMethodDecl();
IMPDecl->getClassMethod(Property->getGetterName()) : if (GetterMethod && GetterMethod->isSynthesizedAccessorStub())
IMPDecl->getInstanceMethod(Property->getGetterName()); GetterMethod = nullptr;
SetterMethod = Property->isClassProperty() ? if (SetterMethod && SetterMethod->isSynthesizedAccessorStub())
IMPDecl->getClassMethod(Property->getSetterName()) : SetterMethod = nullptr;
IMPDecl->getInstanceMethod(Property->getSetterName()); if ((bool)GetterMethod ^ (bool)SetterMethod) {
}
if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) {
SourceLocation MethodLoc = SourceLocation MethodLoc =
(GetterMethod ? GetterMethod->getLocation() (GetterMethod ? GetterMethod->getLocation()
: SetterMethod->getLocation()); : SetterMethod->getLocation());
@ -2210,8 +2262,10 @@ void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D
for (const auto *PID : D->property_impls()) { for (const auto *PID : D->property_impls()) {
const ObjCPropertyDecl *PD = PID->getPropertyDecl(); const ObjCPropertyDecl *PD = PID->getPropertyDecl();
if (PD && !PD->hasAttr<NSReturnsNotRetainedAttr>() && if (PD && !PD->hasAttr<NSReturnsNotRetainedAttr>() &&
!PD->isClassProperty() && !PD->isClassProperty()) {
!D->getInstanceMethod(PD->getGetterName())) { ObjCMethodDecl *IM = PID->getGetterMethodDecl();
if (IM && !IM->isSynthesizedAccessorStub())
continue;
ObjCMethodDecl *method = PD->getGetterMethodDecl(); ObjCMethodDecl *method = PD->getGetterMethodDecl();
if (!method) if (!method)
continue; continue;
@ -2396,16 +2450,14 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
} }
} }
GetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc, GetterMethod = ObjCMethodDecl::Create(
property->getGetterName(), Context, Loc, Loc, property->getGetterName(), resultTy, nullptr, CD,
resultTy, nullptr, CD, !IsClassProperty, /*isVariadic=*/false,
!IsClassProperty, /*isVariadic=*/false, /*isPropertyAccessor=*/true, /*isSynthesizedAccessorStub=*/false,
/*isPropertyAccessor=*/true, /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false, (property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
(property->getPropertyImplementation() == ? ObjCMethodDecl::Optional
ObjCPropertyDecl::Optional) ? : ObjCMethodDecl::Required);
ObjCMethodDecl::Optional :
ObjCMethodDecl::Required);
CD->addDecl(GetterMethod); CD->addDecl(GetterMethod);
AddPropertyAttrs(*this, GetterMethod, property); AddPropertyAttrs(*this, GetterMethod, property);
@ -2447,6 +2499,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
nullptr, CD, !IsClassProperty, nullptr, CD, !IsClassProperty,
/*isVariadic=*/false, /*isVariadic=*/false,
/*isPropertyAccessor=*/true, /*isPropertyAccessor=*/true,
/*isSynthesizedAccessorStub=*/false,
/*isImplicitlyDeclared=*/true, /*isImplicitlyDeclared=*/true,
/*isDefined=*/false, /*isDefined=*/false,
(property->getPropertyImplementation() == (property->getPropertyImplementation() ==

View File

@ -1190,16 +1190,15 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
true /*instance*/); true /*instance*/);
if (!AtIndexGetter && S.getLangOpts().DebuggerObjCLiteral) { if (!AtIndexGetter && S.getLangOpts().DebuggerObjCLiteral) {
AtIndexGetter = ObjCMethodDecl::Create(S.Context, SourceLocation(), AtIndexGetter = ObjCMethodDecl::Create(
SourceLocation(), AtIndexGetterSelector, S.Context, SourceLocation(), SourceLocation(), AtIndexGetterSelector,
S.Context.getObjCIdType() /*ReturnType*/, S.Context.getObjCIdType() /*ReturnType*/, nullptr /*TypeSourceInfo */,
nullptr /*TypeSourceInfo */, S.Context.getTranslationUnitDecl(), true /*Instance*/,
S.Context.getTranslationUnitDecl(), false /*isVariadic*/,
true /*Instance*/, false/*isVariadic*/, /*isPropertyAccessor=*/false,
/*isPropertyAccessor=*/false, /*isSynthesizedAccessorStub=*/false,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false, /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
ObjCMethodDecl::Required, ObjCMethodDecl::Required, false);
false);
ParmVarDecl *Argument = ParmVarDecl::Create(S.Context, AtIndexGetter, ParmVarDecl *Argument = ParmVarDecl::Create(S.Context, AtIndexGetter,
SourceLocation(), SourceLocation(), SourceLocation(), SourceLocation(),
arrayRef ? &S.Context.Idents.get("index") arrayRef ? &S.Context.Idents.get("index")
@ -1303,6 +1302,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
ReturnType, ReturnTInfo, S.Context.getTranslationUnitDecl(), ReturnType, ReturnTInfo, S.Context.getTranslationUnitDecl(),
true /*Instance*/, false /*isVariadic*/, true /*Instance*/, false /*isVariadic*/,
/*isPropertyAccessor=*/false, /*isPropertyAccessor=*/false,
/*isSynthesizedAccessorStub=*/false,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false, /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
ObjCMethodDecl::Required, false); ObjCMethodDecl::Required, false);
SmallVector<ParmVarDecl *, 2> Params; SmallVector<ParmVarDecl *, 2> Params;

View File

@ -1019,6 +1019,7 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
MD->setInstanceMethod(Record.readInt()); MD->setInstanceMethod(Record.readInt());
MD->setVariadic(Record.readInt()); MD->setVariadic(Record.readInt());
MD->setPropertyAccessor(Record.readInt()); MD->setPropertyAccessor(Record.readInt());
MD->setSynthesizedAccessorStub(Record.readInt());
MD->setDefined(Record.readInt()); MD->setDefined(Record.readInt());
MD->setOverriding(Record.readInt()); MD->setOverriding(Record.readInt());
MD->setHasSkippedBody(Record.readInt()); MD->setHasSkippedBody(Record.readInt());
@ -1313,6 +1314,8 @@ void ASTDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
D->setPropertyDecl(ReadDeclAs<ObjCPropertyDecl>()); D->setPropertyDecl(ReadDeclAs<ObjCPropertyDecl>());
D->PropertyIvarDecl = ReadDeclAs<ObjCIvarDecl>(); D->PropertyIvarDecl = ReadDeclAs<ObjCIvarDecl>();
D->IvarLoc = ReadSourceLocation(); D->IvarLoc = ReadSourceLocation();
D->setGetterMethodDecl(ReadDeclAs<ObjCMethodDecl>());
D->setSetterMethodDecl(ReadDeclAs<ObjCMethodDecl>());
D->setGetterCXXConstructor(Record.readExpr()); D->setGetterCXXConstructor(Record.readExpr());
D->setSetterCXXAssignment(Record.readExpr()); D->setSetterCXXAssignment(Record.readExpr());
} }

View File

@ -673,6 +673,7 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
Record.push_back(D->isInstanceMethod()); Record.push_back(D->isInstanceMethod());
Record.push_back(D->isVariadic()); Record.push_back(D->isVariadic());
Record.push_back(D->isPropertyAccessor()); Record.push_back(D->isPropertyAccessor());
Record.push_back(D->isSynthesizedAccessorStub());
Record.push_back(D->isDefined()); Record.push_back(D->isDefined());
Record.push_back(D->isOverriding()); Record.push_back(D->isOverriding());
Record.push_back(D->hasSkippedBody()); Record.push_back(D->hasSkippedBody());
@ -884,6 +885,8 @@ void ASTDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
Record.AddDeclRef(D->getPropertyDecl()); Record.AddDeclRef(D->getPropertyDecl());
Record.AddDeclRef(D->getPropertyIvarDecl()); Record.AddDeclRef(D->getPropertyIvarDecl());
Record.AddSourceLocation(D->getPropertyIvarDeclLoc()); Record.AddSourceLocation(D->getPropertyIvarDeclLoc());
Record.AddDeclRef(D->getGetterMethodDecl());
Record.AddDeclRef(D->getSetterMethodDecl());
Record.AddStmt(D->getGetterCXXConstructor()); Record.AddStmt(D->getGetterCXXConstructor());
Record.AddStmt(D->getSetterCXXAssignment()); Record.AddStmt(D->getSetterCXXAssignment());
Code = serialization::DECL_OBJC_PROPERTY_IMPL; Code = serialization::DECL_OBJC_PROPERTY_IMPL;

View File

@ -144,6 +144,8 @@ void DirectIvarAssignment::checkASTDecl(const ObjCImplementationDecl *D,
continue; continue;
const Stmt *Body = M->getBody(); const Stmt *Body = M->getBody();
if (M->isSynthesizedAccessorStub())
continue;
assert(Body); assert(Body);
MethodCrawler MC(IvarToPropMap, M->getCanonicalDecl(), InterD, BR, this, MethodCrawler MC(IvarToPropMap, M->getCanonicalDecl(), InterD, BR, this,

View File

@ -1080,7 +1080,7 @@ ObjCMessageKind ObjCMethodCall::getMessageKind() const {
const ObjCPropertyDecl *ObjCMethodCall::getAccessedProperty() const { const ObjCPropertyDecl *ObjCMethodCall::getAccessedProperty() const {
// Look for properties accessed with property syntax (foo.bar = ...) // Look for properties accessed with property syntax (foo.bar = ...)
if ( getMessageKind() == OCM_PropertyAccess) { if (getMessageKind() == OCM_PropertyAccess) {
const PseudoObjectExpr *POE = getContainingPseudoObjectExpr(); const PseudoObjectExpr *POE = getContainingPseudoObjectExpr();
assert(POE && "Property access without PseudoObjectExpr?"); assert(POE && "Property access without PseudoObjectExpr?");

View File

@ -1475,7 +1475,173 @@ void f() {
// CHECK-NEXT: "qualType": "int" // CHECK-NEXT: "qualType": "int"
// CHECK-NEXT: } // CHECK-NEXT: }
// 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: ]
// CHECK-NEXT: } // CHECK-NEXT: }

View File

@ -188,7 +188,6 @@
<dict> <dict>
<key>0</key> <key>0</key>
<array> <array>
<integer>10</integer>
<integer>14</integer> <integer>14</integer>
<integer>16</integer> <integer>16</integer>
<integer>17</integer> <integer>17</integer>

View File

@ -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: !DISubprogram(name: "-[Foo setDict:]"
// CHECK-SAME: file: ![[FILE]], // CHECK-SAME: file: ![[FILE]],
// CHECK-SAME: line: 8, // CHECK-SAME: line: 7,
// CHECK-SAME: DISPFlagLocalToUnit | DISPFlagDefinition // CHECK-SAME: DISPFlagLocalToUnit | DISPFlagDefinition

View File

@ -7,6 +7,10 @@
@interface I { @interface I {
int _p1; int _p1;
} }
@property int p1;
@end
@implementation I
// Test that the linetable entries for the synthesized getter and // Test that the linetable entries for the synthesized getter and
// setter are correct. // setter are correct.
// //
@ -22,10 +26,6 @@
// CHECK: ![[DBG1]] = !DILocation(line: [[@LINE+3]], // CHECK: ![[DBG1]] = !DILocation(line: [[@LINE+3]],
// CHECK: !DISubprogram(name: "-[I setP1:]",{{.*}} line: [[@LINE+2]],{{.*}} DISPFlagLocalToUnit | DISPFlagDefinition // CHECK: !DISubprogram(name: "-[I setP1:]",{{.*}} line: [[@LINE+2]],{{.*}} DISPFlagLocalToUnit | DISPFlagDefinition
// CHECK: ![[DBG2]] = !DILocation(line: [[@LINE+1]], // CHECK: ![[DBG2]] = !DILocation(line: [[@LINE+1]],
@property int p1;
@end
@implementation I
@synthesize p1 = _p1; @synthesize p1 = _p1;
@end @end

View File

@ -11,19 +11,6 @@
@protocol HasASelection <NSObject> @protocol HasASelection <NSObject>
@property (nonatomic, retain) Selection* selection; @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 @end
@interface MyClass : NSObject <HasASelection> { @interface MyClass : NSObject <HasASelection> {
@ -33,6 +20,12 @@
@implementation MyClass @implementation MyClass
@synthesize selection = _selection; @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 @end
@interface OtherClass : NSObject <HasASelection> { @interface OtherClass : NSObject <HasASelection> {
@ -41,4 +34,10 @@
@end @end
@implementation OtherClass @implementation OtherClass
@synthesize selection = _selection; @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 @end

View File

@ -1,6 +1,5 @@
// REQUIRES: x86-registered-target // REQUIRES: x86-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -S -o %t %s // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -S %s -o - | FileCheck %s
// RUN: FileCheck < %t %s
// rdar://9072317 // rdar://9072317

View File

@ -11,7 +11,7 @@ IB_DESIGNABLE @interface I
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}} 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 @end

View File

@ -629,6 +629,11 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
Decl *D = *I; Decl *D = *I;
if (D->getLexicalDeclContext() != DC) if (D->getLexicalDeclContext() != DC)
continue; continue;
// Filter out synthesized property accessor redeclarations.
if (isa<ObjCImplDecl>(DC))
if (auto *OMD = dyn_cast<ObjCMethodDecl>(D))
if (OMD->isSynthesizedAccessorStub())
continue;
const Optional<bool> V = handleDeclForVisitation(D); const Optional<bool> V = handleDeclForVisitation(D);
if (!V.hasValue()) if (!V.hasValue())
continue; continue;