TopoSorter: Sort Typedefs before pointers

Also rename visitAfter() to acceptAfter() to match the previous renaming
of visit() to accept().
This commit is contained in:
Alastair Robertson 2023-07-24 05:14:31 -07:00 committed by Alastair Robertson
parent df5ae4e34c
commit e1496354de
3 changed files with 40 additions and 11 deletions

View File

@ -69,7 +69,7 @@ void TopoSorter::visit(Class& c) {
// Same as pointers, children do not create a dependency so are delayed until
// the end.
for (const auto& child : c.children) {
visitAfter(child);
acceptAfter(child);
}
}
@ -103,7 +103,7 @@ void TopoSorter::visit(Container& c) {
sortedTypes_.push_back(c);
if (containerAllowsIncompleteParams(c)) {
for (const auto& param : c.templateParams) {
visitAfter(param.type());
acceptAfter(param.type());
}
}
}
@ -118,9 +118,16 @@ void TopoSorter::visit(Typedef& td) {
}
void TopoSorter::visit(Pointer& p) {
if (dynamic_cast<Typedef*>(&p.pointeeType())) {
// Typedefs can not be forward declared, so we must sort them before
// pointers which reference them
accept(p.pointeeType());
return;
}
// Pointers do not create a dependency, but we do still care about the types
// they point to, so delay them until the end.
visitAfter(p.pointeeType());
acceptAfter(p.pointeeType());
}
/*
@ -131,13 +138,13 @@ void TopoSorter::visit(Pointer& p) {
* program. This means we can delay processing them until after all of the true
* dependencies have been sorted.
*/
void TopoSorter::visitAfter(Type& type) {
void TopoSorter::acceptAfter(Type& type) {
typesToSort_.push(type);
}
void TopoSorter::visitAfter(Type* type) {
void TopoSorter::acceptAfter(Type* type) {
if (type) {
visitAfter(*type);
acceptAfter(*type);
}
}

View File

@ -52,8 +52,8 @@ class TopoSorter : public RecursiveVisitor {
std::vector<std::reference_wrapper<Type>> sortedTypes_;
std::queue<std::reference_wrapper<Type>> typesToSort_;
void visitAfter(Type& type);
void visitAfter(Type* type);
void acceptAfter(Type& type);
void acceptAfter(Type* type);
};
} // namespace type_graph

View File

@ -209,10 +209,16 @@ aliasA
TEST(TopoSorterTest, Pointers) {
// Pointers do not require pointee types to be defined first
auto myclass = Class{0, Class::Kind::Class, "MyClass", 69};
auto mypointer = Pointer{1, myclass};
auto classA = Class{0, Class::Kind::Class, "ClassA", 69};
auto mypointer = Pointer{1, classA};
test({mypointer}, "MyClass");
auto myclass = Class{2, Class::Kind::Class, "MyClass", 69};
myclass.members.push_back(Member{mypointer, "ptr", 0});
test({myclass}, R"(
MyClass
ClassA
)");
}
TEST(TopoSorterTest, PointerCycle) {
@ -238,6 +244,22 @@ ClassA
}
}
TEST(TopoSorterTest, PointerToTypedef) {
auto classA = Class{0, Class::Kind::Class, "ClassA", 8};
auto aliasA = Typedef{1, "aliasA", classA};
auto mypointer = Pointer{1, aliasA};
auto myclass = Class{2, Class::Kind::Class, "MyClass", 69};
myclass.members.push_back(Member{mypointer, "ptrToTypedef", 0});
test({myclass}, R"(
ClassA
aliasA
MyClass
)");
}
TEST(TopoSorterTest, TwoDeep) {
auto myunion = Class{0, Class::Kind::Union, "MyUnion", 7};
auto mystruct = Class{1, Class::Kind::Struct, "MyStruct", 13};