forked from OSchip/llvm-project
Fix debug info for Objective-C properties from class extensions after r251874
After r251874, properties from class extensions no longer show up in ObjCInterfaceDecl::properties(). Make debug info emission explicitly look for properties in class extensions before looking at direct properties. Also add a test that checks for this. There are three interesting cases: 1. A property is only declared in a class extension, and the @implementation is in a different file. This used to generated a DIObjcProperty before r251874 and does again with this fix. 2. A property is declared as readonly in the class itself and redeclared as readwrite in a class extension. clang before r251874 put the DIObjcProperty on the first declaration. clang after r251874 didn't emit any DIObjcProperty, and clang with this fix puts it on the readwrite redeclaration (which is what lookup finds). This seems like a progression. 3. Like 2, but with an @implementation in the same file. In this case, the property debug info gets generated a second time through the ivar from the definition. In this case, lookup and declaration code need to agree on the line number so that the DIObjcProperty isn't emitted twice. In this case, clang before r251874 emitted one DIObjcProperty on the first declaration, clang with r251874 emitted one on the second declaration, and clang with this patch still does the latter. llvm-svn: 254750
This commit is contained in:
parent
fdc4b313d7
commit
7123bca7fb
|
@ -1791,7 +1791,7 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty,
|
|||
}
|
||||
|
||||
// Create entries for all of the properties.
|
||||
for (const auto *PD : ID->properties()) {
|
||||
auto AddProperty = [&](const ObjCPropertyDecl *PD) {
|
||||
SourceLocation Loc = PD->getLocation();
|
||||
llvm::DIFile *PUnit = getOrCreateFile(Loc);
|
||||
unsigned PLine = getLineNumber(Loc);
|
||||
|
@ -1805,6 +1805,21 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty,
|
|||
: getSelectorName(PD->getSetterName()),
|
||||
PD->getPropertyAttributes(), getOrCreateType(PD->getType(), PUnit));
|
||||
EltTys.push_back(PropertyNode);
|
||||
};
|
||||
{
|
||||
llvm::SmallPtrSet<const IdentifierInfo*, 16> PropertySet;
|
||||
//for (const ObjCCategoryDecl *ClassExt : ID->known_extensions())
|
||||
// for (auto *PD : ClassExt->properties()) {
|
||||
// PropertySet.insert(PD->getIdentifier());
|
||||
// AddProperty(PD);
|
||||
// }
|
||||
for (const auto *PD : ID->properties()) {
|
||||
// Don't emit duplicate metadata for properties that were already in a
|
||||
// class extension.
|
||||
if (!PropertySet.insert(PD->getIdentifier()).second)
|
||||
continue;
|
||||
AddProperty(PD);
|
||||
}
|
||||
}
|
||||
|
||||
const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(ID);
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
// RUN: %clang_cc1 -S -emit-llvm -debug-info-kind=limited %s -o - | FileCheck %s
|
||||
|
||||
// Checks debug info for properties from class extensions for a few cases.
|
||||
|
||||
|
||||
// Readonly property in interface made readwrite in a category, with @impl
|
||||
// The interesting bit is that when the ivar debug info is generated, the corresponding
|
||||
// property is looked up and also gets debug info. If the debug info from the interface's
|
||||
// declaration and from the ivar doesn't match, this will end up with two DIObjCProperty
|
||||
// entries which would be bad.
|
||||
@interface FooROWithImpl
|
||||
// CHECK-NOT: !DIObjCProperty(name: "evolvingpropwithimpl"{{.*}}line: [[@LINE+1]]
|
||||
@property (readonly) int evolvingpropwithimpl;
|
||||
@end
|
||||
@interface FooROWithImpl ()
|
||||
// CHECK: !DIObjCProperty(name: "evolvingpropwithimpl"{{.*}}line: [[@LINE+1]]
|
||||
@property int evolvingpropwithimpl;
|
||||
@end
|
||||
@implementation FooROWithImpl
|
||||
@synthesize evolvingpropwithimpl = _evolvingpropwithimpl;
|
||||
@end
|
||||
|
||||
|
||||
// Simple property from a class extension:
|
||||
@interface Foo
|
||||
@end
|
||||
@interface Foo()
|
||||
// CHECK: !DIObjCProperty(name: "myprop"{{.*}}line: [[@LINE+1]]
|
||||
@property int myprop;
|
||||
@end
|
||||
// There's intentionally no @implementation for Foo, because that would
|
||||
// generate debug info for the property via the backing ivar.
|
||||
|
||||
|
||||
// Readonly property in interface made readwrite in a category:
|
||||
@interface FooRO
|
||||
// Shouldn't be here but in the class extension below.
|
||||
// CHECK-NOT: !DIObjCProperty(name: "evolvingprop"{{.*}}line: [[@LINE+1]]
|
||||
@property (readonly) int evolvingprop;
|
||||
@end
|
||||
@interface FooRO ()
|
||||
// CHECK: !DIObjCProperty(name: "evolvingprop"{{.*}}line: [[@LINE+1]]
|
||||
@property int evolvingprop;
|
||||
@end
|
||||
|
||||
|
||||
// This references types in this file to force emission of their debug info.
|
||||
void foo(Foo *f, FooRO *g, FooROWithImpl* h) { }
|
Loading…
Reference in New Issue