Skip to content

Commit e3721d3

Browse files
committed
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 (cherry picked from commit 2073dd2)
1 parent a28a21b commit e3721d3

29 files changed

+501
-197
lines changed

clang/include/clang/AST/DeclBase.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,6 +1583,9 @@ class DeclContext {
15831583
/// True if this method is the getter or setter for an explicit property.
15841584
uint64_t IsPropertyAccessor : 1;
15851585

1586+
/// True if this method is a synthesized property accessor stub.
1587+
uint64_t IsSynthesizedAccessorStub : 1;
1588+
15861589
/// Method has a definition.
15871590
uint64_t IsDefined : 1;
15881591

clang/include/clang/AST/DeclObjC.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
172172
Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo,
173173
DeclContext *contextDecl, bool isInstance = true,
174174
bool isVariadic = false, bool isPropertyAccessor = false,
175+
bool isSynthesizedAccessorStub = false,
175176
bool isImplicitlyDeclared = false, bool isDefined = false,
176177
ImplementationControl impControl = None,
177178
bool HasRelatedResultType = false);
@@ -232,6 +233,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
232233
Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo,
233234
DeclContext *contextDecl, bool isInstance = true,
234235
bool isVariadic = false, bool isPropertyAccessor = false,
236+
bool isSynthesizedAccessorStub = false,
235237
bool isImplicitlyDeclared = false, bool isDefined = false,
236238
ImplementationControl impControl = None,
237239
bool HasRelatedResultType = false);
@@ -436,6 +438,14 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
436438
ObjCMethodDeclBits.IsPropertyAccessor = isAccessor;
437439
}
438440

441+
bool isSynthesizedAccessorStub() const {
442+
return ObjCMethodDeclBits.IsSynthesizedAccessorStub;
443+
}
444+
445+
void setSynthesizedAccessorStub(bool isSynthesizedAccessorStub) {
446+
ObjCMethodDeclBits.IsSynthesizedAccessorStub = isSynthesizedAccessorStub;
447+
}
448+
439449
bool isDefined() const { return ObjCMethodDeclBits.IsDefined; }
440450
void setDefined(bool isDefined) { ObjCMethodDeclBits.IsDefined = isDefined; }
441451

@@ -2808,6 +2818,11 @@ class ObjCPropertyImplDecl : public Decl {
28082818
/// Null for \@dynamic. Required for \@synthesize.
28092819
ObjCIvarDecl *PropertyIvarDecl;
28102820

2821+
/// The getter's definition, which has an empty body if synthesized.
2822+
ObjCMethodDecl *GetterMethodDecl = nullptr;
2823+
/// The getter's definition, which has an empty body if synthesized.
2824+
ObjCMethodDecl *SetterMethodDecl = nullptr;
2825+
28112826
/// Null for \@dynamic. Non-null if property must be copy-constructed in
28122827
/// getter.
28132828
Expr *GetterCXXConstructor = nullptr;
@@ -2874,6 +2889,12 @@ class ObjCPropertyImplDecl : public Decl {
28742889
return IvarLoc.isValid() && IvarLoc != getLocation();
28752890
}
28762891

2892+
ObjCMethodDecl *getGetterMethodDecl() const { return GetterMethodDecl; }
2893+
void setGetterMethodDecl(ObjCMethodDecl *MD) { GetterMethodDecl = MD; }
2894+
2895+
ObjCMethodDecl *getSetterMethodDecl() const { return SetterMethodDecl; }
2896+
void setSetterMethodDecl(ObjCMethodDecl *MD) { SetterMethodDecl = MD; }
2897+
28772898
Expr *getGetterCXXConstructor() const {
28782899
return GetterCXXConstructor;
28792900
}

clang/lib/AST/ASTImporter.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3989,10 +3989,10 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
39893989

39903990
ObjCMethodDecl *ToMethod;
39913991
if (GetImportedOrCreateDecl(
3992-
ToMethod, D, Importer.getToContext(), Loc,
3993-
ToEndLoc, Name.getObjCSelector(), ToReturnType,
3994-
ToReturnTypeSourceInfo, DC, D->isInstanceMethod(), D->isVariadic(),
3995-
D->isPropertyAccessor(), D->isImplicit(), D->isDefined(),
3992+
ToMethod, D, Importer.getToContext(), Loc, ToEndLoc,
3993+
Name.getObjCSelector(), ToReturnType, ToReturnTypeSourceInfo, DC,
3994+
D->isInstanceMethod(), D->isVariadic(), D->isPropertyAccessor(),
3995+
D->isSynthesizedAccessorStub(), D->isImplicit(), D->isDefined(),
39963996
D->getImplementationControl(), D->hasRelatedResultType()))
39973997
return ToMethod;
39983998

clang/lib/AST/DeclObjC.cpp

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -775,14 +775,12 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateMethod(
775775
// ObjCMethodDecl
776776
//===----------------------------------------------------------------------===//
777777

778-
ObjCMethodDecl::ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc,
779-
Selector SelInfo, QualType T,
780-
TypeSourceInfo *ReturnTInfo,
781-
DeclContext *contextDecl, bool isInstance,
782-
bool isVariadic, bool isPropertyAccessor,
783-
bool isImplicitlyDeclared, bool isDefined,
784-
ImplementationControl impControl,
785-
bool HasRelatedResultType)
778+
ObjCMethodDecl::ObjCMethodDecl(
779+
SourceLocation beginLoc, SourceLocation endLoc, Selector SelInfo,
780+
QualType T, TypeSourceInfo *ReturnTInfo, DeclContext *contextDecl,
781+
bool isInstance, bool isVariadic, bool isPropertyAccessor,
782+
bool isSynthesizedAccessorStub, bool isImplicitlyDeclared, bool isDefined,
783+
ImplementationControl impControl, bool HasRelatedResultType)
786784
: NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo),
787785
DeclContext(ObjCMethod), MethodDeclType(T), ReturnTInfo(ReturnTInfo),
788786
DeclEndLoc(endLoc) {
@@ -793,6 +791,7 @@ ObjCMethodDecl::ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc,
793791
setInstanceMethod(isInstance);
794792
setVariadic(isVariadic);
795793
setPropertyAccessor(isPropertyAccessor);
794+
setSynthesizedAccessorStub(isSynthesizedAccessorStub);
796795
setDefined(isDefined);
797796
setIsRedeclaration(false);
798797
setHasRedeclaration(false);
@@ -810,12 +809,13 @@ ObjCMethodDecl *ObjCMethodDecl::Create(
810809
ASTContext &C, SourceLocation beginLoc, SourceLocation endLoc,
811810
Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo,
812811
DeclContext *contextDecl, bool isInstance, bool isVariadic,
813-
bool isPropertyAccessor, bool isImplicitlyDeclared, bool isDefined,
814-
ImplementationControl impControl, bool HasRelatedResultType) {
812+
bool isPropertyAccessor, bool isSynthesizedAccessorStub,
813+
bool isImplicitlyDeclared, bool isDefined, ImplementationControl impControl,
814+
bool HasRelatedResultType) {
815815
return new (C, contextDecl) ObjCMethodDecl(
816816
beginLoc, endLoc, SelInfo, T, ReturnTInfo, contextDecl, isInstance,
817-
isVariadic, isPropertyAccessor, isImplicitlyDeclared, isDefined,
818-
impControl, HasRelatedResultType);
817+
isVariadic, isPropertyAccessor, isSynthesizedAccessorStub,
818+
isImplicitlyDeclared, isDefined, impControl, HasRelatedResultType);
819819
}
820820

821821
ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
@@ -1306,6 +1306,11 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
13061306

13071307
if (isPropertyAccessor()) {
13081308
const auto *Container = cast<ObjCContainerDecl>(getParent());
1309+
// For accessor stubs, go back to the interface.
1310+
if (auto *ImplDecl = dyn_cast<ObjCImplDecl>(Container))
1311+
if (isSynthesizedAccessorStub())
1312+
Container = ImplDecl->getClassInterface();
1313+
13091314
bool IsGetter = (NumArgs == 0);
13101315
bool IsInstance = isInstanceMethod();
13111316

@@ -1358,6 +1363,15 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
13581363
}
13591364
}
13601365

1366+
assert(isSynthesizedAccessorStub() && "expected an accessor stub");
1367+
for (const auto *Cat : ClassDecl->known_categories()) {
1368+
if (Cat == Container)
1369+
continue;
1370+
1371+
if (const auto *Found = findMatchingProperty(Cat))
1372+
return Found;
1373+
}
1374+
13611375
llvm_unreachable("Marked as a property accessor but no property found!");
13621376
}
13631377

clang/lib/Analysis/BodyFarm.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,16 @@ Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) {
830830
if (D->param_size() != 0)
831831
return nullptr;
832832

833+
// If the property was defined in an extension, search the extensions for
834+
// overrides.
835+
const ObjCInterfaceDecl *OID = D->getClassInterface();
836+
if (dyn_cast<ObjCInterfaceDecl>(D->getParent()) != OID)
837+
for (auto *Ext : OID->known_extensions()) {
838+
auto *OMD = Ext->getInstanceMethod(D->getSelector());
839+
if (OMD && !OMD->isImplicit())
840+
return nullptr;
841+
}
842+
833843
Val = createObjCPropertyGetter(C, Prop);
834844

835845
return Val.getValue();

clang/lib/CodeGen/CGObjC.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -954,8 +954,7 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
954954
const ObjCPropertyImplDecl *PID) {
955955
llvm::Constant *AtomicHelperFn =
956956
CodeGenFunction(CGM).GenerateObjCAtomicGetterCopyHelperFunction(PID);
957-
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
958-
ObjCMethodDecl *OMD = PD->getGetterMethodDecl();
957+
ObjCMethodDecl *OMD = PID->getGetterMethodDecl();
959958
assert(OMD && "Invalid call to generate getter (empty method)");
960959
StartObjCMethod(OMD, IMP->getClassInterface());
961960

@@ -1041,7 +1040,7 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
10411040

10421041
const ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
10431042
QualType propType = prop->getType();
1044-
ObjCMethodDecl *getterMethod = prop->getGetterMethodDecl();
1043+
ObjCMethodDecl *getterMethod = propImpl->getGetterMethodDecl();
10451044

10461045
ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
10471046

@@ -1311,9 +1310,8 @@ void
13111310
CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
13121311
const ObjCPropertyImplDecl *propImpl,
13131312
llvm::Constant *AtomicHelperFn) {
1314-
const ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
13151313
ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
1316-
ObjCMethodDecl *setterMethod = prop->getSetterMethodDecl();
1314+
ObjCMethodDecl *setterMethod = propImpl->getSetterMethodDecl();
13171315

13181316
// Just use the setter expression if Sema gave us one and it's
13191317
// non-trivial.
@@ -1490,8 +1488,7 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
14901488
const ObjCPropertyImplDecl *PID) {
14911489
llvm::Constant *AtomicHelperFn =
14921490
CodeGenFunction(CGM).GenerateObjCAtomicSetterCopyHelperFunction(PID);
1493-
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
1494-
ObjCMethodDecl *OMD = PD->getSetterMethodDecl();
1491+
ObjCMethodDecl *OMD = PID->getSetterMethodDecl();
14951492
assert(OMD && "Invalid call to generate setter (empty method)");
14961493
StartObjCMethod(OMD, IMP->getClassInterface());
14971494

clang/lib/CodeGen/CGObjCGNU.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1879,13 +1879,12 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
18791879
for (auto *propImpl : OID->property_impls())
18801880
if (propImpl->getPropertyImplementation() ==
18811881
ObjCPropertyImplDecl::Synthesize) {
1882-
ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
1883-
auto addIfExists = [&](const ObjCMethodDecl* OMD) {
1884-
if (OMD)
1882+
auto addIfExists = [&](const ObjCMethodDecl *OMD) {
1883+
if (OMD && OMD->hasBody())
18851884
InstanceMethods.push_back(OMD);
18861885
};
1887-
addIfExists(prop->getGetterMethodDecl());
1888-
addIfExists(prop->getSetterMethodDecl());
1886+
addIfExists(propImpl->getGetterMethodDecl());
1887+
addIfExists(propImpl->getSetterMethodDecl());
18891888
}
18901889

18911890
if (InstanceMethods.size() == 0)
@@ -3493,13 +3492,12 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
34933492
for (auto *propertyImpl : OID->property_impls())
34943493
if (propertyImpl->getPropertyImplementation() ==
34953494
ObjCPropertyImplDecl::Synthesize) {
3496-
ObjCPropertyDecl *property = propertyImpl->getPropertyDecl();
34973495
auto addPropertyMethod = [&](const ObjCMethodDecl *accessor) {
34983496
if (accessor)
34993497
InstanceMethods.push_back(accessor);
35003498
};
3501-
addPropertyMethod(property->getGetterMethodDecl());
3502-
addPropertyMethod(property->getSetterMethodDecl());
3499+
addPropertyMethod(propertyImpl->getGetterMethodDecl());
3500+
addPropertyMethod(propertyImpl->getSetterMethodDecl());
35033501
}
35043502

35053503
llvm::Constant *Properties = GeneratePropertyList(OID, ClassDecl);

clang/lib/CodeGen/CGObjCMac.cpp

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3561,12 +3561,10 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
35613561

35623562
for (const auto *PID : ID->property_impls()) {
35633563
if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) {
3564-
ObjCPropertyDecl *PD = PID->getPropertyDecl();
3565-
3566-
if (ObjCMethodDecl *MD = PD->getGetterMethodDecl())
3564+
if (ObjCMethodDecl *MD = PID->getGetterMethodDecl())
35673565
if (GetMethodDefinition(MD))
35683566
Methods[InstanceMethods].push_back(MD);
3569-
if (ObjCMethodDecl *MD = PD->getSetterMethodDecl())
3567+
if (ObjCMethodDecl *MD = PID->getSetterMethodDecl())
35703568
if (GetMethodDefinition(MD))
35713569
Methods[InstanceMethods].push_back(MD);
35723570
}
@@ -6227,19 +6225,6 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
62276225
} else {
62286226
for (const auto *MD : ID->instance_methods())
62296227
methods.push_back(MD);
6230-
6231-
for (const auto *PID : ID->property_impls()) {
6232-
if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize){
6233-
ObjCPropertyDecl *PD = PID->getPropertyDecl();
6234-
6235-
if (auto MD = PD->getGetterMethodDecl())
6236-
if (GetMethodDefinition(MD))
6237-
methods.push_back(MD);
6238-
if (auto MD = PD->getSetterMethodDecl())
6239-
if (GetMethodDefinition(MD))
6240-
methods.push_back(MD);
6241-
}
6242-
}
62436228
}
62446229

62456230
values.add(emitMethodList(ID->getObjCRuntimeNameAsString(),
@@ -6702,9 +6687,8 @@ CGObjCNonFragileABIMac::emitMethodList(Twine name, MethodListType kind,
67026687
// method_count
67036688
values.addInt(ObjCTypes.IntTy, methods.size());
67046689
auto methodArray = values.beginArray(ObjCTypes.MethodTy);
6705-
for (auto MD : methods) {
6690+
for (auto MD : methods)
67066691
emitMethodConstant(methodArray, MD, forProtocol);
6707-
}
67086692
methodArray.finishAndAddTo(values);
67096693

67106694
llvm::GlobalVariable *GV = finishAndCreateGlobal(values, prefix + name, CGM);

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -638,8 +638,7 @@ static llvm::Constant *getPrologueSignature(CodeGenModule &CGM,
638638
return CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM);
639639
}
640640

641-
void CodeGenFunction::StartFunction(GlobalDecl GD,
642-
QualType RetTy,
641+
void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
643642
llvm::Function *Fn,
644643
const CGFunctionInfo &FnInfo,
645644
const FunctionArgList &Args,

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4978,11 +4978,12 @@ void CodeGenModule::EmitObjCPropertyImplementations(const
49784978
// we want, that just indicates if the decl came from a
49794979
// property. What we want to know is if the method is defined in
49804980
// this implementation.
4981-
if (!D->getInstanceMethod(PD->getGetterName()))
4981+
auto *Getter = PID->getGetterMethodDecl();
4982+
if (!Getter || Getter->isSynthesizedAccessorStub())
49824983
CodeGenFunction(*this).GenerateObjCGetter(
4983-
const_cast<ObjCImplementationDecl *>(D), PID);
4984-
if (!PD->isReadOnly() &&
4985-
!D->getInstanceMethod(PD->getSetterName()))
4984+
const_cast<ObjCImplementationDecl *>(D), PID);
4985+
auto *Setter = PID->getSetterMethodDecl();
4986+
if (!PD->isReadOnly() && (!Setter || Setter->isSynthesizedAccessorStub()))
49864987
CodeGenFunction(*this).GenerateObjCSetter(
49874988
const_cast<ObjCImplementationDecl *>(D), PID);
49884989
}
@@ -5019,12 +5020,13 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
50195020
if (needsDestructMethod(D)) {
50205021
IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct");
50215022
Selector cxxSelector = getContext().Selectors.getSelector(0, &II);
5022-
ObjCMethodDecl *DTORMethod =
5023-
ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(),
5024-
cxxSelector, getContext().VoidTy, nullptr, D,
5025-
/*isInstance=*/true, /*isVariadic=*/false,
5026-
/*isPropertyAccessor=*/true, /*isImplicitlyDeclared=*/true,
5027-
/*isDefined=*/false, ObjCMethodDecl::Required);
5023+
ObjCMethodDecl *DTORMethod = ObjCMethodDecl::Create(
5024+
getContext(), D->getLocation(), D->getLocation(), cxxSelector,
5025+
getContext().VoidTy, nullptr, D,
5026+
/*isInstance=*/true, /*isVariadic=*/false,
5027+
/*isPropertyAccessor=*/true, /*isSynthesizedAccessorStub=*/false,
5028+
/*isImplicitlyDeclared=*/true,
5029+
/*isDefined=*/false, ObjCMethodDecl::Required);
50285030
D->addInstanceMethod(DTORMethod);
50295031
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false);
50305032
D->setHasDestructors(true);
@@ -5039,17 +5041,13 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
50395041
IdentifierInfo *II = &getContext().Idents.get(".cxx_construct");
50405042
Selector cxxSelector = getContext().Selectors.getSelector(0, &II);
50415043
// The constructor returns 'self'.
5042-
ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(),
5043-
D->getLocation(),
5044-
D->getLocation(),
5045-
cxxSelector,
5046-
getContext().getObjCIdType(),
5047-
nullptr, D, /*isInstance=*/true,
5048-
/*isVariadic=*/false,
5049-
/*isPropertyAccessor=*/true,
5050-
/*isImplicitlyDeclared=*/true,
5051-
/*isDefined=*/false,
5052-
ObjCMethodDecl::Required);
5044+
ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(
5045+
getContext(), D->getLocation(), D->getLocation(), cxxSelector,
5046+
getContext().getObjCIdType(), nullptr, D, /*isInstance=*/true,
5047+
/*isVariadic=*/false,
5048+
/*isPropertyAccessor=*/true, /*isSynthesizedAccessorStub=*/false,
5049+
/*isImplicitlyDeclared=*/true,
5050+
/*isDefined=*/false, ObjCMethodDecl::Required);
50535051
D->addInstanceMethod(CTORMethod);
50545052
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true);
50555053
D->setHasNonZeroConstructors(true);

0 commit comments

Comments
 (0)