TypeGraph: Fix handling for classes which inherit from containers

We previously moved container identification later in CodeGen in order
to preserve information for AlignmentCalc.

However, Flattener needs to know if a class is a container in order to
apply its special handling for this case.

This new approach moves container identification in front of Flattener,
but has Container own a type node, representing its layout. This
underlying type node can be used for calculating a container's
alignment in a later pass.
This commit is contained in:
Alastair Robertson 2023-12-14 08:15:43 -08:00 committed by Alastair Robertson
parent aa87c3f2d1
commit 688d483c0c
25 changed files with 352 additions and 79 deletions

View File

@ -1157,9 +1157,9 @@ void CodeGen::transform(TypeGraph& typeGraph) {
// Simplify the type graph first so there is less work for later passes // Simplify the type graph first so there is less work for later passes
pm.addPass(RemoveTopLevelPointer::createPass()); pm.addPass(RemoveTopLevelPointer::createPass());
pm.addPass(IdentifyContainers::createPass(containerInfos_));
pm.addPass(Flattener::createPass()); pm.addPass(Flattener::createPass());
pm.addPass(AlignmentCalc::createPass()); pm.addPass(AlignmentCalc::createPass());
pm.addPass(IdentifyContainers::createPass(containerInfos_));
pm.addPass(TypeIdentifier::createPass(config_.passThroughTypes)); pm.addPass(TypeIdentifier::createPass(config_.passThroughTypes));
if (config_.features[Feature::PruneTypeGraph]) if (config_.features[Feature::PruneTypeGraph])
pm.addPass(Prune::createPass()); pm.addPass(Prune::createPass());
@ -1173,9 +1173,9 @@ void CodeGen::transform(TypeGraph& typeGraph) {
pm.addPass(AddChildren::createPass(drgnParser, symbols_)); pm.addPass(AddChildren::createPass(drgnParser, symbols_));
// Re-run passes over newly added children // Re-run passes over newly added children
pm.addPass(IdentifyContainers::createPass(containerInfos_));
pm.addPass(Flattener::createPass()); pm.addPass(Flattener::createPass());
pm.addPass(AlignmentCalc::createPass()); pm.addPass(AlignmentCalc::createPass());
pm.addPass(IdentifyContainers::createPass(containerInfos_));
pm.addPass(TypeIdentifier::createPass(config_.passThroughTypes)); pm.addPass(TypeIdentifier::createPass(config_.passThroughTypes));
if (config_.features[Feature::PruneTypeGraph]) if (config_.features[Feature::PruneTypeGraph])
pm.addPass(Prune::createPass()); pm.addPass(Prune::createPass());

View File

@ -48,15 +48,7 @@ void AlignmentCalc::accept(Type& type) {
} }
void AlignmentCalc::visit(Class& c) { void AlignmentCalc::visit(Class& c) {
for (const auto& param : c.templateParams) { RecursiveVisitor::visit(c);
accept(param.type());
}
for (const auto& parent : c.parents) {
accept(parent.type());
}
for (const auto& child : c.children) {
accept(child);
}
uint64_t alignment = 1; uint64_t alignment = 1;
for (auto& member : c.members) { for (auto& member : c.members) {
@ -82,4 +74,12 @@ void AlignmentCalc::visit(Class& c) {
} }
} }
void AlignmentCalc::visit(Container& c) {
RecursiveVisitor::visit(c);
if (c.underlying()) {
c.setAlign(c.underlying()->align());
}
}
} // namespace oi::detail::type_graph } // namespace oi::detail::type_graph

View File

@ -41,6 +41,7 @@ class AlignmentCalc final : public RecursiveVisitor {
void accept(Type& type) override; void accept(Type& type) override;
void visit(Class& c) override; void visit(Class& c) override;
void visit(Container& c) override;
private: private:
std::unordered_set<Type*> visited_; std::unordered_set<Type*> visited_;

View File

@ -81,7 +81,7 @@ class DrgnParser {
template <typename T, typename... Args> template <typename T, typename... Args>
T& makeType(struct drgn_type* drgnType, Args&&... args) { T& makeType(struct drgn_type* drgnType, Args&&... args) {
auto& newType = typeGraph_.makeType<T>(std::forward<Args>(args)...); auto& newType = typeGraph_.makeType<T>(std::forward<Args>(args)...);
drgn_types_.insert({drgnType, newType}); drgn_types_.insert_or_assign(drgnType, newType);
return newType; return newType;
} }
bool chasePointer() const; bool chasePointer() const;

View File

@ -134,8 +134,6 @@ void Flattener::visit(Class& c) {
// }; // };
// TODO comment about virtual inheritance // TODO comment about virtual inheritance
// TODO alignment of parent classes
// Flatten types referenced by template params, parents and members // Flatten types referenced by template params, parents and members
for (const auto& param : c.templateParams) { for (const auto& param : c.templateParams) {
accept(param.type()); accept(param.type());
@ -207,12 +205,4 @@ void Flattener::visit(Class& c) {
} }
} }
void Flattener::visit(Container& c) {
// Containers themselves don't need to be flattened, but their template
// parameters might need to be
for (const auto& templateParam : c.templateParams) {
accept(templateParam.type());
}
}
} // namespace oi::detail::type_graph } // namespace oi::detail::type_graph

View File

@ -42,7 +42,6 @@ class Flattener : public RecursiveVisitor {
void accept(Type& type) override; void accept(Type& type) override;
void visit(Class& c) override; void visit(Class& c) override;
void visit(Container& c) override;
static const inline std::string ParentPrefix = "__oi_parent"; static const inline std::string ParentPrefix = "__oi_parent";

View File

@ -57,11 +57,12 @@ Type& IdentifyContainers::visit(Class& c) {
continue; continue;
} }
auto& container = typeGraph_.makeType<Container>(*containerInfo, c.size()); auto& container =
typeGraph_.makeType<Container>(*containerInfo, c.size(), &c);
container.templateParams = c.templateParams; container.templateParams = c.templateParams;
tracker_.set(c, &container); tracker_.set(c, &container);
RecursiveMutator::visit(container); visit(container);
return container; return container;
} }
@ -70,4 +71,15 @@ Type& IdentifyContainers::visit(Class& c) {
return c; return c;
} }
Type& IdentifyContainers::visit(Container& c) {
for (auto& param : c.templateParams) {
param.setType(mutate(param.type()));
}
// Do not mutate the underlying class further here as that would result in it
// getting replaced with this Container node
return c;
}
} // namespace oi::detail::type_graph } // namespace oi::detail::type_graph

View File

@ -48,6 +48,7 @@ class IdentifyContainers : public RecursiveMutator {
Type& mutate(Type& type) override; Type& mutate(Type& type) override;
Type& visit(Class& c) override; Type& visit(Class& c) override;
Type& visit(Container& c) override;
private: private:
ResultTracker<Type*> tracker_; ResultTracker<Type*> tracker_;

View File

@ -85,7 +85,7 @@ void Printer::visit(const Class& c) {
print_function(function); print_function(function);
} }
for (auto& child : c.children) { for (auto& child : c.children) {
print_child(child); print_type("Child", child);
} }
} }
@ -93,11 +93,14 @@ void Printer::visit(const Container& c) {
if (prefix(c)) if (prefix(c))
return; return;
out_ << "Container: " << c.name() << " (size: " << c.size() << ")" out_ << "Container: " << c.name() << " (size: " << c.size()
<< std::endl; << align_str(c.align()) << ")" << std::endl;
for (const auto& param : c.templateParams) { for (const auto& param : c.templateParams) {
print_param(param); print_param(param);
} }
if (c.underlying()) {
print_type("Underlying", *c.underlying());
}
} }
void Printer::visit(const Primitive& p) { void Printer::visit(const Primitive& p) {
@ -240,11 +243,11 @@ void Printer::print_function(const Function& function) {
depth_--; depth_--;
} }
void Printer::print_child(const Type& child) { void Printer::print_type(std::string_view header, const Type& type) {
depth_++; depth_++;
prefix(); prefix();
out_ << "Child" << std::endl; out_ << header << std::endl;
print(child); print(type);
depth_--; depth_--;
} }

View File

@ -51,7 +51,7 @@ class Printer : public ConstVisitor {
void print_parent(const Parent& parent); void print_parent(const Parent& parent);
void print_member(const Member& member); void print_member(const Member& member);
void print_function(const Function& function); void print_function(const Function& function);
void print_child(const Type& child); void print_type(std::string_view header, const Type& type);
void print_value(const std::string& value); void print_value(const std::string& value);
void print_qualifiers(const QualifierSet& qualifiers); void print_qualifiers(const QualifierSet& qualifiers);
void print_enumerator(int64_t val, const std::string& name); void print_enumerator(int64_t val, const std::string& name);

View File

@ -39,18 +39,7 @@ void Prune::accept(Type& type) {
} }
void Prune::visit(Class& c) { void Prune::visit(Class& c) {
for (const auto& param : c.templateParams) { RecursiveVisitor::visit(c);
accept(param.type());
}
for (const auto& parent : c.parents) {
accept(parent.type());
}
for (const auto& member : c.members) {
accept(member.type());
}
for (const auto& child : c.children) {
accept(child);
}
c.templateParams.clear(); c.templateParams.clear();
c.parents.clear(); c.parents.clear();
@ -62,4 +51,10 @@ void Prune::visit(Class& c) {
c.functions.shrink_to_fit(); c.functions.shrink_to_fit();
} }
void Prune::visit(Container& c) {
RecursiveVisitor::visit(c);
c.setUnderlying(nullptr);
}
} // namespace oi::detail::type_graph } // namespace oi::detail::type_graph

View File

@ -43,6 +43,7 @@ class Prune : public RecursiveVisitor {
void accept(Type& type) override; void accept(Type& type) override;
void visit(Class& c) override; void visit(Class& c) override;
void visit(Container& c) override;
private: private:
NodeTracker& tracker_; NodeTracker& tracker_;

View File

@ -79,7 +79,8 @@ void TypeIdentifier::visit(Container& c) {
it != passThroughTypeDummys_.end()) { it != passThroughTypeDummys_.end()) {
dummy = &it->second.get(); dummy = &it->second.get();
} else { } else {
dummy = &typeGraph_.makeType<Container>(info, param.type().size()); dummy = &typeGraph_.makeType<Container>(
info, param.type().size(), paramClass);
dummy->templateParams = paramClass->templateParams; dummy->templateParams = paramClass->templateParams;
passThroughTypeDummys_.insert(it, passThroughTypeDummys_.insert(it,
{paramClass->id(), std::ref(*dummy)}); {paramClass->id(), std::ref(*dummy)});

View File

@ -150,7 +150,6 @@ struct Function {
int virtuality; int virtuality;
}; };
class Class;
struct Parent { struct Parent {
Parent(Type& type, uint64_t bitOffset) : type_(type), bitOffset(bitOffset) { Parent(Type& type, uint64_t bitOffset) : type_(type), bitOffset(bitOffset) {
} }
@ -298,10 +297,6 @@ class Class : public Type {
DECLARE_ACCEPT DECLARE_ACCEPT
Kind kind() const {
return kind_;
}
virtual const std::string& name() const override { virtual const std::string& name() const override {
return name_; return name_;
} }
@ -326,12 +321,16 @@ class Class : public Type {
return align_; return align_;
} }
void setAlign(uint64_t alignment) {
align_ = alignment;
}
virtual NodeId id() const override { virtual NodeId id() const override {
return id_; return id_;
} }
void setAlign(uint64_t alignment) { Kind kind() const {
align_ = alignment; return kind_;
} }
int virtuality() const { int virtuality() const {
@ -371,10 +370,19 @@ class Class : public Type {
bool packed_ = false; bool packed_ = false;
}; };
/*
* Container
*
* A type of class for which we can do special processing.
*/
class Container : public Type { class Container : public Type {
public: public:
Container(NodeId id, const ContainerInfo& containerInfo, size_t size) Container(NodeId id,
const ContainerInfo& containerInfo,
size_t size,
Type* underlying)
: containerInfo_(containerInfo), : containerInfo_(containerInfo),
underlying_(underlying),
name_(containerInfo.typeName), name_(containerInfo.typeName),
inputName_(containerInfo.typeName), inputName_(containerInfo.typeName),
size_(size), size_(size),
@ -386,6 +394,7 @@ class Container : public Type {
const ContainerInfo& containerInfo) const ContainerInfo& containerInfo)
: templateParams(other.templateParams), : templateParams(other.templateParams),
containerInfo_(containerInfo), containerInfo_(containerInfo),
underlying_(other.underlying_),
name_(other.name_), name_(other.name_),
inputName_(other.inputName_), inputName_(other.inputName_),
size_(other.size_), size_(other.size_),
@ -396,22 +405,18 @@ class Container : public Type {
DECLARE_ACCEPT DECLARE_ACCEPT
const std::string& containerName() const {
return containerInfo_.typeName;
}
virtual const std::string& name() const override { virtual const std::string& name() const override {
return name_; return name_;
} }
void setName(std::string name) {
name_ = std::move(name);
}
virtual std::string_view inputName() const override { virtual std::string_view inputName() const override {
return inputName_; return inputName_;
} }
void setName(std::string name) {
name_ = std::move(name);
}
void setInputName(std::string name) { void setInputName(std::string name) {
inputName_ = std::move(name); inputName_ = std::move(name);
} }
@ -424,18 +429,31 @@ class Container : public Type {
return align_; return align_;
} }
void setAlign(uint64_t alignment) {
align_ = alignment;
}
virtual NodeId id() const override { virtual NodeId id() const override {
return id_; return id_;
} }
void setAlign(uint64_t alignment) { const std::string& containerName() const {
align_ = alignment; return containerInfo_.typeName;
}
Type* underlying() const {
return underlying_;
}
void setUnderlying(Type* underlying) {
underlying_ = underlying;
} }
std::vector<TemplateParam> templateParams; std::vector<TemplateParam> templateParams;
const ContainerInfo& containerInfo_; const ContainerInfo& containerInfo_;
private: private:
Type* underlying_;
std::string name_; std::string name_;
std::string inputName_; std::string inputName_;
size_t size_; size_t size_;

View File

@ -93,6 +93,7 @@ class RecursiveVisitor : public Visitor<void> {
for (const auto& param : c.templateParams) { for (const auto& param : c.templateParams) {
accept(param.type()); accept(param.type());
} }
accept(c.underlying());
} }
virtual void visit(Primitive&) { virtual void visit(Primitive&) {
} }
@ -126,6 +127,11 @@ class RecursiveMutator : public Visitor<Type&> {
public: public:
virtual ~RecursiveMutator() = default; virtual ~RecursiveMutator() = default;
virtual Type& mutate(Type&) = 0; virtual Type& mutate(Type&) = 0;
virtual Type* mutate(Type* type) {
if (type)
return &mutate(*type);
return nullptr;
}
virtual Type& visit(Incomplete& i) { virtual Type& visit(Incomplete& i) {
return i; return i;
} }
@ -148,6 +154,7 @@ class RecursiveMutator : public Visitor<Type&> {
for (auto& param : c.templateParams) { for (auto& param : c.templateParams) {
param.setType(mutate(param.type())); param.setType(mutate(param.type()));
} }
c.setUnderlying(mutate(c.underlying()));
return c; return c;
} }
virtual Type& visit(Primitive& p) { virtual Type& visit(Primitive& p) {

View File

@ -265,10 +265,11 @@ Type& TypeGraphParser::parseType(std::string_view& input, size_t rootIndent) {
auto size = parseNumericAttribute(line, nodeTypeName, "size: "); auto size = parseNumericAttribute(line, nodeTypeName, "size: ");
Container& c = typeGraph_.makeType<Container>(id, info, size); Container& c = typeGraph_.makeType<Container>(id, info, size, nullptr);
nodesById_.insert({id, c}); nodesById_.insert({id, c});
parseParams(c, input, indent + 2); parseParams(c, input, indent + 2);
parseUnderlying(c, input, indent + 2);
type = &c; type = &c;
} else if (nodeTypeName == "Primitive") { } else if (nodeTypeName == "Primitive") {
@ -452,3 +453,26 @@ void TypeGraphParser::parseChildren(Class& c,
// No more children for us - put back the line we just read // No more children for us - put back the line we just read
input = origInput; input = origInput;
} }
void TypeGraphParser::parseUnderlying(Container& c,
std::string_view& input,
size_t rootIndent) {
std::string_view origInput = input;
std::string_view line;
getline(input, line);
size_t indent = stripIndent(line);
if (indent != rootIndent) {
input = origInput;
return;
}
// Format: "Underlying"
if (!tryRemovePrefix(line, "Underlying")) {
input = origInput;
return;
}
Type& type = parseType(input, rootIndent + 2);
c.setUnderlying(&type);
}

View File

@ -34,6 +34,9 @@ class TypeGraphParser {
void parseMembers(Class& c, std::string_view& input, size_t rootIndent); void parseMembers(Class& c, std::string_view& input, size_t rootIndent);
void parseFunctions(Class& c, std::string_view& input, size_t rootIndent); void parseFunctions(Class& c, std::string_view& input, size_t rootIndent);
void parseChildren(Class& c, std::string_view& input, size_t rootIndent); void parseChildren(Class& c, std::string_view& input, size_t rootIndent);
void parseUnderlying(Container& c,
std::string_view& input,
size_t rootIndent);
}; };
class TypeGraphParserError : public std::runtime_error { class TypeGraphParserError : public std::runtime_error {

View File

@ -106,7 +106,7 @@ TEST_F(AddChildrenTest, InheritancePolymorphic) {
Function: ~allocator Function: ~allocator
Function: allocate Function: allocate
Function: deallocate Function: deallocate
* *
Function: ~B (virtual) Function: ~B (virtual)
Function: myfunc (virtual) Function: myfunc (virtual)
Function: B Function: B
@ -159,7 +159,7 @@ TEST_F(AddChildrenTest, InheritancePolymorphic) {
Function: ~allocator Function: ~allocator
Function: allocate Function: allocate
Function: deallocate Function: deallocate
* *
Function: operator= Function: operator=
Function: B Function: B
Function: B Function: B

View File

@ -58,16 +58,16 @@ TEST(AlignmentCalcTest, StructInContainer) {
Member: n (offset: 0) Member: n (offset: 0)
Primitive: int8_t Primitive: int8_t
Member: n (offset: 8) Member: n (offset: 8)
Primitive: int64_t Primitive: int32_t
)", )",
R"( R"(
[0] Container: std::vector (size: 8) [0] Container: std::vector (size: 8)
Param Param
[1] Class: MyClass (size: 16, align: 8) [1] Class: MyClass (size: 16, align: 4)
Member: n (offset: 0, align: 1) Member: n (offset: 0, align: 1)
Primitive: int8_t Primitive: int8_t
Member: n (offset: 8, align: 8) Member: n (offset: 8, align: 4)
Primitive: int64_t Primitive: int32_t
)"); )");
} }
@ -264,3 +264,33 @@ TEST(AlignmentCalcTest, Typedef) {
Primitive: int8_t Primitive: int8_t
)"); )");
} }
TEST(AlignmentCalcTest, Container) {
test(AlignmentCalc::createPass(),
R"(
[0] Container: std::vector (size: 24)
Underlying
[1] Class: vector (size: 24)
Member: n (offset: 0)
Primitive: int8_t
Member: s (offset: 4)
[2] Struct: MyStruct (size: 8)
Member: n1 (offset: 0)
Primitive: int32_t
Member: n2 (offset: 4)
Primitive: int32_t
)",
R"(
[0] Container: std::vector (size: 24, align: 4)
Underlying
[1] Class: vector (size: 24, align: 4)
Member: n (offset: 0, align: 1)
Primitive: int8_t
Member: s (offset: 4, align: 4)
[2] Struct: MyStruct (size: 8, align: 4)
Member: n1 (offset: 0, align: 4)
Primitive: int32_t
Member: n2 (offset: 4, align: 4)
Primitive: int32_t
)");
}

View File

@ -45,6 +45,8 @@ void testTransform(OICodeGen::Config& config,
void testTransform(std::string_view input, std::string_view expectedAfter) { void testTransform(std::string_view input, std::string_view expectedAfter) {
OICodeGen::Config config; OICodeGen::Config config;
config.features[Feature::PruneTypeGraph] = true;
config.features[Feature::TreeBuilderV2] = true;
testTransform(config, input, expectedAfter); testTransform(config, input, expectedAfter);
} }
} // namespace } // namespace
@ -62,7 +64,7 @@ TEST(CodeGenTest, TransformContainerAllocator) {
Function: deallocate Function: deallocate
)", )",
R"( R"(
[2] Container: std::vector<int32_t, DummyAllocator<int32_t, 8, 1, 3>> (size: 24) [2] Container: std::vector<int32_t, DummyAllocator<int32_t, 8, 1, 3>> (size: 24, align: 1)
Param Param
Primitive: int32_t Primitive: int32_t
Param Param
@ -95,14 +97,14 @@ TEST(CodeGenTest, TransformContainerAllocatorParamInParent) {
Function: deallocate Function: deallocate
)", )",
R"( R"(
[4] Container: std::map<int32_t, int32_t, DummyAllocator<std::pair<int32_t const, int32_t>, 0, 1, 6>> (size: 24) [4] Container: std::map<int32_t, int32_t, DummyAllocator<std::pair<int32_t const, int32_t>, 0, 1, 6>> (size: 24, align: 1)
Param Param
Primitive: int32_t Primitive: int32_t
Param Param
Primitive: int32_t Primitive: int32_t
Param Param
[6] DummyAllocator [MyAlloc<std::pair<const int, int>>] (size: 0, align: 1) [6] DummyAllocator [MyAlloc<std::pair<const int, int>>] (size: 0, align: 1)
[5] Container: std::pair<int32_t const, int32_t> (size: 8) [5] Container: std::pair<int32_t const, int32_t> (size: 8, align: 1)
Param Param
Primitive: int32_t Primitive: int32_t
Qualifiers: const Qualifiers: const
@ -168,7 +170,7 @@ TEST(CodeGenTest, ReplaceContainersAndDummies) {
Function: deallocate Function: deallocate
)", )",
R"( R"(
[2] Container: std::vector<uint32_t, DummyAllocator<uint32_t, 0, 1, 3>> (size: 24) [2] Container: std::vector<uint32_t, DummyAllocator<uint32_t, 0, 1, 3>> (size: 24, align: 1)
Param Param
Primitive: uint32_t Primitive: uint32_t
Param Param
@ -176,3 +178,73 @@ TEST(CodeGenTest, ReplaceContainersAndDummies) {
Primitive: uint32_t Primitive: uint32_t
)"); )");
} }
TEST(CodeGenTest, ContainerAlignment) {
testTransform(R"(
[0] Class: MyClass (size: 24)
Member: container (offset: 0)
[1] Class: std::vector (size: 24)
Param
Primitive: int32_t
Member: __impl__ (offset: 0)
Primitive: StubbedPointer
Member: __impl__ (offset: 8)
Primitive: StubbedPointer
Member: __impl__ (offset: 16)
Primitive: StubbedPointer
)",
R"(
[0] Class: MyClass_0 [MyClass] (size: 24, align: 8)
Member: container_0 [container] (offset: 0, align: 8)
[2] Container: std::vector<int32_t> (size: 24, align: 8)
Param
Primitive: int32_t
)");
}
TEST(CodeGenTest, InheritFromContainer) {
testTransform(R"(
[0] Class: MyClass (size: 24)
Parent (offset: 0)
[1] Class: std::vector (size: 24)
Param
Primitive: int32_t
Member: __impl__ (offset: 0)
Primitive: StubbedPointer
Member: __impl__ (offset: 8)
Primitive: StubbedPointer
Member: __impl__ (offset: 16)
Primitive: StubbedPointer
)",
R"(
[0] Class: MyClass_0 [MyClass] (size: 24, align: 8)
Member: __oi_parent_0 [__oi_parent] (offset: 0, align: 8)
[2] Container: std::vector<int32_t> (size: 24, align: 8)
Param
Primitive: int32_t
)");
}
TEST(CodeGenTest, InheritFromContainerCompat) {
OICodeGen::Config config;
testTransform(config,
R"(
[0] Class: MyClass (size: 24)
Parent (offset: 0)
[1] Class: std::vector (size: 24)
Param
Primitive: int32_t
Member: __impl__ (offset: 0)
Primitive: StubbedPointer
Member: __impl__ (offset: 8)
Primitive: StubbedPointer
Member: __impl__ (offset: 16)
Primitive: StubbedPointer
)",
R"(
[0] Class: MyClass_0 [MyClass] (size: 24, align: 8)
Member: __oi_padding_0 (offset: 0)
[3] Array: [int8_t[24]] (length: 24)
Primitive: int8_t
)");
}

View File

@ -799,6 +799,27 @@ TEST(FlattenerTest, ParentClassAndContainer) {
)"); )");
} }
TEST(FlattenerTest, ContainerWithParent) {
// This is necessary to correctly calculate container alignment
test(Flattener::createPass(),
R"(
[0] Container: std::vector (size: 24)
Underlying
[1] Class: vector (size: 24)
Parent (offset: 0)
[2] Class: Parent (size: 4)
Member: x (offset: 0)
Primitive: int32_t
)",
R"(
[0] Container: std::vector (size: 24)
Underlying
[1] Class: vector (size: 24)
Member: x (offset: 0)
Primitive: int32_t
)");
}
TEST(FlattenerTest, AllocatorParamInParent) { TEST(FlattenerTest, AllocatorParamInParent) {
test(Flattener::createPass(), test(Flattener::createPass(),
R"( R"(
@ -857,7 +878,7 @@ TEST(FlattenerTest, AllocatorUnfixableNoParent) {
)"); )");
} }
TEST(FlattenerTest, AllocatorUnfixableParentNotClass) { TEST(FlattenerTest, AllocatorParamInParentContainer) {
// This could be supported if need-be, we just don't do it yet // This could be supported if need-be, we just don't do it yet
test(Flattener::createPass(), test(Flattener::createPass(),
R"( R"(

View File

@ -27,6 +27,12 @@ TEST(IdentifyContainers, Container) {
[1] Container: std::vector (size: 24) [1] Container: std::vector (size: 24)
Param Param
Primitive: int32_t Primitive: int32_t
Underlying
[0] Class: std::vector (size: 24)
Param
Primitive: int32_t
Member: a (offset: 0)
Primitive: int32_t
)"); )");
} }
@ -52,14 +58,26 @@ TEST(IdentifyContainers, ContainerInClass) {
[4] Container: std::vector (size: 24) [4] Container: std::vector (size: 24)
Param Param
Primitive: int32_t Primitive: int32_t
Underlying
[1] Class: std::vector (size: 24)
Param
Primitive: int32_t
Parent (offset: 0) Parent (offset: 0)
[5] Container: std::vector (size: 24) [5] Container: std::vector (size: 24)
Param Param
Primitive: int32_t Primitive: int32_t
Underlying
[2] Class: std::vector (size: 24)
Param
Primitive: int32_t
Member: a (offset: 0) Member: a (offset: 0)
[6] Container: std::vector (size: 24) [6] Container: std::vector (size: 24)
Param Param
Primitive: int32_t Primitive: int32_t
Underlying
[3] Class: std::vector (size: 24)
Param
Primitive: int32_t
)"); )");
} }
@ -77,6 +95,14 @@ TEST(IdentifyContainers, ContainerInContainer) {
[3] Container: std::vector (size: 24) [3] Container: std::vector (size: 24)
Param Param
Primitive: int32_t Primitive: int32_t
Underlying
[1] Class: std::vector (size: 24)
Param
Primitive: int32_t
Underlying
[0] Class: std::vector (size: 24)
Param
[1]
)"); )");
} }
@ -94,6 +120,10 @@ TEST(IdentifyContainers, ContainerInContainer2) {
[2] Container: std::vector (size: 24) [2] Container: std::vector (size: 24)
Param Param
Primitive: int32_t Primitive: int32_t
Underlying
[1] Class: std::vector (size: 24)
Param
Primitive: int32_t
)"); )");
} }
@ -109,6 +139,10 @@ TEST(IdentifyContainers, ContainerInArray) {
[2] Container: std::vector (size: 24) [2] Container: std::vector (size: 24)
Param Param
Primitive: int32_t Primitive: int32_t
Underlying
[1] Class: std::vector (size: 24)
Param
Primitive: int32_t
)"); )");
} }
@ -124,6 +158,10 @@ TEST(IdentifyContainers, ContainerInTypedef) {
[2] Container: std::vector (size: 24) [2] Container: std::vector (size: 24)
Param Param
Primitive: int32_t Primitive: int32_t
Underlying
[1] Class: std::vector (size: 24)
Param
Primitive: int32_t
)"); )");
} }
@ -139,6 +177,10 @@ TEST(IdentifyContainers, ContainerInPointer) {
[2] Container: std::vector (size: 24) [2] Container: std::vector (size: 24)
Param Param
Primitive: int32_t Primitive: int32_t
Underlying
[1] Class: std::vector (size: 24)
Param
Primitive: int32_t
)"); )");
} }
@ -155,6 +197,12 @@ TEST(IdentifyContainers, ContainerDuplicate) {
[1] Container: std::vector (size: 24) [1] Container: std::vector (size: 24)
Param Param
Primitive: int32_t Primitive: int32_t
Underlying
[0] Class: std::vector (size: 24)
Param
Primitive: int32_t
Member: a (offset: 0)
Primitive: int32_t
[1] [1]
)"); )");
} }
@ -190,5 +238,9 @@ TEST(IdentifyContainers, CycleContainer) {
[2] Container: std::vector (size: 0) [2] Container: std::vector (size: 0)
Param Param
[0] [0]
Underlying
[1] Class: std::vector (size: 0)
Param
[0]
)"); )");
} }

View File

@ -63,3 +63,33 @@ TEST(PruneTest, RecurseClassChild) {
[1] Class: ClassA (size: 12) [1] Class: ClassA (size: 12)
)"); )");
} }
TEST(PruneTest, PruneContainer) {
test(Prune::createPass(),
R"(
[0] Container: std::vector (size: 24)
Param
Primitive: int32_t
Param
Value: "123"
Primitive: int32_t
Underlying
[1] Class: vector<int32_t> (size: 24)
Parent (offset: 0)
[2] Class: MyParent (size: 4)
Member: a (offset: 0)
Primitive: int32_t
Member: a (offset: 0)
Primitive: int32_t
Member: b (offset: 4)
Primitive: int32_t
)",
R"(
[0] Container: std::vector (size: 24)
Param
Primitive: int32_t
Param
Value: "123"
Primitive: int32_t
)");
}

View File

@ -108,6 +108,12 @@ TEST(TypeIdentifierTest, PassThroughTypes) {
[2] Container: std::allocator (size: 1) [2] Container: std::allocator (size: 1)
Param Param
Primitive: int32_t Primitive: int32_t
Underlying
[1] Class: std::allocator (size: 1)
Param
Primitive: int32_t
Function: allocate
Function: deallocate
)"); )");
} }
@ -137,6 +143,12 @@ TEST(TypeIdentifierTest, PassThroughSameType) {
[2] Container: std::allocator (size: 1) [2] Container: std::allocator (size: 1)
Param Param
Primitive: int32_t Primitive: int32_t
Underlying
[1] Class: std::allocator (size: 1)
Param
Primitive: int32_t
Function: allocate
Function: deallocate
Param Param
[2] [2]
)"); )");

View File

@ -86,22 +86,23 @@ std::vector<std::unique_ptr<ContainerInfo>> getContainerInfos() {
Container getVector(NodeId id) { Container getVector(NodeId id) {
static ContainerInfo info{"std::vector", SEQ_TYPE, "vector"}; static ContainerInfo info{"std::vector", SEQ_TYPE, "vector"};
info.stubTemplateParams = {1}; info.stubTemplateParams = {1};
return Container{id, info, 24}; return Container{id, info, 24, nullptr};
} }
Container getMap(NodeId id) { Container getMap(NodeId id) {
static ContainerInfo info{"std::map", STD_MAP_TYPE, "map"}; static ContainerInfo info{"std::map", STD_MAP_TYPE, "map"};
info.stubTemplateParams = {2, 3}; info.stubTemplateParams = {2, 3};
return Container{id, info, 48}; return Container{id, info, 48, nullptr};
} }
Container getList(NodeId id) { Container getList(NodeId id) {
static ContainerInfo info{"std::list", LIST_TYPE, "list"}; static ContainerInfo info{"std::list", LIST_TYPE, "list"};
info.stubTemplateParams = {1}; info.stubTemplateParams = {1};
return Container{id, info, 24}; return Container{id, info, 24, nullptr};
} }
Container getPair(NodeId id) { Container getPair(NodeId id) {
static ContainerInfo info{"std::pair", PAIR_TYPE, "utility"}; static ContainerInfo info{"std::pair", PAIR_TYPE, "utility"};
return Container{id, info, 8}; // Nonsense size, shouldn't matter for tests return Container{
id, info, 8, nullptr}; // Nonsense size, shouldn't matter for tests
} }