aprantl created this revision. aprantl added reviewers: rjmccall, dergachev.a, dcoughlin, theraven, ahatanak, erik.pilkington, davide. Herald added subscribers: arphaman, dexonsmith. Herald added a project: clang. aprantl added a child revision: D66121: Debug Info: Nest Objective-C property function decls inside their container..
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. This patch became much longer than I hoped it would be but most of the changes are mechanical in nature. 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. Most of the updates are very straightforward, the most irritating part was updating the static analyzer, there may be a more elegant way to do this. I'm somewhat concerned that I didn't have to update the GNU Objective-C runtime for the testsuite to pass. 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. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D68108 Files: clang/include/clang/AST/DeclObjC.h clang/include/clang/Sema/Sema.h clang/lib/AST/DeclObjC.cpp clang/lib/Analysis/BodyFarm.cpp clang/lib/CodeGen/CGObjC.cpp clang/lib/CodeGen/CGObjCGNU.cpp clang/lib/CodeGen/CGObjCMac.cpp clang/lib/CodeGen/CodeGenFunction.cpp clang/lib/CodeGen/CodeGenModule.cpp clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp clang/lib/Frontend/Rewrite/RewriteObjC.cpp clang/lib/Index/IndexDecl.cpp clang/lib/Sema/SemaDeclObjC.cpp clang/lib/Sema/SemaObjCProperty.cpp clang/lib/Serialization/ASTReaderDecl.cpp clang/lib/Serialization/ASTWriterDecl.cpp clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp clang/lib/StaticAnalyzer/Core/CallEvent.cpp clang/test/AST/ast-dump-decl-json.m clang/test/Analysis/Inputs/expected-plists/nullability-notes.m.plist clang/test/Analysis/properties.m clang/test/CodeGenObjC/debug-info-synthesis.m clang/test/CodeGenObjC/debug-property-synth.m clang/test/CodeGenObjC/debuginfo-properties.m clang/test/CodeGenObjC/instance-method-metadata.m
Index: clang/test/CodeGenObjC/instance-method-metadata.m =================================================================== --- clang/test/CodeGenObjC/instance-method-metadata.m +++ clang/test/CodeGenObjC/instance-method-metadata.m @@ -1,6 +1,5 @@ // REQUIRES: x86-registered-target -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -S -o %t %s -// RUN: FileCheck < %t %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -S %s -o - | FileCheck %s // rdar://9072317 Index: clang/test/CodeGenObjC/debuginfo-properties.m =================================================================== --- clang/test/CodeGenObjC/debuginfo-properties.m +++ clang/test/CodeGenObjC/debuginfo-properties.m @@ -11,19 +11,6 @@ @protocol HasASelection <NSObject> @property (nonatomic, retain) Selection* selection; -// CHECK: !DISubprogram(name: "-[MyClass selection]" -// CHECK-SAME: line: [[@LINE-2]] -// CHECK-SAME: DISPFlagLocalToUnit | DISPFlagDefinition -// CHECK: !DISubprogram(name: "-[MyClass setSelection:]" -// CHECK-SAME: line: [[@LINE-5]] -// CHECK-SAME: DISPFlagLocalToUnit | DISPFlagDefinition -// CHECK: !DISubprogram(name: "-[OtherClass selection]" -// CHECK-SAME: line: [[@LINE-8]] -// CHECK-SAME: DISPFlagLocalToUnit | DISPFlagDefinition -// CHECK: !DISubprogram(name: "-[OtherClass setSelection:]" -// CHECK-SAME: line: [[@LINE-11]] -// CHECK-SAME: DISPFlagLocalToUnit | DISPFlagDefinition - @end @interface MyClass : NSObject <HasASelection> { @@ -33,6 +20,12 @@ @implementation MyClass @synthesize selection = _selection; +// CHECK: !DISubprogram(name: "-[MyClass selection]" +// CHECK-SAME: line: [[@LINE-2]] +// CHECK-SAME: DISPFlagLocalToUnit | DISPFlagDefinition +// CHECK: !DISubprogram(name: "-[MyClass setSelection:]" +// CHECK-SAME: line: [[@LINE-5]] +// CHECK-SAME: DISPFlagLocalToUnit | DISPFlagDefinition @end @interface OtherClass : NSObject <HasASelection> { @@ -41,4 +34,10 @@ @end @implementation OtherClass @synthesize selection = _selection; +// CHECK: !DISubprogram(name: "-[OtherClass selection]" +// CHECK-SAME: line: [[@LINE-2]] +// CHECK-SAME: DISPFlagLocalToUnit | DISPFlagDefinition +// CHECK: !DISubprogram(name: "-[OtherClass setSelection:]" +// CHECK-SAME: line: [[@LINE-5]] +// CHECK-SAME: DISPFlagLocalToUnit | DISPFlagDefinition @end Index: clang/test/CodeGenObjC/debug-property-synth.m =================================================================== --- clang/test/CodeGenObjC/debug-property-synth.m +++ clang/test/CodeGenObjC/debug-property-synth.m @@ -7,6 +7,10 @@ @interface I { int _p1; } +@property int p1; +@end + +@implementation I // Test that the linetable entries for the synthesized getter and // setter are correct. // @@ -22,10 +26,6 @@ // CHECK: ![[DBG1]] = !DILocation(line: [[@LINE+3]], // CHECK: !DISubprogram(name: "-[I setP1:]",{{.*}} line: [[@LINE+2]],{{.*}} DISPFlagLocalToUnit | DISPFlagDefinition // CHECK: ![[DBG2]] = !DILocation(line: [[@LINE+1]], -@property int p1; -@end - -@implementation I @synthesize p1 = _p1; @end Index: clang/test/CodeGenObjC/debug-info-synthesis.m =================================================================== --- clang/test/CodeGenObjC/debug-info-synthesis.m +++ clang/test/CodeGenObjC/debug-info-synthesis.m @@ -30,8 +30,8 @@ } } -// CHECK: ![[FILE:.*]] = !DIFile(filename: "{{[^"]+}}foo.h" +// CHECK: ![[FILE:.*]] = !DIFile(filename: "foo.m" // CHECK: !DISubprogram(name: "-[Foo setDict:]" // CHECK-SAME: file: ![[FILE]], -// CHECK-SAME: line: 8, +// CHECK-SAME: line: 7, // CHECK-SAME: DISPFlagLocalToUnit | DISPFlagDefinition Index: clang/test/Analysis/properties.m =================================================================== --- clang/test/Analysis/properties.m +++ clang/test/Analysis/properties.m @@ -34,7 +34,7 @@ +(id)alloc; -(id)initWithInteger:(int)i; @end - +#if 0 // rdar://6946338 @interface Test1 : NSObject { @@ -1004,7 +1004,7 @@ } #endif // non-ARC - +#endif @interface ExplicitAccessorInCategory : NSObject @property(readonly) int normal; - (int)normal; Index: clang/test/Analysis/Inputs/expected-plists/nullability-notes.m.plist =================================================================== --- clang/test/Analysis/Inputs/expected-plists/nullability-notes.m.plist +++ clang/test/Analysis/Inputs/expected-plists/nullability-notes.m.plist @@ -188,7 +188,6 @@ <dict> <key>0</key> <array> - <integer>10</integer> <integer>14</integer> <integer>16</integer> <integer>17</integer> Index: clang/test/AST/ast-dump-decl-json.m =================================================================== --- clang/test/AST/ast-dump-decl-json.m +++ clang/test/AST/ast-dump-decl-json.m @@ -1332,7 +1332,7 @@ // CHECK-NEXT: "col": 13, // CHECK-NEXT: "tokLen": 3 // CHECK-NEXT: } -// CHECK-NEXT: }, +// CHECK-NEXT: }, // CHECK-NEXT: "name": "bar", // CHECK-NEXT: "implKind": "synthesize", // CHECK-NEXT: "propertyDecl": { @@ -1348,7 +1348,155 @@ // CHECK-NEXT: "qualType": "int" // CHECK-NEXT: } // CHECK-NEXT: } -// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ObjCMethodDecl", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "line": 70, +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "col": 13, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "name": "getterFoo", +// CHECK-NEXT: "returnType": { +// CHECK-NEXT: "qualType": "int" +// CHECK-NEXT: }, +// CHECK-NEXT: "instance": true +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ObjCMethodDecl", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "col": 13, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "name": "setterFoo:", +// CHECK-NEXT: "returnType": { +// CHECK-NEXT: "qualType": "void" +// CHECK-NEXT: }, +// CHECK-NEXT: "instance": true, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParmVarDecl", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "line": 63, +// CHECK-NEXT: "col": 52, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "col": 52, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "col": 52, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "name": "foo", +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "int" +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ObjCMethodDecl", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "line": 71, +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "col": 13, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "name": "bar", +// CHECK-NEXT: "returnType": { +// CHECK-NEXT: "qualType": "int" +// CHECK-NEXT: }, +// CHECK-NEXT: "instance": true +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ObjCMethodDecl", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "col": 13, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "name": "setBar:", +// CHECK-NEXT: "returnType": { +// CHECK-NEXT: "qualType": "void" +// CHECK-NEXT: }, +// CHECK-NEXT: "instance": true, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParmVarDecl", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "line": 64, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "name": "bar", +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "int" +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } // CHECK-NEXT: ] // CHECK-NEXT: } Index: clang/lib/StaticAnalyzer/Core/CallEvent.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -1080,7 +1080,7 @@ const ObjCPropertyDecl *ObjCMethodCall::getAccessedProperty() const { // Look for properties accessed with property syntax (foo.bar = ...) - if ( getMessageKind() == OCM_PropertyAccess) { + if (getMessageKind() == OCM_PropertyAccess) { const PseudoObjectExpr *POE = getContainingPseudoObjectExpr(); assert(POE && "Property access without PseudoObjectExpr?"); Index: clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp +++ clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp @@ -144,7 +144,8 @@ continue; const Stmt *Body = M->getBody(); - assert(Body); + if (!Body) + continue; MethodCrawler MC(IvarToPropMap, M->getCanonicalDecl(), InterD, BR, this, DCtx); Index: clang/lib/Serialization/ASTWriterDecl.cpp =================================================================== --- clang/lib/Serialization/ASTWriterDecl.cpp +++ clang/lib/Serialization/ASTWriterDecl.cpp @@ -884,6 +884,8 @@ Record.AddDeclRef(D->getPropertyDecl()); Record.AddDeclRef(D->getPropertyIvarDecl()); Record.AddSourceLocation(D->getPropertyIvarDeclLoc()); + Record.AddDeclRef(D->getGetterMethodDecl()); + Record.AddDeclRef(D->getSetterMethodDecl()); Record.AddStmt(D->getGetterCXXConstructor()); Record.AddStmt(D->getSetterCXXAssignment()); Code = serialization::DECL_OBJC_PROPERTY_IMPL; Index: clang/lib/Serialization/ASTReaderDecl.cpp =================================================================== --- clang/lib/Serialization/ASTReaderDecl.cpp +++ clang/lib/Serialization/ASTReaderDecl.cpp @@ -1313,6 +1313,8 @@ D->setPropertyDecl(ReadDeclAs<ObjCPropertyDecl>()); D->PropertyIvarDecl = ReadDeclAs<ObjCIvarDecl>(); D->IvarLoc = ReadSourceLocation(); + D->setGetterMethodDecl(ReadDeclAs<ObjCMethodDecl>()); + D->setSetterMethodDecl(ReadDeclAs<ObjCMethodDecl>()); D->setGetterCXXConstructor(Record.readExpr()); D->setSetterCXXAssignment(Record.readExpr()); } Index: clang/lib/Sema/SemaObjCProperty.cpp =================================================================== --- clang/lib/Sema/SemaObjCProperty.cpp +++ clang/lib/Sema/SemaObjCProperty.cpp @@ -1037,6 +1037,33 @@ return false; } +void Sema::RedeclarePropertyAccessor(ObjCImplementationDecl *Impl, + SynthesizedObjCPropertyAccessor Accessor) { + ObjCMethodDecl *Decl = Accessor.AccessorDecl; + ObjCMethodDecl *ImplDecl = ObjCMethodDecl::Create( + Context, Accessor.AtLoc, Accessor.PropertyLoc, Decl->getSelector(), + Decl->getReturnType(), Decl->getReturnTypeSourceInfo(), Impl, + Decl->isInstanceMethod(), Decl->isVariadic(), Decl->isPropertyAccessor(), + Decl->isImplicit(), Decl->isDefined(), Decl->getImplementationControl(), + Decl->hasRelatedResultType()); + ImplDecl->getMethodFamily(); + if (Decl->hasAttrs()) + ImplDecl->setAttrs(Decl->getAttrs()); + ImplDecl->setSelfDecl(Decl->getSelfDecl()); + ImplDecl->setCmdDecl(Decl->getCmdDecl()); + SmallVector<SourceLocation, 1> SelLocs; + Decl->getSelectorLocs(SelLocs); + ImplDecl->setMethodParams(Context, Decl->parameters(), SelLocs); + ImplDecl->setLexicalDeclContext(Impl); + ImplDecl->setDefined(false); + Impl->makeDeclVisibleInContext(ImplDecl); + Impl->addDecl(ImplDecl); + if (!Accessor.IsSetter) + Accessor.PropertyImpl->setGetterMethodDecl(ImplDecl); + else + Accessor.PropertyImpl->setSetterMethodDecl(ImplDecl); +} + /// ActOnPropertyImplDecl - This routine performs semantic checks and /// builds the AST node for a property implementation declaration; declared /// as \@synthesize or \@dynamic. @@ -1404,6 +1431,12 @@ if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) { getterMethod->createImplicitParams(Context, IDecl); + + // Redeclare the getter within the implementation as DeclContext. + if (Synthesize) + SynthesizedObjCPropertyAccessors[ClassImpDecl].push_back( + {PIDecl, getterMethod, AtLoc, PropertyLoc, false}); + if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr && Ivar->getType()->isRecordType()) { // For Objective-C++, need to synthesize the AST for the IVAR object to be @@ -1456,8 +1489,15 @@ break; } } + if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) { setterMethod->createImplicitParams(Context, IDecl); + + // Redeclare the setter within the implementation as DeclContext. + if (Synthesize) + SynthesizedObjCPropertyAccessors[ClassImpDecl].push_back( + {PIDecl, setterMethod, AtLoc, PropertyLoc, true}); + if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr && Ivar->getType()->isRecordType()) { // FIXME. Eventually we want to do this for Objective-C as well. @@ -2083,7 +2123,6 @@ void Sema::diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl) { for (const auto *propertyImpl : impDecl->property_impls()) { const auto *property = propertyImpl->getPropertyDecl(); - // Warn about null_resettable properties with synthesized setters, // because the setter won't properly handle nil. if (propertyImpl->getPropertyImplementation() @@ -2094,8 +2133,12 @@ property->getSetterMethodDecl()) { auto *getterMethod = property->getGetterMethodDecl(); auto *setterMethod = property->getSetterMethodDecl(); - if (!impDecl->getInstanceMethod(setterMethod->getSelector()) && - !impDecl->getInstanceMethod(getterMethod->getSelector())) { + auto *getterImpl = + impDecl->getInstanceMethod(getterMethod->getSelector()); + auto *setterImpl = + impDecl->getInstanceMethod(setterMethod->getSelector()); + if ((!getterImpl || !getterImpl->getBody()) && + (!setterImpl || !setterImpl->getBody())) { SourceLocation loc = propertyImpl->getLocation(); if (loc.isInvalid()) loc = impDecl->getBeginLoc(); @@ -2138,6 +2181,10 @@ SetterMethod = Property->isClassProperty() ? IMPDecl->getClassMethod(Property->getSetterName()) : IMPDecl->getInstanceMethod(Property->getSetterName()); + if (GetterMethod && !GetterMethod->getBody()) + GetterMethod = nullptr; + if (SetterMethod && !SetterMethod->getBody()) + SetterMethod = nullptr; LookedUpGetterSetter = true; if (GetterMethod) { Diag(GetterMethod->getLocation(), @@ -2168,6 +2215,10 @@ SetterMethod = Property->isClassProperty() ? IMPDecl->getClassMethod(Property->getSetterName()) : IMPDecl->getInstanceMethod(Property->getSetterName()); + if (GetterMethod && !GetterMethod->getBody()) + GetterMethod = nullptr; + if (SetterMethod && !SetterMethod->getBody()) + SetterMethod = nullptr; } if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) { SourceLocation MethodLoc = @@ -2210,8 +2261,10 @@ for (const auto *PID : D->property_impls()) { const ObjCPropertyDecl *PD = PID->getPropertyDecl(); if (PD && !PD->hasAttr<NSReturnsNotRetainedAttr>() && - !PD->isClassProperty() && - !D->getInstanceMethod(PD->getGetterName())) { + !PD->isClassProperty()) { + ObjCMethodDecl *IM = D->getInstanceMethod(PD->getGetterName()); + if (IM && IM->getBody()) + continue; ObjCMethodDecl *method = PD->getGetterMethodDecl(); if (!method) continue; Index: clang/lib/Sema/SemaDeclObjC.cpp =================================================================== --- clang/lib/Sema/SemaDeclObjC.cpp +++ clang/lib/Sema/SemaDeclObjC.cpp @@ -2828,6 +2828,9 @@ "Expected to find the method through lookup as well"); // ImpMethodDecl may be null as in a @dynamic property. if (ImpMethodDecl) { + // Skip property accessor function stubs. + if (I->isPropertyAccessor() && !ImpMethodDecl->getBody()) + continue; if (!WarnCategoryMethodImpl) WarnConflictingTypedMethods(ImpMethodDecl, I, isa<ObjCProtocolDecl>(CDecl)); @@ -2854,6 +2857,9 @@ "Expected to find the method through lookup as well"); // ImpMethodDecl may be null as in a @dynamic property. if (ImpMethodDecl) { + // Skip property accessor function stubs. + if (I->isPropertyAccessor() && !ImpMethodDecl->getBody()) + continue; if (!WarnCategoryMethodImpl) WarnConflictingTypedMethods(ImpMethodDecl, I, isa<ObjCProtocolDecl>(CDecl)); @@ -3903,6 +3909,15 @@ || isa<ObjCProtocolDecl>(ClassDecl); bool checkIdenticalMethods = isa<ObjCImplementationDecl>(ClassDecl); + // Redeclare synthesized property accessors, if they haven't been overridden. + auto Accessors = SynthesizedObjCPropertyAccessors.find(OCD); + if (Accessors != SynthesizedObjCPropertyAccessors.end()) + for (auto &A : Accessors->second) { + auto *OID = cast<ObjCImplementationDecl>(OCD); + if (!OID->getInstanceMethod(A.AccessorDecl->getSelector())) + RedeclarePropertyAccessor(OID, A); + } + // FIXME: Remove these and use the ObjCContainerDecl/DeclContext. llvm::DenseMap<Selector, const ObjCMethodDecl*> InsMap; llvm::DenseMap<Selector, const ObjCMethodDecl*> ClsMap; @@ -5063,6 +5078,9 @@ if (!IV) continue; + if (!CurMethod->getBody()) + continue; + UnusedBackingIvarChecker Checker(*this, CurMethod, IV); Checker.TraverseStmt(CurMethod->getBody()); if (Checker.AccessedIvar) Index: clang/lib/Index/IndexDecl.cpp =================================================================== --- clang/lib/Index/IndexDecl.cpp +++ clang/lib/Index/IndexDecl.cpp @@ -513,7 +513,6 @@ } bool VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) { - ObjCPropertyDecl *PD = D->getPropertyDecl(); auto *Container = cast<ObjCImplDecl>(D->getDeclContext()); SourceLocation Loc = D->getLocation(); SymbolRoleSet Roles = 0; @@ -533,12 +532,12 @@ assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize); SymbolRoleSet AccessorMethodRoles = SymbolRoleSet(SymbolRole::Dynamic) | SymbolRoleSet(SymbolRole::Implicit); - if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) { + if (ObjCMethodDecl *MD = D->getGetterMethodDecl()) { if (MD->isPropertyAccessor() && !hasUserDefined(MD, Container)) IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container); } - if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) { + if (ObjCMethodDecl *MD = D->getSetterMethodDecl()) { if (MD->isPropertyAccessor() && !hasUserDefined(MD, Container)) IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container); Index: clang/lib/Frontend/Rewrite/RewriteObjC.cpp =================================================================== --- clang/lib/Frontend/Rewrite/RewriteObjC.cpp +++ clang/lib/Frontend/Rewrite/RewriteObjC.cpp @@ -786,8 +786,9 @@ if (!OID) return; + unsigned Attributes = PD->getPropertyAttributes(); - if (!PD->getGetterMethodDecl()->isDefined()) { + if (PID->getGetterMethodDecl() && !PID->getGetterMethodDecl()->isDefined()) { bool GenGetProperty = !(Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) && (Attributes & (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_copy)); @@ -799,7 +800,7 @@ "id objc_getProperty(id, SEL, long, bool);\n"; } RewriteObjCMethodDecl(OID->getContainingInterface(), - PD->getGetterMethodDecl(), Getr); + PID->getGetterMethodDecl(), Getr); Getr += "{ "; // Synthesize an explicit cast to gain access to the ivar. // See objc-act.c:objc_synthesize_new_getter() for details. @@ -807,7 +808,7 @@ // return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1) Getr += "typedef "; const FunctionType *FPRetType = nullptr; - RewriteTypeIntoString(PD->getGetterMethodDecl()->getReturnType(), Getr, + RewriteTypeIntoString(PID->getGetterMethodDecl()->getReturnType(), Getr, FPRetType); Getr += " _TYPE"; if (FPRetType) { @@ -843,7 +844,8 @@ InsertText(onePastSemiLoc, Getr); } - if (PD->isReadOnly() || PD->getSetterMethodDecl()->isDefined()) + if (PD->isReadOnly() || !PID->getSetterMethodDecl() || + PID->getSetterMethodDecl()->isDefined()) return; // Generate the 'setter' function. @@ -858,7 +860,7 @@ } RewriteObjCMethodDecl(OID->getContainingInterface(), - PD->getSetterMethodDecl(), Setr); + PID->getSetterMethodDecl(), Setr); Setr += "{ "; // Synthesize an explicit cast to initialize the ivar. // See objc-act.c:objc_synthesize_new_setter() for details. @@ -1167,6 +1169,8 @@ InsertText(IMD ? IMD->getBeginLoc() : CID->getBeginLoc(), "// "); for (auto *OMD : IMD ? IMD->instance_methods() : CID->instance_methods()) { + if (!OMD->getBody()) + continue; std::string ResultStr; RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); SourceLocation LocStart = OMD->getBeginLoc(); @@ -1178,6 +1182,8 @@ } for (auto *OMD : IMD ? IMD->class_methods() : CID->class_methods()) { + if (!OMD->getBody()) + continue; std::string ResultStr; RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); SourceLocation LocStart = OMD->getBeginLoc(); @@ -5354,12 +5360,12 @@ ObjCPropertyDecl *PD = Prop->getPropertyDecl(); if (!PD) continue; - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl()) if (!Getter->isDefined()) InstanceMethods.push_back(Getter); if (PD->isReadOnly()) continue; - if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) + if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl()) if (!Setter->isDefined()) InstanceMethods.push_back(Setter); } @@ -5632,11 +5638,11 @@ ObjCPropertyDecl *PD = Prop->getPropertyDecl(); if (!PD) continue; - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl()) InstanceMethods.push_back(Getter); if (PD->isReadOnly()) continue; - if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) + if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl()) InstanceMethods.push_back(Setter); } RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(), Index: clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp =================================================================== --- clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -909,9 +909,9 @@ static bool mustSynthesizeSetterGetterMethod(ObjCImplementationDecl *IMP, ObjCPropertyDecl *PD, bool getter) { - return getter ? !IMP->getInstanceMethod(PD->getGetterName()) - : !IMP->getInstanceMethod(PD->getSetterName()); - + auto *OMD = IMP->getInstanceMethod(getter ? PD->getGetterName() + : PD->getSetterName()); + return !OMD || !OMD->getBody(); } void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, @@ -953,7 +953,7 @@ "id objc_getProperty(id, SEL, long, bool);\n"; } RewriteObjCMethodDecl(OID->getContainingInterface(), - PD->getGetterMethodDecl(), Getr); + PID->getGetterMethodDecl(), Getr); Getr += "{ "; // Synthesize an explicit cast to gain access to the ivar. // See objc-act.c:objc_synthesize_new_getter() for details. @@ -961,7 +961,7 @@ // return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1) Getr += "typedef "; const FunctionType *FPRetType = nullptr; - RewriteTypeIntoString(PD->getGetterMethodDecl()->getReturnType(), Getr, + RewriteTypeIntoString(PID->getGetterMethodDecl()->getReturnType(), Getr, FPRetType); Getr += " _TYPE"; if (FPRetType) { @@ -1013,7 +1013,7 @@ } RewriteObjCMethodDecl(OID->getContainingInterface(), - PD->getSetterMethodDecl(), Setr); + PID->getSetterMethodDecl(), Setr); Setr += "{ "; // Synthesize an explicit cast to initialize the ivar. // See objc-act.c:objc_synthesize_new_setter() for details. @@ -1346,6 +1346,8 @@ InsertText(CID->getBeginLoc(), "// "); for (auto *OMD : IMD ? IMD->instance_methods() : CID->instance_methods()) { + if (!OMD->getBody()) + continue; std::string ResultStr; RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); SourceLocation LocStart = OMD->getBeginLoc(); @@ -1357,6 +1359,8 @@ } for (auto *OMD : IMD ? IMD->class_methods() : CID->class_methods()) { + if (!OMD->getBody()) + continue; std::string ResultStr; RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); SourceLocation LocStart = OMD->getBeginLoc(); @@ -7032,12 +7036,12 @@ ObjCPropertyDecl *PD = Prop->getPropertyDecl(); if (!PD) continue; - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl()) if (mustSynthesizeSetterGetterMethod(IDecl, PD, true /*getter*/)) InstanceMethods.push_back(Getter); if (PD->isReadOnly()) continue; - if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) + if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl()) if (mustSynthesizeSetterGetterMethod(IDecl, PD, false /*setter*/)) InstanceMethods.push_back(Setter); } @@ -7282,11 +7286,11 @@ ObjCPropertyDecl *PD = Prop->getPropertyDecl(); if (!PD) continue; - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl()) InstanceMethods.push_back(Getter); if (PD->isReadOnly()) continue; - if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) + if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl()) InstanceMethods.push_back(Setter); } Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -5052,11 +5052,12 @@ // we want, that just indicates if the decl came from a // property. What we want to know is if the method is defined in // this implementation. - if (!D->getInstanceMethod(PD->getGetterName())) + auto *Getter = D->getInstanceMethod(PD->getGetterName()); + if (!Getter || !Getter->getBody()) CodeGenFunction(*this).GenerateObjCGetter( - const_cast<ObjCImplementationDecl *>(D), PID); - if (!PD->isReadOnly() && - !D->getInstanceMethod(PD->getSetterName())) + const_cast<ObjCImplementationDecl *>(D), PID); + auto *Setter = D->getInstanceMethod(PD->getSetterName()); + if (!PD->isReadOnly() && (!Setter || !Setter->getBody())) CodeGenFunction(*this).GenerateObjCSetter( const_cast<ObjCImplementationDecl *>(D), PID); } Index: clang/lib/CodeGen/CodeGenFunction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenFunction.cpp +++ clang/lib/CodeGen/CodeGenFunction.cpp @@ -635,8 +635,7 @@ return CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM); } -void CodeGenFunction::StartFunction(GlobalDecl GD, - QualType RetTy, +void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, llvm::Function *Fn, const CGFunctionInfo &FnInfo, const FunctionArgList &Args, Index: clang/lib/CodeGen/CGObjCMac.cpp =================================================================== --- clang/lib/CodeGen/CGObjCMac.cpp +++ clang/lib/CodeGen/CGObjCMac.cpp @@ -3561,12 +3561,10 @@ for (const auto *PID : ID->property_impls()) { if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) { - ObjCPropertyDecl *PD = PID->getPropertyDecl(); - - if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) + if (ObjCMethodDecl *MD = PID->getGetterMethodDecl()) if (GetMethodDefinition(MD)) Methods[InstanceMethods].push_back(MD); - if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) + if (ObjCMethodDecl *MD = PID->getSetterMethodDecl()) if (GetMethodDefinition(MD)) Methods[InstanceMethods].push_back(MD); } @@ -6233,19 +6231,6 @@ } else { for (const auto *MD : ID->instance_methods()) methods.push_back(MD); - - for (const auto *PID : ID->property_impls()) { - if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize){ - ObjCPropertyDecl *PD = PID->getPropertyDecl(); - - if (auto MD = PD->getGetterMethodDecl()) - if (GetMethodDefinition(MD)) - methods.push_back(MD); - if (auto MD = PD->getSetterMethodDecl()) - if (GetMethodDefinition(MD)) - methods.push_back(MD); - } - } } values.add(emitMethodList(ID->getObjCRuntimeNameAsString(), @@ -6708,9 +6693,8 @@ // method_count values.addInt(ObjCTypes.IntTy, methods.size()); auto methodArray = values.beginArray(ObjCTypes.MethodTy); - for (auto MD : methods) { + for (auto MD : methods) emitMethodConstant(methodArray, MD, forProtocol); - } methodArray.finishAndAddTo(values); llvm::GlobalVariable *GV = finishAndCreateGlobal(values, prefix + name, CGM); Index: clang/lib/CodeGen/CGObjCGNU.cpp =================================================================== --- clang/lib/CodeGen/CGObjCGNU.cpp +++ clang/lib/CodeGen/CGObjCGNU.cpp @@ -1879,13 +1879,12 @@ for (auto *propImpl : OID->property_impls()) if (propImpl->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) { - ObjCPropertyDecl *prop = propImpl->getPropertyDecl(); auto addIfExists = [&](const ObjCMethodDecl* OMD) { if (OMD) InstanceMethods.push_back(OMD); }; - addIfExists(prop->getGetterMethodDecl()); - addIfExists(prop->getSetterMethodDecl()); + addIfExists(propImpl->getGetterMethodDecl()); + addIfExists(propImpl->getSetterMethodDecl()); } if (InstanceMethods.size() == 0) @@ -3493,13 +3492,12 @@ for (auto *propertyImpl : OID->property_impls()) if (propertyImpl->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) { - ObjCPropertyDecl *property = propertyImpl->getPropertyDecl(); auto addPropertyMethod = [&](const ObjCMethodDecl *accessor) { if (accessor) InstanceMethods.push_back(accessor); }; - addPropertyMethod(property->getGetterMethodDecl()); - addPropertyMethod(property->getSetterMethodDecl()); + addPropertyMethod(propertyImpl->getGetterMethodDecl()); + addPropertyMethod(propertyImpl->getSetterMethodDecl()); } llvm::Constant *Properties = GeneratePropertyList(OID, ClassDecl); Index: clang/lib/CodeGen/CGObjC.cpp =================================================================== --- clang/lib/CodeGen/CGObjC.cpp +++ clang/lib/CodeGen/CGObjC.cpp @@ -954,8 +954,7 @@ const ObjCPropertyImplDecl *PID) { llvm::Constant *AtomicHelperFn = CodeGenFunction(CGM).GenerateObjCAtomicGetterCopyHelperFunction(PID); - const ObjCPropertyDecl *PD = PID->getPropertyDecl(); - ObjCMethodDecl *OMD = PD->getGetterMethodDecl(); + ObjCMethodDecl *OMD = PID->getGetterMethodDecl(); assert(OMD && "Invalid call to generate getter (empty method)"); StartObjCMethod(OMD, IMP->getClassInterface()); @@ -1041,7 +1040,7 @@ const ObjCPropertyDecl *prop = propImpl->getPropertyDecl(); QualType propType = prop->getType(); - ObjCMethodDecl *getterMethod = prop->getGetterMethodDecl(); + ObjCMethodDecl *getterMethod = propImpl->getGetterMethodDecl(); ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl(); @@ -1311,9 +1310,8 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl, const ObjCPropertyImplDecl *propImpl, llvm::Constant *AtomicHelperFn) { - const ObjCPropertyDecl *prop = propImpl->getPropertyDecl(); ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl(); - ObjCMethodDecl *setterMethod = prop->getSetterMethodDecl(); + ObjCMethodDecl *setterMethod = propImpl->getSetterMethodDecl(); // Just use the setter expression if Sema gave us one and it's // non-trivial. @@ -1490,8 +1488,7 @@ const ObjCPropertyImplDecl *PID) { llvm::Constant *AtomicHelperFn = CodeGenFunction(CGM).GenerateObjCAtomicSetterCopyHelperFunction(PID); - const ObjCPropertyDecl *PD = PID->getPropertyDecl(); - ObjCMethodDecl *OMD = PD->getSetterMethodDecl(); + ObjCMethodDecl *OMD = PID->getSetterMethodDecl(); assert(OMD && "Invalid call to generate setter (empty method)"); StartObjCMethod(OMD, IMP->getClassInterface()); Index: clang/lib/Analysis/BodyFarm.cpp =================================================================== --- clang/lib/Analysis/BodyFarm.cpp +++ clang/lib/Analysis/BodyFarm.cpp @@ -809,15 +809,6 @@ if (!D->isImplicit()) return nullptr; - Optional<Stmt *> &Val = Bodies[D]; - if (Val.hasValue()) - return Val.getValue(); - Val = nullptr; - - const ObjCPropertyDecl *Prop = D->findPropertyDecl(); - if (!Prop) - return nullptr; - // For now, we only synthesize getters. // Synthesizing setters would cause false negatives in the // RetainCountChecker because the method body would bind the parameter @@ -830,6 +821,27 @@ if (D->param_size() != 0) return nullptr; + const ObjCPropertyDecl *Prop = D->findPropertyDecl(); + if (!Prop) + return nullptr; + + D = Prop->getGetterMethodDecl(); + + // 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; + } + + Optional<Stmt *> &Val = Bodies[D]; + if (Val.hasValue()) + return Val.getValue(); + Val = nullptr; + Val = createObjCPropertyGetter(C, Prop); return Val.getValue(); Index: clang/lib/AST/DeclObjC.cpp =================================================================== --- clang/lib/AST/DeclObjC.cpp +++ clang/lib/AST/DeclObjC.cpp @@ -1285,10 +1285,9 @@ SmallVectorImpl<const ObjCMethodDecl *> &Overridden) const { const ObjCMethodDecl *Method = this; - if (Method->isRedeclaration()) { + if (Method->isRedeclaration()) Method = cast<ObjCContainerDecl>(Method->getDeclContext())-> getMethod(Method->getSelector(), Method->isInstanceMethod()); - } if (Method->isOverriding()) { collectOverriddenMethodsSlow(Method, Overridden); @@ -1306,6 +1305,7 @@ if (isPropertyAccessor()) { const auto *Container = cast<ObjCContainerDecl>(getParent()); + bool IsGetter = (NumArgs == 0); bool IsInstance = isInstanceMethod(); @@ -1358,6 +1358,28 @@ } } + assert(!getBody() && "expected an accessor stub"); + // Go back to the interface. + if (auto *ImplDecl = dyn_cast<ObjCImplDecl>(Container)) { + ClassDecl = ImplDecl->getClassInterface(); + if (const auto *Found = findMatchingProperty(ClassDecl)) + return Found; + for (const auto *Ext : ClassDecl->visible_extensions()) { + if (Ext == Container) + continue; + + if (const auto *Found = findMatchingProperty(Ext)) + return Found; + } + for (const auto *Cat : ClassDecl->known_categories()) { + if (Cat == Container) + continue; + + if (const auto *Found = findMatchingProperty(Cat)) + return Found; + } + } + llvm_unreachable("Marked as a property accessor but no property found!"); } Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -8504,6 +8504,27 @@ tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC = nullptr); +private: + struct SynthesizedObjCPropertyAccessor { + ObjCPropertyImplDecl *PropertyImpl; + ObjCMethodDecl *AccessorDecl; + SourceLocation AtLoc; + SourceLocation PropertyLoc; + bool IsSetter; + }; + + /// Helper to redeclare an accessor inside the implementation. + void RedeclarePropertyAccessor(ObjCImplementationDecl *Impl, + SynthesizedObjCPropertyAccessor Accessor); + + /// Synthesized property accessors are redeclared in the + /// implementation, but only if they haven't been overridden by an + /// explicit definition. + llvm::DenseMap<ObjCContainerDecl *, + std::vector<SynthesizedObjCPropertyAccessor>> + SynthesizedObjCPropertyAccessors; + +public: Decl *ActOnPropertyImplDecl(Scope *S, SourceLocation AtLoc, SourceLocation PropertyLoc, Index: clang/include/clang/AST/DeclObjC.h =================================================================== --- clang/include/clang/AST/DeclObjC.h +++ clang/include/clang/AST/DeclObjC.h @@ -2779,6 +2779,13 @@ /// Null for \@dynamic. Required for \@synthesize. ObjCIvarDecl *PropertyIvarDecl; + /// A redeclaration of the getter with this implementation's + /// interface as a decl context. + ObjCMethodDecl *GetterMethodDecl = nullptr; + /// A redeclaration of the setter with this implementation's + /// interface as a decl context. + ObjCMethodDecl *SetterMethodDecl = nullptr; + /// Null for \@dynamic. Non-null if property must be copy-constructed in /// getter. Expr *GetterCXXConstructor = nullptr; @@ -2845,6 +2852,12 @@ return IvarLoc.isValid() && IvarLoc != getLocation(); } + ObjCMethodDecl *getGetterMethodDecl() const { return GetterMethodDecl; } + void setGetterMethodDecl(ObjCMethodDecl *MD) { GetterMethodDecl = MD; } + + ObjCMethodDecl *getSetterMethodDecl() const { return SetterMethodDecl; } + void setSetterMethodDecl(ObjCMethodDecl *MD) { SetterMethodDecl = MD; } + Expr *getGetterCXXConstructor() const { return GetterCXXConstructor; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits