mirror of
https://github.com/JakeHillion/object-introspection.git
synced 2024-09-19 11:09:05 +01:00
TypeGraph: Add IdentifyContainers mutator pass
This commit is contained in:
parent
451678b19b
commit
98008f9054
@ -5,6 +5,7 @@ add_library(type_graph
|
|||||||
DrgnParser.cpp
|
DrgnParser.cpp
|
||||||
EnforceCompatibility.cpp
|
EnforceCompatibility.cpp
|
||||||
Flattener.cpp
|
Flattener.cpp
|
||||||
|
IdentifyContainers.cpp
|
||||||
KeyCapture.cpp
|
KeyCapture.cpp
|
||||||
NameGen.cpp
|
NameGen.cpp
|
||||||
PassManager.cpp
|
PassManager.cpp
|
||||||
|
88
oi/type_graph/IdentifyContainers.cpp
Normal file
88
oi/type_graph/IdentifyContainers.cpp
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
#include "IdentifyContainers.h"
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
#include "TypeGraph.h"
|
||||||
|
#include "oi/ContainerInfo.h"
|
||||||
|
|
||||||
|
namespace oi::detail::type_graph {
|
||||||
|
|
||||||
|
Pass IdentifyContainers::createPass(
|
||||||
|
const std::vector<std::unique_ptr<ContainerInfo>>& containers) {
|
||||||
|
auto fn = [&containers](TypeGraph& typeGraph, NodeTracker&) {
|
||||||
|
IdentifyContainers typeId{typeGraph, containers};
|
||||||
|
for (auto& type : typeGraph.rootTypes()) {
|
||||||
|
type = typeId.mutate(type);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Pass("IdentifyContainers", fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IdentifyContainers::isAllocator(Type& t) {
|
||||||
|
auto* c = dynamic_cast<Class*>(&t);
|
||||||
|
if (!c)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Maybe add more checks for an allocator.
|
||||||
|
// For now, just test for the presence of an "allocate" function
|
||||||
|
for (const auto& func : c->functions) {
|
||||||
|
if (func.name == "allocate") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
IdentifyContainers::IdentifyContainers(
|
||||||
|
TypeGraph& typeGraph,
|
||||||
|
const std::vector<std::unique_ptr<ContainerInfo>>& containers)
|
||||||
|
: tracker_(typeGraph.size()),
|
||||||
|
typeGraph_(typeGraph),
|
||||||
|
containers_(containers) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Type& IdentifyContainers::mutate(Type& type) {
|
||||||
|
if (Type* mutated = tracker_.get(type))
|
||||||
|
return *mutated;
|
||||||
|
|
||||||
|
Type& mutated = type.accept(*this);
|
||||||
|
tracker_.set(type, mutated);
|
||||||
|
return mutated;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type& IdentifyContainers::visit(Class& c) {
|
||||||
|
for (const auto& containerInfo : containers_) {
|
||||||
|
if (!std::regex_search(c.fqName(), containerInfo->matcher)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& container = typeGraph_.makeType<Container>(*containerInfo, c.size());
|
||||||
|
container.templateParams = c.templateParams;
|
||||||
|
|
||||||
|
tracker_.set(c, container);
|
||||||
|
RecursiveMutator::visit(container);
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
tracker_.set(c, c);
|
||||||
|
RecursiveMutator::visit(c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace oi::detail::type_graph
|
59
oi/type_graph/IdentifyContainers.h
Normal file
59
oi/type_graph/IdentifyContainers.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "NodeTracker.h"
|
||||||
|
#include "PassManager.h"
|
||||||
|
#include "Types.h"
|
||||||
|
#include "Visitor.h"
|
||||||
|
#include "oi/ContainerInfo.h"
|
||||||
|
|
||||||
|
namespace oi::detail::type_graph {
|
||||||
|
|
||||||
|
class TypeGraph;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IdentifyContainers
|
||||||
|
*
|
||||||
|
* Walks a flattened type graph and replaces type nodes based on container
|
||||||
|
* definition TOML files.
|
||||||
|
*/
|
||||||
|
class IdentifyContainers : public RecursiveMutator {
|
||||||
|
public:
|
||||||
|
static Pass createPass(
|
||||||
|
const std::vector<std::unique_ptr<ContainerInfo>>& containers);
|
||||||
|
static bool isAllocator(Type& t);
|
||||||
|
|
||||||
|
IdentifyContainers(
|
||||||
|
TypeGraph& typeGraph,
|
||||||
|
const std::vector<std::unique_ptr<ContainerInfo>>& containers);
|
||||||
|
|
||||||
|
using RecursiveMutator::mutate;
|
||||||
|
|
||||||
|
Type& mutate(Type& type) override;
|
||||||
|
Type& visit(Class& c) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
MutationTracker tracker_;
|
||||||
|
TypeGraph& typeGraph_;
|
||||||
|
const std::vector<std::unique_ptr<ContainerInfo>>& containers_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace oi::detail::type_graph
|
@ -43,6 +43,7 @@ add_executable(test_type_graph
|
|||||||
test_drgn_parser.cpp
|
test_drgn_parser.cpp
|
||||||
test_enforce_compatibility.cpp
|
test_enforce_compatibility.cpp
|
||||||
test_flattener.cpp
|
test_flattener.cpp
|
||||||
|
test_identify_containers.cpp
|
||||||
test_key_capture.cpp
|
test_key_capture.cpp
|
||||||
test_name_gen.cpp
|
test_name_gen.cpp
|
||||||
test_node_tracker.cpp
|
test_node_tracker.cpp
|
||||||
|
193
test/test_identify_containers.cpp
Normal file
193
test/test_identify_containers.cpp
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "oi/ContainerInfo.h"
|
||||||
|
#include "oi/type_graph/IdentifyContainers.h"
|
||||||
|
#include "oi/type_graph/Types.h"
|
||||||
|
#include "test/type_graph_utils.h"
|
||||||
|
|
||||||
|
using namespace type_graph;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void test(std::string_view input, std::string_view expectedAfter) {
|
||||||
|
::test(IdentifyContainers::createPass(getContainerInfos()), input,
|
||||||
|
expectedAfter);
|
||||||
|
}
|
||||||
|
}; // namespace
|
||||||
|
|
||||||
|
TEST(IdentifyContainers, Container) {
|
||||||
|
test(R"(
|
||||||
|
[0] Class: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
Member: a (offset: 0)
|
||||||
|
Primitive: int32_t
|
||||||
|
)",
|
||||||
|
R"(
|
||||||
|
[1] Container: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(IdentifyContainers, ContainerInClass) {
|
||||||
|
test(R"(
|
||||||
|
[0] Class: MyClass (size: 0)
|
||||||
|
Param
|
||||||
|
[1] Class: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
Parent (offset: 0)
|
||||||
|
[2] Class: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
Member: a (offset: 0)
|
||||||
|
[3] Class: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
)",
|
||||||
|
R"(
|
||||||
|
[0] Class: MyClass (size: 0)
|
||||||
|
Param
|
||||||
|
[4] Container: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
Parent (offset: 0)
|
||||||
|
[5] Container: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
Member: a (offset: 0)
|
||||||
|
[6] Container: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(IdentifyContainers, ContainerInContainer) {
|
||||||
|
test(R"(
|
||||||
|
[0] Class: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
[1] Class: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
)",
|
||||||
|
R"(
|
||||||
|
[2] Container: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
[3] Container: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(IdentifyContainers, ContainerInContainer2) {
|
||||||
|
test(R"(
|
||||||
|
[0] Container: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
[1] Class: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
)",
|
||||||
|
R"(
|
||||||
|
[0] Container: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
[2] Container: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(IdentifyContainers, ContainerInArray) {
|
||||||
|
test(R"(
|
||||||
|
[0] Array: (length: 2)
|
||||||
|
[1] Class: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
)",
|
||||||
|
R"(
|
||||||
|
[0] Array: (length: 2)
|
||||||
|
[2] Container: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(IdentifyContainers, ContainerInTypedef) {
|
||||||
|
test(R"(
|
||||||
|
[0] Typedef: MyAlias
|
||||||
|
[1] Class: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
)",
|
||||||
|
R"(
|
||||||
|
[0] Typedef: MyAlias
|
||||||
|
[2] Container: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(IdentifyContainers, ContainerInPointer) {
|
||||||
|
test(R"(
|
||||||
|
[0] Pointer
|
||||||
|
[1] Class: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
)",
|
||||||
|
R"(
|
||||||
|
[0] Pointer
|
||||||
|
[2] Container: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(IdentifyContainers, ContainerDuplicate) {
|
||||||
|
test(R"(
|
||||||
|
[0] Class: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
Member: a (offset: 0)
|
||||||
|
Primitive: int32_t
|
||||||
|
[0]
|
||||||
|
)",
|
||||||
|
R"(
|
||||||
|
[1] Container: std::vector (size: 24)
|
||||||
|
Param
|
||||||
|
Primitive: int32_t
|
||||||
|
[1]
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(IdentifyContainers, CycleClass) {
|
||||||
|
test(R"(
|
||||||
|
[0] Class: ClassA (size: 0)
|
||||||
|
Member: x (offset: 0)
|
||||||
|
[1] Class: ClassB (size: 0)
|
||||||
|
Param
|
||||||
|
[0]
|
||||||
|
)",
|
||||||
|
R"(
|
||||||
|
[0] Class: ClassA (size: 0)
|
||||||
|
Member: x (offset: 0)
|
||||||
|
[1] Class: ClassB (size: 0)
|
||||||
|
Param
|
||||||
|
[0]
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(IdentifyContainers, CycleContainer) {
|
||||||
|
test(R"(
|
||||||
|
[0] Class: ClassA (size: 0)
|
||||||
|
Member: x (offset: 0)
|
||||||
|
[1] Class: std::vector (size: 0)
|
||||||
|
Param
|
||||||
|
[0]
|
||||||
|
)",
|
||||||
|
R"(
|
||||||
|
[0] Class: ClassA (size: 0)
|
||||||
|
Member: x (offset: 0)
|
||||||
|
[2] Container: std::vector (size: 0)
|
||||||
|
Param
|
||||||
|
[0]
|
||||||
|
)");
|
||||||
|
}
|
@ -59,6 +59,30 @@ void testNoChange(type_graph::Pass pass, std::string_view input) {
|
|||||||
test(pass, input, input);
|
test(pass, input, input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<ContainerInfo>> getContainerInfos() {
|
||||||
|
auto std_vector =
|
||||||
|
std::make_unique<ContainerInfo>("std::vector", SEQ_TYPE, "vector");
|
||||||
|
std_vector->stubTemplateParams = {1};
|
||||||
|
|
||||||
|
auto std_map = std::make_unique<ContainerInfo>("std::map", SEQ_TYPE, "map");
|
||||||
|
std_map->stubTemplateParams = {2, 3};
|
||||||
|
|
||||||
|
auto std_list =
|
||||||
|
std::make_unique<ContainerInfo>("std::list", SEQ_TYPE, "list");
|
||||||
|
std_list->stubTemplateParams = {1};
|
||||||
|
|
||||||
|
auto std_pair =
|
||||||
|
std::make_unique<ContainerInfo>("std::pair", SEQ_TYPE, "list");
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<ContainerInfo>> containers;
|
||||||
|
containers.emplace_back(std::move(std_vector));
|
||||||
|
containers.emplace_back(std::move(std_map));
|
||||||
|
containers.emplace_back(std::move(std_list));
|
||||||
|
containers.emplace_back(std::move(std_pair));
|
||||||
|
|
||||||
|
return containers;
|
||||||
|
}
|
||||||
|
|
||||||
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};
|
||||||
|
@ -23,6 +23,7 @@ void test(type_graph::Pass pass,
|
|||||||
|
|
||||||
void testNoChange(type_graph::Pass pass, std::string_view input);
|
void testNoChange(type_graph::Pass pass, std::string_view input);
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<ContainerInfo>> getContainerInfos();
|
||||||
type_graph::Container getVector(type_graph::NodeId id = 0);
|
type_graph::Container getVector(type_graph::NodeId id = 0);
|
||||||
type_graph::Container getMap(type_graph::NodeId id = 0);
|
type_graph::Container getMap(type_graph::NodeId id = 0);
|
||||||
type_graph::Container getList(type_graph::NodeId id = 0);
|
type_graph::Container getList(type_graph::NodeId id = 0);
|
||||||
|
Loading…
Reference in New Issue
Block a user