Printer: Use NodeIds for stable IDs when printing graphs

This removes Printer's legacy behaviour of generating an ID for each
node as it gets printed. This old method meant that if new nodes were
added to or removed from a graph, every ID after the new/removed node
would change.

Now IDs are stable so it is easier to follow specific nodes through
multiple transformation passes in CodeGen.
This commit is contained in:
Alastair Robertson 2023-08-02 03:11:52 -07:00 committed by Alastair Robertson
parent dca99fc4ad
commit ff31971bd3
13 changed files with 155 additions and 203 deletions

View File

@ -42,7 +42,7 @@ void print(const TypeGraph& typeGraph) {
return;
std::stringstream out;
Printer printer{out, typeGraph.size()};
Printer printer{out, typeGraph.resetTracker(), typeGraph.size()};
for (const auto& type : typeGraph.rootTypes()) {
printer.print(type);
}

View File

@ -19,7 +19,8 @@
namespace oi::detail::type_graph {
Printer::Printer(std::ostream& out, size_t numTypes) : out_(out) {
Printer::Printer(std::ostream& out, NodeTracker& tracker, size_t numTypes)
: tracker_(tracker), out_(out) {
if (numTypes == 0) {
baseIndent_ = 0;
return;
@ -139,19 +140,16 @@ bool Printer::prefix(const Type* type) {
int indent = baseIndent_ + depth_ * 2;
if (type) {
if (auto it = nodeNums_.find(type); it != nodeNums_.end()) {
if (tracker_.visit(*type)) {
// Node has already been printed - print a reference to it this time
out_ << std::string(indent, ' ');
int nodeNum = it->second;
out_ << "[" << nodeNum << "]" << std::endl;
out_ << "[" << type->id() << "]" << std::endl;
return true;
}
int nodeNum = nextNodeNum_++;
std::string nodeId = "[" + std::to_string(nodeNum) + "]";
std::string nodeId = "[" + std::to_string(type->id()) + "]";
out_ << nodeId;
indent -= nodeId.size();
nodeNums_.insert({type, nodeNum});
}
out_ << std::string(indent, ' ');

View File

@ -16,8 +16,8 @@
#pragma once
#include <ostream>
#include <unordered_map>
#include "NodeTracker.h"
#include "Types.h"
#include "Visitor.h"
@ -28,7 +28,7 @@ namespace oi::detail::type_graph {
*/
class Printer : public ConstVisitor {
public:
Printer(std::ostream& out, size_t numTypes);
Printer(std::ostream& out, NodeTracker& tracker, size_t numTypes);
void print(const Type& type);
@ -53,11 +53,10 @@ class Printer : public ConstVisitor {
void print_qualifiers(const QualifierSet& qualifiers);
static std::string align_str(uint64_t align);
NodeTracker& tracker_;
std::ostream& out_;
int baseIndent_;
int depth_ = -1;
int nextNodeNum_ = 0;
std::unordered_map<const Type*, int> nodeNums_;
};
} // namespace oi::detail::type_graph

View File

@ -17,7 +17,7 @@
namespace oi::detail::type_graph {
NodeTracker& TypeGraph::resetTracker() noexcept {
NodeTracker& TypeGraph::resetTracker() const noexcept {
tracker_.reset();
tracker_.resize(size());
return tracker_;

View File

@ -48,7 +48,7 @@ class TypeGraph {
rootTypes_.push_back(type);
}
NodeTracker& resetTracker() noexcept;
NodeTracker& resetTracker() const noexcept;
// Override of the generic makeType function that returns singleton Primitive
// objects
@ -58,6 +58,7 @@ class TypeGraph {
template <typename T, typename... Args>
T& makeType(NodeId id, Args&&... args) {
static_assert(T::has_node_id, "Unnecessary node ID provided");
next_id_ = std::max(next_id_, id + 1);
auto type_unique_ptr = std::make_unique<T>(id, std::forward<Args>(args)...);
auto type_raw_ptr = type_unique_ptr.get();
types_.push_back(std::move(type_unique_ptr));
@ -87,7 +88,7 @@ class TypeGraph {
std::vector<std::reference_wrapper<Type>> rootTypes_;
// Store all type objects in vectors for ownership. Order is not significant.
std::vector<std::unique_ptr<Type>> types_;
NodeTracker tracker_;
mutable NodeTracker tracker_;
NodeId next_id_ = 0;
};

View File

@ -26,7 +26,7 @@ std::string AddChildrenTest::run(std::string_view function,
pass.run(typeGraph);
std::stringstream out;
Printer printer{out, typeGraph.size()};
Printer printer{out, typeGraph.resetTracker(), typeGraph.size()};
printer.print(type);
return out.str();
@ -35,8 +35,8 @@ std::string AddChildrenTest::run(std::string_view function,
TEST_F(AddChildrenTest, SimpleStruct) {
// Should do nothing
test("oid_test_case_simple_struct", R"(
[0] Pointer
[1] Struct: SimpleStruct (size: 16)
[1] Pointer
[0] Struct: SimpleStruct (size: 16)
Member: a (offset: 0)
Primitive: int32_t
Member: b (offset: 4)
@ -49,10 +49,10 @@ TEST_F(AddChildrenTest, SimpleStruct) {
TEST_F(AddChildrenTest, InheritanceStatic) {
// Should do nothing
test("oid_test_case_inheritance_access_public", R"(
[0] Pointer
[1] Class: Public (size: 8)
[2] Pointer
[0] Class: Public (size: 8)
Parent (offset: 0)
[2] Class: Base (size: 4)
[1] Class: Base (size: 4)
Member: base_int (offset: 0)
Primitive: int32_t
Member: public_int (offset: 4)
@ -62,8 +62,8 @@ TEST_F(AddChildrenTest, InheritanceStatic) {
TEST_F(AddChildrenTest, InheritancePolymorphic) {
testMultiCompiler("oid_test_case_inheritance_polymorphic_a_as_a", R"(
[0] Pointer
[1] Class: A (size: 16)
[1] Pointer
[0] Class: A (size: 16)
Member: _vptr$A (offset: 0)
Primitive: uintptr_t
Member: int_a (offset: 8)
@ -73,19 +73,19 @@ TEST_F(AddChildrenTest, InheritancePolymorphic) {
Function: A
Function: A
Child
[2] Class: B (size: 40)
[8] Class: B (size: 40)
Parent (offset: 0)
[1]
[0]
Member: vec_b (offset: 16)
[3] Container: std::vector (size: 24)
[4] Container: std::vector (size: 24)
Param
Primitive: int32_t
Param
[4] Class: allocator<int> (size: 1)
[5] Class: allocator<int> (size: 1)
Param
Primitive: int32_t
Parent (offset: 0)
[5] Typedef: __allocator_base<int>
[7] Typedef: __allocator_base<int>
[6] Class: new_allocator<int> (size: 1)
Param
Primitive: int32_t
@ -105,9 +105,9 @@ TEST_F(AddChildrenTest, InheritancePolymorphic) {
Function: B
Function: B
Child
[7] Class: C (size: 48)
[10] Class: C (size: 48)
Parent (offset: 0)
[2]
[8]
Member: int_c (offset: 40)
Primitive: int32_t
Function: ~C (virtual)
@ -116,8 +116,8 @@ TEST_F(AddChildrenTest, InheritancePolymorphic) {
Function: C
)",
R"(
[0] Pointer
[1] Class: A (size: 16)
[1] Pointer
[0] Class: A (size: 16)
Member: _vptr.A (offset: 0)
Primitive: uintptr_t
Member: int_a (offset: 8)
@ -128,17 +128,17 @@ TEST_F(AddChildrenTest, InheritancePolymorphic) {
Function: ~A (virtual)
Function: myfunc (virtual)
Child
[2] Class: B (size: 40)
[7] Class: B (size: 40)
Parent (offset: 0)
[1]
[0]
Member: vec_b (offset: 16)
[3] Container: std::vector (size: 24)
[4] Container: std::vector (size: 24)
Param
Primitive: int32_t
Param
[4] Class: allocator<int> (size: 1)
[5] Class: allocator<int> (size: 1)
Parent (offset: 0)
[5] Class: new_allocator<int> (size: 1)
[6] Class: new_allocator<int> (size: 1)
Param
Primitive: int32_t
Function: new_allocator
@ -158,9 +158,9 @@ TEST_F(AddChildrenTest, InheritancePolymorphic) {
Function: ~B (virtual)
Function: myfunc (virtual)
Child
[6] Class: C (size: 48)
[9] Class: C (size: 48)
Parent (offset: 0)
[2]
[7]
Member: int_c (offset: 40)
Primitive: int32_t
Function: operator=

View File

@ -8,7 +8,6 @@
#include "TypeGraphParser.h"
#include "mocks.h"
#include "oi/CodeGen.h"
#include "oi/type_graph/Printer.h"
#include "oi/type_graph/TypeGraph.h"
#include "oi/type_graph/Types.h"
#include "type_graph_utils.h"
@ -32,13 +31,13 @@ void testTransform(OICodeGen::Config& config,
}
// Validate input formatting
check(typeGraph.rootTypes(), input, "parsing input graph");
check(typeGraph, input, "parsing input graph");
MockSymbolService symbols;
CodeGen codegen{config, symbols};
codegen.transform(typeGraph);
check(typeGraph.rootTypes(), expectedAfter, "after transform");
check(typeGraph, expectedAfter, "after transform");
}
void testTransform(std::string_view input, std::string_view expectedAfter) {
@ -100,7 +99,7 @@ TEST(CodeGenTest, TransformContainerAllocatorParamInParent) {
Primitive: int32_t
Param
DummyAllocator (size: 0)
[1] Container: std::pair<int32_t const, int32_t> (size: 8)
[3] Container: std::pair<int32_t const, int32_t> (size: 8)
Param
Primitive: int32_t
Qualifiers: const

View File

@ -55,7 +55,7 @@ std::string DrgnParserTest::run(std::string_view function,
Type& type = drgnParser.parse(drgnRoot);
std::stringstream out;
Printer printer{out, typeGraph.size()};
Printer printer{out, typeGraph.resetTracker(), typeGraph.size()};
printer.print(type);
return out.str();
@ -105,8 +105,8 @@ void DrgnParserTest::testMultiCompilerContains(
TEST_F(DrgnParserTest, SimpleStruct) {
test("oid_test_case_simple_struct", R"(
[0] Pointer
[1] Struct: SimpleStruct (size: 16)
[1] Pointer
[0] Struct: SimpleStruct (size: 16)
Member: a (offset: 0)
Primitive: int32_t
Member: b (offset: 4)
@ -118,8 +118,8 @@ TEST_F(DrgnParserTest, SimpleStruct) {
TEST_F(DrgnParserTest, SimpleClass) {
test("oid_test_case_simple_class", R"(
[0] Pointer
[1] Class: SimpleClass (size: 16)
[1] Pointer
[0] Class: SimpleClass (size: 16)
Member: a (offset: 0)
Primitive: int32_t
Member: b (offset: 4)
@ -131,8 +131,8 @@ TEST_F(DrgnParserTest, SimpleClass) {
TEST_F(DrgnParserTest, SimpleUnion) {
test("oid_test_case_simple_union", R"(
[0] Pointer
[1] Union: SimpleUnion (size: 8)
[1] Pointer
[0] Union: SimpleUnion (size: 8)
Member: a (offset: 0)
Primitive: int32_t
Member: b (offset: 0)
@ -144,10 +144,10 @@ TEST_F(DrgnParserTest, SimpleUnion) {
TEST_F(DrgnParserTest, Inheritance) {
test("oid_test_case_inheritance_access_public", R"(
[0] Pointer
[1] Class: Public (size: 8)
[2] Pointer
[0] Class: Public (size: 8)
Parent (offset: 0)
[2] Class: Base (size: 4)
[1] Class: Base (size: 4)
Member: base_int (offset: 0)
Primitive: int32_t
Member: public_int (offset: 4)
@ -157,26 +157,26 @@ TEST_F(DrgnParserTest, Inheritance) {
TEST_F(DrgnParserTest, InheritanceMultiple) {
test("oid_test_case_inheritance_multiple_a", R"(
[0] Pointer
[1] Struct: Derived_2 (size: 24)
[6] Pointer
[0] Struct: Derived_2 (size: 24)
Parent (offset: 0)
[2] Struct: Base_1 (size: 4)
[1] Struct: Base_1 (size: 4)
Member: a (offset: 0)
Primitive: int32_t
Parent (offset: 4)
[3] Struct: Derived_1 (size: 12)
[2] Struct: Derived_1 (size: 12)
Parent (offset: 0)
[4] Struct: Base_2 (size: 4)
[3] Struct: Base_2 (size: 4)
Member: b (offset: 0)
Primitive: int32_t
Parent (offset: 4)
[5] Struct: Base_3 (size: 4)
[4] Struct: Base_3 (size: 4)
Member: c (offset: 0)
Primitive: int32_t
Member: d (offset: 8)
Primitive: int32_t
Parent (offset: 16)
[6] Struct: Base_4 (size: 4)
[5] Struct: Base_4 (size: 4)
Member: e (offset: 0)
Primitive: int32_t
Member: f (offset: 20)
@ -186,17 +186,17 @@ TEST_F(DrgnParserTest, InheritanceMultiple) {
TEST_F(DrgnParserTest, Container) {
testMultiCompiler("oid_test_case_std_vector_int_empty", R"(
[0] Pointer
[1] Container: std::vector (size: 24)
[4] Pointer
[0] Container: std::vector (size: 24)
Param
Primitive: int32_t
Param
[2] Class: allocator<int> (size: 1)
[1] Class: allocator<int> (size: 1)
Param
Primitive: int32_t
Parent (offset: 0)
[3] Typedef: __allocator_base<int>
[4] Class: new_allocator<int> (size: 1)
[2] Class: new_allocator<int> (size: 1)
Param
Primitive: int32_t
Function: new_allocator
@ -212,14 +212,14 @@ TEST_F(DrgnParserTest, Container) {
Function: deallocate
)",
R"(
[0] Pointer
[1] Container: std::vector (size: 24)
[3] Pointer
[0] Container: std::vector (size: 24)
Param
Primitive: int32_t
Param
[2] Class: allocator<int> (size: 1)
[1] Class: allocator<int> (size: 1)
Parent (offset: 0)
[3] Class: new_allocator<int> (size: 1)
[2] Class: new_allocator<int> (size: 1)
Param
Primitive: int32_t
Function: new_allocator
@ -257,36 +257,36 @@ TEST_F(DrgnParserTest, UnscopedEnum) {
TEST_F(DrgnParserTest, Typedef) {
test("oid_test_case_typedefs_c_style", R"(
[0] Typedef: TdUInt64
[2] Typedef: TdUInt64
[1] Typedef: uint64_t
[2] Typedef: __uint64_t
[0] Typedef: __uint64_t
Primitive: uint64_t
)");
}
TEST_F(DrgnParserTest, Using) {
test("oid_test_case_typedefs_using", R"(
[0] Typedef: UsingUInt64
[2] Typedef: UsingUInt64
[1] Typedef: uint64_t
[2] Typedef: __uint64_t
[0] Typedef: __uint64_t
Primitive: uint64_t
)");
}
TEST_F(DrgnParserTest, ArrayMember) {
test("oid_test_case_arrays_member_int10", R"(
[0] Pointer
[1] Struct: Foo10 (size: 40)
[2] Pointer
[0] Struct: Foo10 (size: 40)
Member: arr (offset: 0)
[2] Array: (length: 10)
[1] Array: (length: 10)
Primitive: int32_t
)");
}
TEST_F(DrgnParserTest, ArrayRef) {
test("oid_test_case_arrays_ref_int10", R"(
[0] Pointer
[1] Array: (length: 10)
[1] Pointer
[0] Array: (length: 10)
Primitive: int32_t
)");
}
@ -300,23 +300,23 @@ TEST_F(DrgnParserTest, ArrayDirect) {
TEST_F(DrgnParserTest, Pointer) {
test("oid_test_case_pointers_struct_primitive_ptrs", R"(
[0] Pointer
[1] Struct: PrimitivePtrs (size: 24)
[3] Pointer
[0] Struct: PrimitivePtrs (size: 24)
Member: a (offset: 0)
Primitive: int32_t
Member: b (offset: 8)
[2] Pointer
[1] Pointer
Primitive: int32_t
Member: c (offset: 16)
[3] Pointer
[2] Pointer
Primitive: void
)");
}
TEST_F(DrgnParserTest, PointerNoFollow) {
test("oid_test_case_pointers_struct_primitive_ptrs", R"(
[0] Pointer
[1] Struct: PrimitivePtrs (size: 24)
[1] Pointer
[0] Struct: PrimitivePtrs (size: 24)
Member: a (offset: 0)
Primitive: int32_t
Member: b (offset: 8)
@ -336,20 +336,20 @@ TEST_F(DrgnParserTest, PointerIncomplete) {
TEST_F(DrgnParserTest, Cycle) {
test("oid_test_case_cycles_raw_ptr", R"(
[0] Pointer
[1] Struct: RawNode (size: 16)
[2] Pointer
[0] Struct: RawNode (size: 16)
Member: value (offset: 0)
Primitive: int32_t
Member: next (offset: 8)
[2] Pointer
[1]
[1] Pointer
[0]
)");
}
TEST_F(DrgnParserTest, ClassTemplateInt) {
test("oid_test_case_templates_int", R"(
[0] Pointer
[1] Class: TemplatedClass1<int> (size: 4)
[1] Pointer
[0] Class: TemplatedClass1<int> (size: 4)
Param
Primitive: int32_t
Member: val (offset: 0)
@ -359,19 +359,19 @@ TEST_F(DrgnParserTest, ClassTemplateInt) {
TEST_F(DrgnParserTest, ClassTemplateVector) {
testMultiCompiler("oid_test_case_templates_vector", R"(
[0] Pointer
[1] Class: TemplatedClass1<std::vector<int, std::allocator<int> > > (size: 24)
[5] Pointer
[0] Class: TemplatedClass1<std::vector<int, std::allocator<int> > > (size: 24)
Param
[2] Container: std::vector (size: 24)
[1] Container: std::vector (size: 24)
Param
Primitive: int32_t
Param
[3] Class: allocator<int> (size: 1)
[2] Class: allocator<int> (size: 1)
Param
Primitive: int32_t
Parent (offset: 0)
[4] Typedef: __allocator_base<int>
[5] Class: new_allocator<int> (size: 1)
[3] Class: new_allocator<int> (size: 1)
Param
Primitive: int32_t
Function: new_allocator
@ -386,21 +386,21 @@ TEST_F(DrgnParserTest, ClassTemplateVector) {
Function: allocate
Function: deallocate
Member: val (offset: 0)
[2]
[1]
Function: ~TemplatedClass1
Function: TemplatedClass1
)",
R"(
[0] Pointer
[1] Class: TemplatedClass1<std::vector<int, std::allocator<int> > > (size: 24)
[4] Pointer
[0] Class: TemplatedClass1<std::vector<int, std::allocator<int> > > (size: 24)
Param
[2] Container: std::vector (size: 24)
[1] Container: std::vector (size: 24)
Param
Primitive: int32_t
Param
[3] Class: allocator<int> (size: 1)
[2] Class: allocator<int> (size: 1)
Parent (offset: 0)
[4] Class: new_allocator<int> (size: 1)
[3] Class: new_allocator<int> (size: 1)
Param
Primitive: int32_t
Function: new_allocator
@ -415,7 +415,7 @@ TEST_F(DrgnParserTest, ClassTemplateVector) {
Function: allocate
Function: deallocate
Member: val (offset: 0)
[2]
[1]
Function: TemplatedClass1
Function: ~TemplatedClass1
)");
@ -423,10 +423,10 @@ TEST_F(DrgnParserTest, ClassTemplateVector) {
TEST_F(DrgnParserTest, ClassTemplateTwo) {
test("oid_test_case_templates_two", R"(
[0] Pointer
[1] Class: TemplatedClass2<ns_templates::Foo, int> (size: 12)
[3] Pointer
[0] Class: TemplatedClass2<ns_templates::Foo, int> (size: 12)
Param
[2] Struct: Foo (size: 8)
[1] Struct: Foo (size: 8)
Member: a (offset: 0)
Primitive: int32_t
Member: b (offset: 4)
@ -434,11 +434,11 @@ TEST_F(DrgnParserTest, ClassTemplateTwo) {
Param
Primitive: int32_t
Member: tc1 (offset: 0)
[3] Class: TemplatedClass1<ns_templates::Foo> (size: 8)
[2] Class: TemplatedClass1<ns_templates::Foo> (size: 8)
Param
[2]
[1]
Member: val (offset: 0)
[2]
[1]
Member: val2 (offset: 8)
Primitive: int32_t
)");
@ -446,12 +446,12 @@ TEST_F(DrgnParserTest, ClassTemplateTwo) {
TEST_F(DrgnParserTest, ClassTemplateValue) {
test("oid_test_case_templates_value", R"(
[0] Pointer
[1] Struct: TemplatedClassVal<3> (size: 12)
[2] Pointer
[0] Struct: TemplatedClassVal<3> (size: 12)
Param
Value: 3
Member: arr (offset: 0)
[2] Array: (length: 3)
[1] Array: (length: 3)
Primitive: int32_t
)");
}
@ -459,14 +459,14 @@ TEST_F(DrgnParserTest, ClassTemplateValue) {
TEST_F(DrgnParserTest, TemplateEnumValue) {
testMultiCompilerContains("oid_test_case_enums_params_scoped_enum_val",
R"(
[0] Pointer
[1] Class: MyClass<ns_enums_params::MyNS::ScopedEnum::One> (size: 4)
[1] Pointer
[0] Class: MyClass<ns_enums_params::MyNS::ScopedEnum::One> (size: 4)
Param
Value: ns_enums_params::MyNS::ScopedEnum::One
)",
R"(
[0] Pointer
[1] Class: MyClass<(ns_enums_params::MyNS::ScopedEnum)1> (size: 4)
[1] Pointer
[0] Class: MyClass<(ns_enums_params::MyNS::ScopedEnum)1> (size: 4)
Param
Value: ns_enums_params::MyNS::ScopedEnum::One
)");
@ -475,14 +475,14 @@ TEST_F(DrgnParserTest, TemplateEnumValue) {
TEST_F(DrgnParserTest, TemplateEnumValueGaps) {
testMultiCompilerContains("oid_test_case_enums_params_scoped_enum_val_gaps",
R"(
[0] Pointer
[1] Class: ClassGaps<ns_enums_params::MyNS::EnumWithGaps::Twenty> (size: 4)
[1] Pointer
[0] Class: ClassGaps<ns_enums_params::MyNS::EnumWithGaps::Twenty> (size: 4)
Param
Value: ns_enums_params::MyNS::EnumWithGaps::Twenty
)",
R"(
[0] Pointer
[1] Class: ClassGaps<(ns_enums_params::MyNS::EnumWithGaps)20> (size: 4)
[1] Pointer
[0] Class: ClassGaps<(ns_enums_params::MyNS::EnumWithGaps)20> (size: 4)
Param
Value: ns_enums_params::MyNS::EnumWithGaps::Twenty
)");
@ -491,14 +491,14 @@ TEST_F(DrgnParserTest, TemplateEnumValueGaps) {
TEST_F(DrgnParserTest, TemplateEnumValueNegative) {
testMultiCompilerContains(
"oid_test_case_enums_params_scoped_enum_val_negative", R"(
[0] Pointer
[1] Class: ClassGaps<ns_enums_params::MyNS::EnumWithGaps::MinusTwo> (size: 4)
[1] Pointer
[0] Class: ClassGaps<ns_enums_params::MyNS::EnumWithGaps::MinusTwo> (size: 4)
Param
Value: ns_enums_params::MyNS::EnumWithGaps::MinusTwo
)",
R"(
[0] Pointer
[1] Class: ClassGaps<(ns_enums_params::MyNS::EnumWithGaps)-2> (size: 4)
[1] Pointer
[0] Class: ClassGaps<(ns_enums_params::MyNS::EnumWithGaps)-2> (size: 4)
Param
Value: ns_enums_params::MyNS::EnumWithGaps::MinusTwo
)");
@ -519,8 +519,8 @@ TEST_F(DrgnParserTest, TemplateEnumValueNegative) {
TEST_F(DrgnParserTest, StructAlignment) {
GTEST_SKIP() << "Alignment not reported by drgn yet";
test("oid_test_case_alignment_struct", R"(
[0] Pointer
[1] Struct: Align16 (size: 16, align: 16)
[1] Pointer
[0] Struct: Align16 (size: 16, align: 16)
Member: c (offset: 0)
Primitive: int8_t
)");
@ -529,8 +529,8 @@ TEST_F(DrgnParserTest, StructAlignment) {
TEST_F(DrgnParserTest, MemberAlignment) {
GTEST_SKIP() << "Alignment not reported by drgn yet";
test("oid_test_case_alignment_member_alignment", R"(
[0] Pointer
[1] Struct: MemberAlignment (size: 64)
[1] Pointer
[0] Struct: MemberAlignment (size: 64)
Member: c (offset: 0)
Primitive: int8_t
Member: c32 (offset: 32, align: 32)
@ -540,8 +540,8 @@ TEST_F(DrgnParserTest, MemberAlignment) {
TEST_F(DrgnParserTest, VirtualFunctions) {
testMultiCompiler("oid_test_case_inheritance_polymorphic_a_as_a", R"(
[0] Pointer
[1] Class: A (size: 16)
[1] Pointer
[0] Class: A (size: 16)
Member: _vptr$A (offset: 0)
Primitive: uintptr_t
Member: int_a (offset: 8)
@ -552,8 +552,8 @@ TEST_F(DrgnParserTest, VirtualFunctions) {
Function: A
)",
R"(
[0] Pointer
[1] Class: A (size: 16)
[1] Pointer
[0] Class: A (size: 16)
Member: _vptr.A (offset: 0)
Primitive: uintptr_t
Member: int_a (offset: 8)
@ -568,8 +568,8 @@ TEST_F(DrgnParserTest, VirtualFunctions) {
TEST_F(DrgnParserTest, BitfieldsSingle) {
test("oid_test_case_bitfields_single", R"(
[0] Pointer
[1] Struct: Single (size: 4)
[1] Pointer
[0] Struct: Single (size: 4)
Member: bitfield (offset: 0, bitsize: 3)
Primitive: int32_t
)");
@ -577,8 +577,8 @@ TEST_F(DrgnParserTest, BitfieldsSingle) {
TEST_F(DrgnParserTest, BitfieldsWithinBytes) {
test("oid_test_case_bitfields_within_bytes", R"(
[0] Pointer
[1] Struct: WithinBytes (size: 2)
[1] Pointer
[0] Struct: WithinBytes (size: 2)
Member: a (offset: 0, bitsize: 3)
Primitive: int8_t
Member: b (offset: 0.375, bitsize: 5)
@ -590,8 +590,8 @@ TEST_F(DrgnParserTest, BitfieldsWithinBytes) {
TEST_F(DrgnParserTest, BitfieldsStraddleBytes) {
test("oid_test_case_bitfields_straddle_bytes", R"(
[0] Pointer
[1] Struct: StraddleBytes (size: 3)
[1] Pointer
[0] Struct: StraddleBytes (size: 3)
Member: a (offset: 0, bitsize: 7)
Primitive: int8_t
Member: b (offset: 1, bitsize: 7)
@ -603,8 +603,8 @@ TEST_F(DrgnParserTest, BitfieldsStraddleBytes) {
TEST_F(DrgnParserTest, BitfieldsMixed) {
test("oid_test_case_bitfields_mixed", R"(
[0] Pointer
[1] Struct: Mixed (size: 12)
[1] Pointer
[0] Struct: Mixed (size: 12)
Member: a (offset: 0)
Primitive: int32_t
Member: b (offset: 4, bitsize: 4)
@ -621,8 +621,8 @@ TEST_F(DrgnParserTest, BitfieldsMixed) {
TEST_F(DrgnParserTest, BitfieldsMoreBitsThanType) {
GTEST_SKIP() << "drgn errors out";
test("oid_test_case_bitfields_more_bits_than_type", R"(
[0] Pointer
[1] Struct: MoreBitsThanType (size: 4)
[1] Pointer
[0] Struct: MoreBitsThanType (size: 4)
Member: a (offset: 0, bitsize: 8)
Primitive: int8_t
)");
@ -630,8 +630,8 @@ TEST_F(DrgnParserTest, BitfieldsMoreBitsThanType) {
TEST_F(DrgnParserTest, BitfieldsZeroBits) {
test("oid_test_case_bitfields_zero_bits", R"(
[0] Pointer
[1] Struct: ZeroBits (size: 2)
[1] Pointer
[0] Struct: ZeroBits (size: 2)
Member: b1 (offset: 0, bitsize: 3)
Primitive: int8_t
Member: b2 (offset: 1, bitsize: 2)
@ -641,8 +641,8 @@ TEST_F(DrgnParserTest, BitfieldsZeroBits) {
TEST_F(DrgnParserTest, BitfieldsEnum) {
test("oid_test_case_bitfields_enum", R"(
[0] Pointer
[1] Struct: Enum (size: 4)
[1] Pointer
[0] Struct: Enum (size: 4)
Member: e (offset: 0, bitsize: 2)
Enum: MyEnum (size: 4)
Member: f (offset: 0.25, bitsize: 4)

View File

@ -363,7 +363,7 @@ TEST(FlattenerTest, MemberOfParent) {
Member: b (offset: 0)
Primitive: int32_t
Member: c (offset: 4)
[1] Class: ClassC (size: 4)
[2] Class: ClassC (size: 4)
Member: c (offset: 0)
Primitive: int32_t
Member: a (offset: 8)
@ -771,7 +771,7 @@ TEST(FlattenerTest, ParentClassAndContainer) {
Member: b (offset: 0)
Primitive: int32_t
Member: __oi_parent (offset: 8)
[1] Container: std::vector (size: 24)
[2] Container: std::vector (size: 24)
Param
Primitive: int32_t
)");
@ -809,7 +809,7 @@ TEST(FlattenerTest, AllocatorParamInParent) {
Param
[1] Struct: MyAlloc<std::pair<const int, int>> (size: 1)
Param
[2] Container: std::pair (size: 8)
[3] Container: std::pair (size: 8)
Param
Primitive: int32_t
Qualifiers: const

View File

@ -14,7 +14,7 @@ TEST(RemoveTopLevelPointerTest, TopLevelPointerRemoved) {
Primitive: int32_t
)",
R"(
[0] Class: MyClass (size: 4)
[1] Class: MyClass (size: 4)
Member: n (offset: 0)
Primitive: int32_t
)");

View File

@ -101,7 +101,7 @@ TEST(TypeIdentifierTest, PassThroughTypes) {
Param
Primitive: int32_t
Param
[1] Container: std::allocator (size: 1)
[2] Container: std::allocator (size: 1)
Param
Primitive: int32_t
)");

View File

@ -17,13 +17,13 @@ using type_graph::TypeGraph;
template <typename T>
using ref = std::reference_wrapper<T>;
void check(const std::vector<ref<Type>>& types,
void check(const TypeGraph& typeGraph,
std::string_view expected,
std::string_view comment) {
std::stringstream out;
type_graph::Printer printer(out, types.size());
type_graph::Printer printer(out, typeGraph.resetTracker(), typeGraph.size());
for (const auto& type : types) {
for (const auto& type : typeGraph.rootTypes()) {
printer.print(type);
}
@ -45,52 +45,15 @@ void test(type_graph::Pass pass,
}
// Validate input formatting
check(typeGraph.rootTypes(), input, "parsing input graph");
// Run pass and check results
test(pass, typeGraph.rootTypes(), expectedAfter);
}
void testNoChange(type_graph::Pass pass, std::string_view input) {
input.remove_prefix(1); // Remove initial '\n'
TypeGraph typeGraph;
TypeGraphParser parser{typeGraph};
try {
parser.parse(input);
} catch (const TypeGraphParserError& err) {
FAIL() << "Error parsing input graph: " << err.what();
}
// Validate input formatting
check(typeGraph.rootTypes(), input, "parsing input graph");
// Run pass and check results
test(pass, typeGraph.rootTypes(), input);
}
void test(type_graph::Pass pass,
std::vector<ref<Type>> rootTypes,
std::string_view expectedBefore,
std::string_view expectedAfter) {
if (expectedBefore.data()) {
check(rootTypes, expectedBefore, "before running pass");
}
TypeGraph typeGraph;
for (const auto& type : rootTypes) {
typeGraph.addRoot(type);
}
check(typeGraph, input, "parsing input graph");
pass.run(typeGraph);
// Must use typeGraph's root types here, as the pass may have modified them
check(typeGraph.rootTypes(), expectedAfter, "after running pass");
check(typeGraph, expectedAfter, "after running pass");
}
void test(type_graph::Pass pass,
std::vector<ref<Type>> rootTypes,
std::string_view expectedAfter) {
test(pass, rootTypes, {}, expectedAfter);
void testNoChange(type_graph::Pass pass, std::string_view input) {
test(pass, input, input);
}
Container getVector(NodeId id) {

View File

@ -8,11 +8,12 @@
namespace oi::detail::type_graph {
class Pass;
class TypeGraph;
} // namespace oi::detail::type_graph
using namespace oi::detail;
void check(const std::vector<std::reference_wrapper<type_graph::Type>>& types,
void check(const type_graph::TypeGraph& typeGraph,
std::string_view expected,
std::string_view comment);
@ -22,15 +23,6 @@ void test(type_graph::Pass pass,
void testNoChange(type_graph::Pass pass, std::string_view input);
void test(type_graph::Pass pass,
std::vector<std::reference_wrapper<type_graph::Type>> rootTypes,
std::string_view expectedBefore,
std::string_view expectedAfter);
void test(type_graph::Pass pass,
std::vector<std::reference_wrapper<type_graph::Type>> rootTypes,
std::string_view expectedAfter);
type_graph::Container getVector(type_graph::NodeId id = 0);
type_graph::Container getMap(type_graph::NodeId id = 0);
type_graph::Container getList(type_graph::NodeId id = 0);