Skip to content

Commit 2073dd2

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
1 parent 8d22100 commit 2073dd2

29 files changed

+505
-197
lines changed

clang/include/clang/AST/DeclBase.h

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

1593+
/// True if this method is a synthesized property accessor stub.
1594+
uint64_t IsSynthesizedAccessorStub : 1;
1595+
15931596
/// Method has a definition.
15941597
uint64_t IsDefined : 1;
15951598

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

@@ -2779,6 +2789,11 @@ class ObjCPropertyImplDecl : public Decl {
27792789
/// Null for \@dynamic. Required for \@synthesize.
27802790
ObjCIvarDecl *PropertyIvarDecl;
27812791

2792+
/// The getter's definition, which has an empty body if synthesized.
2793+
ObjCMethodDecl *GetterMethodDecl = nullptr;
2794+
/// The getter's definition, which has an empty body if synthesized.
2795+
ObjCMethodDecl *SetterMethodDecl = nullptr;
2796+
27822797
/// Null for \@dynamic. Non-null if property must be copy-constructed in
27832798
/// getter.
27842799
Expr *GetterCXXConstructor = nullptr;
@@ -2845,6 +2860,12 @@ class ObjCPropertyImplDecl : public Decl {
28452860
return IvarLoc.isValid() && IvarLoc != getLocation();
28462861
}
28472862

2863+
ObjCMethodDecl *getGetterMethodDecl() const { return GetterMethodDecl; }
2864+
void setGetterMethodDecl(ObjCMethodDecl *MD) { GetterMethodDecl = MD; }
2865+
2866+
ObjCMethodDecl *getSetterMethodDecl() const { return SetterMethodDecl; }
2867+
void setSetterMethodDecl(ObjCMethodDecl *MD) { SetterMethodDecl = MD; }
2868+
28482869
Expr *getGetterCXXConstructor() const {
28492870
return GetterCXXConstructor;
28502871
}

clang/lib/AST/ASTImporter.cpp

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

39643964
ObjCMethodDecl *ToMethod;
39653965
if (GetImportedOrCreateDecl(
3966-
ToMethod, D, Importer.getToContext(), Loc,
3967-
ToEndLoc, Name.getObjCSelector(), ToReturnType,
3968-
ToReturnTypeSourceInfo, DC, D->isInstanceMethod(), D->isVariadic(),
3969-
D->isPropertyAccessor(), D->isImplicit(), D->isDefined(),
3966+
ToMethod, D, Importer.getToContext(), Loc, ToEndLoc,
3967+
Name.getObjCSelector(), ToReturnType, ToReturnTypeSourceInfo, DC,
3968+
D->isInstanceMethod(), D->isVariadic(), D->isPropertyAccessor(),
3969+
D->isSynthesizedAccessorStub(), D->isImplicit(), D->isDefined(),
39703970
D->getImplementationControl(), D->hasRelatedResultType()))
39713971
return ToMethod;
39723972

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
@@ -1880,13 +1880,12 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
18801880
for (auto *propImpl : OID->property_impls())
18811881
if (propImpl->getPropertyImplementation() ==
18821882
ObjCPropertyImplDecl::Synthesize) {
1883-
ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
1884-
auto addIfExists = [&](const ObjCMethodDecl* OMD) {
1885-
if (OMD)
1883+
auto addIfExists = [&](const ObjCMethodDecl *OMD) {
1884+
if (OMD && OMD->hasBody())
18861885
InstanceMethods.push_back(OMD);
18871886
};
1888-
addIfExists(prop->getGetterMethodDecl());
1889-
addIfExists(prop->getSetterMethodDecl());
1887+
addIfExists(propImpl->getGetterMethodDecl());
1888+
addIfExists(propImpl->getSetterMethodDecl());
18901889
}
18911890

18921891
if (InstanceMethods.size() == 0)
@@ -3494,13 +3493,12 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
34943493
for (auto *propertyImpl : OID->property_impls())
34953494
if (propertyImpl->getPropertyImplementation() ==
34963495
ObjCPropertyImplDecl::Synthesize) {
3497-
ObjCPropertyDecl *property = propertyImpl->getPropertyDecl();
34983496
auto addPropertyMethod = [&](const ObjCMethodDecl *accessor) {
34993497
if (accessor)
35003498
InstanceMethods.push_back(accessor);
35013499
};
3502-
addPropertyMethod(property->getGetterMethodDecl());
3503-
addPropertyMethod(property->getSetterMethodDecl());
3500+
addPropertyMethod(propertyImpl->getGetterMethodDecl());
3501+
addPropertyMethod(propertyImpl->getSetterMethodDecl());
35043502
}
35053503

35063504
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
@@ -3559,12 +3559,10 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
35593559

35603560
for (const auto *PID : ID->property_impls()) {
35613561
if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) {
3562-
ObjCPropertyDecl *PD = PID->getPropertyDecl();
3563-
3564-
if (ObjCMethodDecl *MD = PD->getGetterMethodDecl())
3562+
if (ObjCMethodDecl *MD = PID->getGetterMethodDecl())
35653563
if (GetMethodDefinition(MD))
35663564
Methods[InstanceMethods].push_back(MD);
3567-
if (ObjCMethodDecl *MD = PD->getSetterMethodDecl())
3565+
if (ObjCMethodDecl *MD = PID->getSetterMethodDecl())
35683566
if (GetMethodDefinition(MD))
35693567
Methods[InstanceMethods].push_back(MD);
35703568
}
@@ -6232,19 +6230,6 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
62326230
} else {
62336231
for (const auto *MD : ID->instance_methods())
62346232
methods.push_back(MD);
6235-
6236-
for (const auto *PID : ID->property_impls()) {
6237-
if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize){
6238-
ObjCPropertyDecl *PD = PID->getPropertyDecl();
6239-
6240-
if (auto MD = PD->getGetterMethodDecl())
6241-
if (GetMethodDefinition(MD))
6242-
methods.push_back(MD);
6243-
if (auto MD = PD->getSetterMethodDecl())
6244-
if (GetMethodDefinition(MD))
6245-
methods.push_back(MD);
6246-
}
6247-
}
62486233
}
62496234

62506235
values.add(emitMethodList(ID->getObjCRuntimeNameAsString(),
@@ -6707,9 +6692,8 @@ CGObjCNonFragileABIMac::emitMethodList(Twine name, MethodListType kind,
67076692
// method_count
67086693
values.addInt(ObjCTypes.IntTy, methods.size());
67096694
auto methodArray = values.beginArray(ObjCTypes.MethodTy);
6710-
for (auto MD : methods) {
6695+
for (auto MD : methods)
67116696
emitMethodConstant(methodArray, MD, forProtocol);
6712-
}
67136697
methodArray.finishAndAddTo(values);
67146698

67156699
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
@@ -690,8 +690,7 @@ static llvm::Constant *getPrologueSignature(CodeGenModule &CGM,
690690
return CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM);
691691
}
692692

693-
void CodeGenFunction::StartFunction(GlobalDecl GD,
694-
QualType RetTy,
693+
void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
695694
llvm::Function *Fn,
696695
const CGFunctionInfo &FnInfo,
697696
const FunctionArgList &Args,

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5113,11 +5113,12 @@ void CodeGenModule::EmitObjCPropertyImplementations(const
51135113
// we want, that just indicates if the decl came from a
51145114
// property. What we want to know is if the method is defined in
51155115
// this implementation.
5116-
if (!D->getInstanceMethod(PD->getGetterName()))
5116+
auto *Getter = PID->getGetterMethodDecl();
5117+
if (!Getter || Getter->isSynthesizedAccessorStub())
51175118
CodeGenFunction(*this).GenerateObjCGetter(
5118-
const_cast<ObjCImplementationDecl *>(D), PID);
5119-
if (!PD->isReadOnly() &&
5120-
!D->getInstanceMethod(PD->getSetterName()))
5119+
const_cast<ObjCImplementationDecl *>(D), PID);
5120+
auto *Setter = PID->getSetterMethodDecl();
5121+
if (!PD->isReadOnly() && (!Setter || Setter->isSynthesizedAccessorStub()))
51215122
CodeGenFunction(*this).GenerateObjCSetter(
51225123
const_cast<ObjCImplementationDecl *>(D), PID);
51235124
}
@@ -5154,12 +5155,13 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
51545155
if (needsDestructMethod(D)) {
51555156
IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct");
51565157
Selector cxxSelector = getContext().Selectors.getSelector(0, &II);
5157-
ObjCMethodDecl *DTORMethod =
5158-
ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(),
5159-
cxxSelector, getContext().VoidTy, nullptr, D,
5160-
/*isInstance=*/true, /*isVariadic=*/false,
5161-
/*isPropertyAccessor=*/true, /*isImplicitlyDeclared=*/true,
5162-
/*isDefined=*/false, ObjCMethodDecl::Required);
5158+
ObjCMethodDecl *DTORMethod = ObjCMethodDecl::Create(
5159+
getContext(), D->getLocation(), D->getLocation(), cxxSelector,
5160+
getContext().VoidTy, nullptr, D,
5161+
/*isInstance=*/true, /*isVariadic=*/false,
5162+
/*isPropertyAccessor=*/true, /*isSynthesizedAccessorStub=*/false,
5163+
/*isImplicitlyDeclared=*/true,
5164+
/*isDefined=*/false, ObjCMethodDecl::Required);
51635165
D->addInstanceMethod(DTORMethod);
51645166
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false);
51655167
D->setHasDestructors(true);
@@ -5174,17 +5176,13 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
51745176
IdentifierInfo *II = &getContext().Idents.get(".cxx_construct");
51755177
Selector cxxSelector = getContext().Selectors.getSelector(0, &II);
51765178
// The constructor returns 'self'.
5177-
ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(),
5178-
D->getLocation(),
5179-
D->getLocation(),
5180-
cxxSelector,
5181-
getContext().getObjCIdType(),
5182-
nullptr, D, /*isInstance=*/true,
5183-
/*isVariadic=*/false,
5184-
/*isPropertyAccessor=*/true,
5185-
/*isImplicitlyDeclared=*/true,
5186-
/*isDefined=*/false,
5187-
ObjCMethodDecl::Required);
5179+
ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(
5180+
getContext(), D->getLocation(), D->getLocation(), cxxSelector,
5181+
getContext().getObjCIdType(), nullptr, D, /*isInstance=*/true,
5182+
/*isVariadic=*/false,
5183+
/*isPropertyAccessor=*/true, /*isSynthesizedAccessorStub=*/false,
5184+
/*isImplicitlyDeclared=*/true,
5185+
/*isDefined=*/false, ObjCMethodDecl::Required);
51885186
D->addInstanceMethod(CTORMethod);
51895187
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true);
51905188
D->setHasNonZeroConstructors(true);

0 commit comments

Comments
 (0)