DrgnParser: store type of template param value

This commit is contained in:
Jake Hillion 2023-08-16 12:44:58 -07:00 committed by Jake Hillion
parent ca0c71fa40
commit a2f7462a5d
12 changed files with 74 additions and 67 deletions

View File

@ -282,8 +282,27 @@ void DrgnParser::enumerateTemplateParam(struct drgn_type* type,
drgn_type_template_parameter* tparams, drgn_type_template_parameter* tparams,
size_t i, size_t i,
std::vector<TemplateParam>& params) { std::vector<TemplateParam>& params) {
drgn_qualified_type tparamQualType;
struct drgn_error* err =
drgn_template_parameter_type(&tparams[i], &tparamQualType);
if (err) {
warnForDrgnError(
type,
"Error looking up template parameter type (" + std::to_string(i) + ")",
err);
return;
}
struct drgn_type* tparamType = tparamQualType.type;
QualifierSet qualifiers;
qualifiers[Qualifier::Const] =
(tparamQualType.qualifiers & DRGN_QUALIFIER_CONST);
auto& ttype = enumerateType(tparamType);
const drgn_object* obj = nullptr; const drgn_object* obj = nullptr;
if (auto* err = drgn_template_parameter_object(&tparams[i], &obj)) { if (err = drgn_template_parameter_object(&tparams[i], &obj); err != nullptr) {
warnForDrgnError(type, warnForDrgnError(type,
"Error looking up template parameter object (" + "Error looking up template parameter object (" +
std::to_string(i) + ")", std::to_string(i) + ")",
@ -291,26 +310,7 @@ void DrgnParser::enumerateTemplateParam(struct drgn_type* type,
return; return;
} }
struct drgn_qualified_type tparamQualType;
if (obj == nullptr) { if (obj == nullptr) {
// This template parameter is a typename
struct drgn_error* err =
drgn_template_parameter_type(&tparams[i], &tparamQualType);
if (err) {
warnForDrgnError(type,
"Error looking up template parameter type (" +
std::to_string(i) + ")",
err);
return;
}
struct drgn_type* tparamType = tparamQualType.type;
QualifierSet qualifiers;
qualifiers[Qualifier::Const] =
(tparamQualType.qualifiers & DRGN_QUALIFIER_CONST);
auto& ttype = enumerateType(tparamType);
params.emplace_back(ttype, qualifiers); params.emplace_back(ttype, qualifiers);
} else { } else {
// This template parameter is a value // This template parameter is a value
@ -319,7 +319,7 @@ void DrgnParser::enumerateTemplateParam(struct drgn_type* type,
if (drgn_type_kind(obj->type) == DRGN_TYPE_ENUM) { if (drgn_type_kind(obj->type) == DRGN_TYPE_ENUM) {
char* nameStr = nullptr; char* nameStr = nullptr;
size_t length = 0; size_t length = 0;
auto* err = drgn_type_fully_qualified_name(obj->type, &nameStr, &length); err = drgn_type_fully_qualified_name(obj->type, &nameStr, &length);
if (err != nullptr || nameStr == nullptr) { if (err != nullptr || nameStr == nullptr) {
throw DrgnParserError{"Failed to get enum's fully qualified name", err}; throw DrgnParserError{"Failed to get enum's fully qualified name", err};
} }
@ -383,7 +383,7 @@ void DrgnParser::enumerateTemplateParam(struct drgn_type* type,
} }
} }
params.emplace_back(std::move(value)); params.emplace_back(ttype, std::move(value));
} }
} }

View File

@ -100,13 +100,13 @@ void fixAllocatorParams(Class& alloc) {
return; return;
} }
Type* allocParam = parentClass->templateParams[0].type(); if (parentClass->templateParams[0].value) {
if (!allocParam) {
// Nothing we can do // Nothing we can do
return; return;
} }
Type& typeToAllocate = stripTypedefs(*allocParam); Type& allocParam = parentClass->templateParams[0].type();
Type& typeToAllocate = stripTypedefs(allocParam);
alloc.templateParams.push_back(TemplateParam{typeToAllocate}); alloc.templateParams.push_back(TemplateParam{typeToAllocate});
} }
} // namespace } // namespace

View File

@ -113,7 +113,7 @@ void NameGen::visit(Container& c) {
if (param.value) { if (param.value) {
name += *param.value; name += *param.value;
} else { } else {
name += param.type()->name(); name += param.type().name();
// The "const" keyword must come after the type name so that pointers are // The "const" keyword must come after the type name so that pointers are
// handled correctly. // handled correctly.
// //

View File

@ -162,9 +162,8 @@ void Printer::print_param(const TemplateParam& param) {
out_ << "Param" << std::endl; out_ << "Param" << std::endl;
if (param.value) { if (param.value) {
print_value(*param.value); print_value(*param.value);
} else {
print(*param.type());
} }
print(param.type());
print_qualifiers(param.qualifiers); print_qualifiers(param.qualifiers);
depth_--; depth_--;
} }

View File

@ -60,22 +60,22 @@ void TypeIdentifier::visit(Container& c) {
// TODO these two arrays could be looped over in sync for better performance // TODO these two arrays could be looped over in sync for better performance
for (size_t i = 0; i < c.templateParams.size(); i++) { for (size_t i = 0; i < c.templateParams.size(); i++) {
const auto& param = c.templateParams[i]; const auto& param = c.templateParams[i];
if (dynamic_cast<Dummy*>(param.type()) || if (dynamic_cast<Dummy*>(&param.type()) ||
dynamic_cast<DummyAllocator*>(param.type()) || dynamic_cast<DummyAllocator*>(&param.type()) ||
dynamic_cast<Container*>(param.type())) { dynamic_cast<Container*>(&param.type())) {
// In case the TypeIdentifier pass is run multiple times, we don't want to // In case the TypeIdentifier pass is run multiple times, we don't want to
// replace dummies again as the context of the original replacement has // replace dummies again as the context of the original replacement has
// been lost. // been lost.
continue; continue;
} }
if (Class* paramClass = dynamic_cast<Class*>(param.type())) { if (Class* paramClass = dynamic_cast<Class*>(&param.type())) {
bool replaced = false; bool replaced = false;
for (const auto& info : passThroughTypes_) { for (const auto& info : passThroughTypes_) {
if (std::regex_search(paramClass->fqName(), info.matcher)) { if (std::regex_search(paramClass->fqName(), info.matcher)) {
// Create dummy containers // Create dummy containers
auto& dummy = auto& dummy =
typeGraph_.makeType<Container>(info, param.type()->size()); typeGraph_.makeType<Container>(info, param.type().size());
dummy.templateParams = paramClass->templateParams; dummy.templateParams = paramClass->templateParams;
c.templateParams[i] = dummy; c.templateParams[i] = dummy;
replaced = true; replaced = true;
@ -89,22 +89,22 @@ void TypeIdentifier::visit(Container& c) {
if (std::find(stubParams.begin(), stubParams.end(), i) != if (std::find(stubParams.begin(), stubParams.end(), i) !=
stubParams.end()) { stubParams.end()) {
size_t size = param.type()->size(); size_t size = param.type().size();
if (size == 1) { if (size == 1) {
// Hack: when we get a reported size of 1 for these parameters, it // Hack: when we get a reported size of 1 for these parameters, it
// turns out that a size of 0 is actually expected. // turns out that a size of 0 is actually expected.
size = 0; size = 0;
} }
if (isAllocator(*param.type())) { if (isAllocator(param.type())) {
auto* allocator = auto* allocator = dynamic_cast<Class*>(
dynamic_cast<Class*>(param.type()); // TODO please don't do this... &param.type()); // TODO please don't do this...
Type& typeToAllocate = *allocator->templateParams.at(0).type(); Type& typeToAllocate = allocator->templateParams.at(0).type();
auto& dummy = typeGraph_.makeType<DummyAllocator>( auto& dummy = typeGraph_.makeType<DummyAllocator>(typeToAllocate, size,
typeToAllocate, size, param.type()->align()); param.type().align());
c.templateParams[i] = dummy; c.templateParams[i] = dummy;
} else { } else {
auto& dummy = typeGraph_.makeType<Dummy>(size, param.type()->align()); auto& dummy = typeGraph_.makeType<Dummy>(size, param.type().align());
c.templateParams[i] = dummy; c.templateParams[i] = dummy;
} }
} }

View File

@ -143,23 +143,23 @@ struct Parent {
uint64_t bitOffset; uint64_t bitOffset;
}; };
class TemplateParam { struct TemplateParam {
public:
// TODO make ctors explicit // TODO make ctors explicit
TemplateParam(Type& type) : type_(&type) { TemplateParam(Type& type) : type_(type) {
} }
TemplateParam(Type& type, QualifierSet qualifiers) TemplateParam(Type& type, QualifierSet qualifiers)
: type_(&type), qualifiers(qualifiers) { : type_(type), qualifiers(qualifiers) {
} }
TemplateParam(std::string value) : value(std::move(value)) { TemplateParam(Type& type, std::string value)
: type_(type), value(std::move(value)) {
} }
Type* type() const { Type& type() const {
return type_; return type_;
} }
private: private:
Type* type_ = nullptr; // Note: type is not set when this param holds a value std::reference_wrapper<Type> type_;
public: public:
QualifierSet qualifiers; QualifierSet qualifiers;

View File

@ -314,22 +314,19 @@ void TypeGraphParser::parseParams(T& c,
if (!tryRemovePrefix(line, "Param")) if (!tryRemovePrefix(line, "Param"))
break; break;
if (auto value = tryParseStringValue(input, "Value: ", rootIndent + 2); auto value = tryParseStringValue(input, "Value: ", rootIndent + 2);
value) { Type& type = parseType(input, rootIndent + 2);
c.templateParams.emplace_back(std::string{*value}); TemplateParam param{type};
} else { if (value)
Type& type = parseType(input, rootIndent + 2); param.value = value;
TemplateParam param{type}; if (auto qualStr =
tryParseStringValue(input, "Qualifiers: ", rootIndent + 2);
if (auto qualStr = qualStr) {
tryParseStringValue(input, "Qualifiers: ", rootIndent + 2); Qualifier qual = getQualifier(*qualStr);
qualStr) { param.qualifiers[qual] = true;
Qualifier qual = getQualifier(*qualStr);
param.qualifiers[qual] = true;
}
c.templateParams.push_back(param);
} }
c.templateParams.push_back(param);
} }
// No more params for us - put back the line we just read // No more params for us - put back the line we just read
input = origInput; input = origInput;

View File

@ -450,6 +450,7 @@ TEST_F(DrgnParserTest, ClassTemplateValue) {
[0] Struct: TemplatedClassVal<3> (size: 12) [0] Struct: TemplatedClassVal<3> (size: 12)
Param Param
Value: 3 Value: 3
Primitive: int32_t
Member: arr (offset: 0) Member: arr (offset: 0)
[1] Array: (length: 3) [1] Array: (length: 3)
Primitive: int32_t Primitive: int32_t
@ -463,12 +464,14 @@ TEST_F(DrgnParserTest, TemplateEnumValue) {
[0] Class: MyClass<ns_enums_params::MyNS::ScopedEnum::One> (size: 4) [0] Class: MyClass<ns_enums_params::MyNS::ScopedEnum::One> (size: 4)
Param Param
Value: ns_enums_params::MyNS::ScopedEnum::One Value: ns_enums_params::MyNS::ScopedEnum::One
Enum: ScopedEnum (size: 4)
)", )",
R"( R"(
[1] Pointer [1] Pointer
[0] Class: MyClass<(ns_enums_params::MyNS::ScopedEnum)1> (size: 4) [0] Class: MyClass<(ns_enums_params::MyNS::ScopedEnum)1> (size: 4)
Param Param
Value: ns_enums_params::MyNS::ScopedEnum::One Value: ns_enums_params::MyNS::ScopedEnum::One
Enum: ScopedEnum (size: 4)
)"); )");
} }
@ -479,12 +482,14 @@ TEST_F(DrgnParserTest, TemplateEnumValueGaps) {
[0] Class: ClassGaps<ns_enums_params::MyNS::EnumWithGaps::Twenty> (size: 4) [0] Class: ClassGaps<ns_enums_params::MyNS::EnumWithGaps::Twenty> (size: 4)
Param Param
Value: ns_enums_params::MyNS::EnumWithGaps::Twenty Value: ns_enums_params::MyNS::EnumWithGaps::Twenty
Enum: EnumWithGaps (size: 4)
)", )",
R"( R"(
[1] Pointer [1] Pointer
[0] Class: ClassGaps<(ns_enums_params::MyNS::EnumWithGaps)20> (size: 4) [0] Class: ClassGaps<(ns_enums_params::MyNS::EnumWithGaps)20> (size: 4)
Param Param
Value: ns_enums_params::MyNS::EnumWithGaps::Twenty Value: ns_enums_params::MyNS::EnumWithGaps::Twenty
Enum: EnumWithGaps (size: 4)
)"); )");
} }
@ -495,12 +500,14 @@ TEST_F(DrgnParserTest, TemplateEnumValueNegative) {
[0] Class: ClassGaps<ns_enums_params::MyNS::EnumWithGaps::MinusTwo> (size: 4) [0] Class: ClassGaps<ns_enums_params::MyNS::EnumWithGaps::MinusTwo> (size: 4)
Param Param
Value: ns_enums_params::MyNS::EnumWithGaps::MinusTwo Value: ns_enums_params::MyNS::EnumWithGaps::MinusTwo
Enum: EnumWithGaps (size: 4)
)", )",
R"( R"(
[1] Pointer [1] Pointer
[0] Class: ClassGaps<(ns_enums_params::MyNS::EnumWithGaps)-2> (size: 4) [0] Class: ClassGaps<(ns_enums_params::MyNS::EnumWithGaps)-2> (size: 4)
Param Param
Value: ns_enums_params::MyNS::EnumWithGaps::MinusTwo Value: ns_enums_params::MyNS::EnumWithGaps::MinusTwo
Enum: EnumWithGaps (size: 4)
)"); )");
} }

View File

@ -914,6 +914,7 @@ TEST(FlattenerTest, AllocatorUnfixableParentParamIsValue) {
[2] Struct: MyAllocBase (size: 1) [2] Struct: MyAllocBase (size: 1)
Param Param
Value: 123 Value: 123
Primitive: int32_t
Function: allocate Function: allocate
Function: deallocate Function: deallocate
Function: allocate Function: allocate

View File

@ -205,14 +205,15 @@ TEST(NameGenTest, ContainerParamsValue) {
auto myenum = Enum{"MyEnum", 4}; auto myenum = Enum{"MyEnum", 4};
auto mycontainer = getVector(); auto mycontainer = getVector();
mycontainer.templateParams.push_back(TemplateParam{"123"}); mycontainer.templateParams.push_back(TemplateParam{myint, "123"});
mycontainer.templateParams.push_back(TemplateParam{"MyEnum::OptionC"}); mycontainer.templateParams.push_back(
TemplateParam{myenum, "MyEnum::OptionC"});
NameGen nameGen; NameGen nameGen;
nameGen.generateNames({mycontainer}); nameGen.generateNames({mycontainer});
EXPECT_EQ(myint.name(), "int32_t"); EXPECT_EQ(myint.name(), "int32_t");
EXPECT_EQ(myenum.name(), "MyEnum"); EXPECT_EQ(myenum.name(), "MyEnum_0");
EXPECT_EQ(mycontainer.name(), "std::vector<123, MyEnum::OptionC>"); EXPECT_EQ(mycontainer.name(), "std::vector<123, MyEnum::OptionC>");
} }

View File

@ -12,6 +12,7 @@ TEST(PruneTest, PruneClass) {
Primitive: int32_t Primitive: int32_t
Param Param
Value: "123" Value: "123"
Primitive: int32_t
Parent (offset: 0) Parent (offset: 0)
[1] Class: MyParent (size: 4) [1] Class: MyParent (size: 4)
Member: a (offset: 0) Member: a (offset: 0)

View File

@ -94,7 +94,8 @@ MyClass
TEST(TopoSorterTest, TemplateParamValue) { TEST(TopoSorterTest, TemplateParamValue) {
auto myclass = Class{1, Class::Kind::Class, "MyClass", 69}; auto myclass = Class{1, Class::Kind::Class, "MyClass", 69};
myclass.templateParams.push_back(TemplateParam{"123"}); auto myint = Primitive{Primitive::Kind::Int32};
myclass.templateParams.push_back(TemplateParam{myint, "123"});
test({myclass}, R"( test({myclass}, R"(
MyClass MyClass