logic: add storage transformation to merge anonymous types and the respective typedef

* moved storage related classes to data/storage folder
* implemented recording c++ unions as NODE_UNION instead of just using NODE_TYPE
* added transformation to merge anonymous classes/structs/enums/unions and typedef nodes
* added tests for this transformation
* added setting for enabling/disabling this transformation
This commit is contained in:
malte_langkabel
2017-07-18 15:14:43 +02:00
parent e536f20e36
commit cad595a32c
76 changed files with 524 additions and 96 deletions
+1
View File
@@ -28,6 +28,7 @@ add_files(
SqliteBookmarkStorageTestSuite.h
SqliteIndexStorageTestSuite.h
StorageTestSuite.h
StorageTransformationAnonymousTypedefTestSuite.h
TaskSchedulerTestSuite.h
TextAccessTestSuite.h
UtilityStringTestSuite.h
+17 -1
View File
@@ -292,6 +292,21 @@ public:
TS_ASSERT_DIFFERS(utility::substrBeforeLast(client->fields[0], '<'), utility::substrBeforeLast(client->fields[1], '<'));
}
void test_cxx_parser_finds_anonymous_union_declaration()
{
std::shared_ptr<TestParserClient> client = parseCode(
"typedef union\n"
"{\n"
" int i;\n"
" float f;\n"
"} Foo;\n"
);
TS_ASSERT(utility::containsElement<std::string>(
client->unions, "anonymous union (input.cc<1:9>) <1:9 <1:9 1:13> 5:1>"
));
}
void test_cxx_parser_finds_enum_defined_in_global_namespace()
{
std::shared_ptr<TestParserClient> client = parseCode(
@@ -3325,7 +3340,8 @@ public:
"c++1z",
std::vector<FilePath>(),
std::vector<FilePath>(),
std::vector<std::string>()
std::vector<std::string>(),
false
);
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
+1 -1
View File
@@ -2,7 +2,7 @@
#include "boost/filesystem.hpp"
#include "data/SqliteBookmarkStorage.h"
#include "data/storage/sqlite/SqliteBookmarkStorage.h"
class SqliteBookmarkStorageTestSuite: public CxxTest::TestSuite
{
+1 -1
View File
@@ -2,7 +2,7 @@
#include "boost/filesystem.hpp"
#include "data/SqliteIndexStorage.h"
#include "data/storage/sqlite/SqliteIndexStorage.h"
class SqliteIndexStorageTestSuite: public CxxTest::TestSuite
{
+2 -2
View File
@@ -3,8 +3,8 @@
#include "utility/utilityString.h"
#include "data/parser/ParseLocation.h"
#include "data/IntermediateStorage.h"
#include "data/PersistentStorage.h"
#include "data/storage/IntermediateStorage.h"
#include "data/storage/PersistentStorage.h"
class StorageTestSuite: public CxxTest::TestSuite
{
@@ -0,0 +1,158 @@
#include "cxxtest/TestSuite.h"
#include "data/storage/StorageTransformationAnonymousTypedef.h"
#include "data/storage/IntermediateStorage.h"
#include "data/graph/Node.h"
#include "utility/utility.h"
class StorageTransformationAnonymousTypedefTestSuite: public CxxTest::TestSuite
{
public:
void test_transformation_removes_anonymous_class_that_has_typedef()
{
std::shared_ptr<IntermediateStorage> storage = std::make_shared<IntermediateStorage>();
Id anonymousTypeId = storage->addNode(Node::typeToInt(Node::NODE_CLASS), NameHierarchy::serialize(NameHierarchy("anonymous class (input.cc<1:9>)", NAME_DELIMITER_CXX)));
Id typedefId = storage->addNode(Node::typeToInt(Node::NODE_TYPEDEF), NameHierarchy::serialize(NameHierarchy("ClassTypedef", NAME_DELIMITER_CXX)));
storage->addEdge(Edge::typeToInt(Edge::EDGE_TYPE_USAGE), typedefId, anonymousTypeId);
StorageTransformationAnonymousTypedef::transform(storage);
const std::vector<StorageNode> nodes = storage->getStorageNodes();
std::vector<std::string> nodeNames(nodes.size());
std::transform(nodes.begin(), nodes.end(), nodeNames.begin(), [](const StorageNode& node)
{
return NameHierarchy::deserialize(node.serializedName).getQualifiedNameWithSignature();
});
TS_ASSERT_EQUALS(1, nodeNames.size());
TS_ASSERT(utility::containsElement<std::string>(
nodeNames, "ClassTypedef"
));
}
void test_transformation_redirects_incoming_edges_to_renamed_anonymous_class()
{
std::shared_ptr<IntermediateStorage> storage = std::make_shared<IntermediateStorage>();
Id anonymousTypeId = storage->addNode(Node::typeToInt(Node::NODE_CLASS), NameHierarchy::serialize(NameHierarchy("anonymous class (input.cc<1:9>)", NAME_DELIMITER_CXX)));
Id typedefId = storage->addNode(Node::typeToInt(Node::NODE_TYPEDEF), NameHierarchy::serialize(NameHierarchy("ClassTypedef", NAME_DELIMITER_CXX)));
storage->addEdge(Edge::typeToInt(Edge::EDGE_TYPE_USAGE), typedefId, anonymousTypeId);
storage->addEdge(Edge::typeToInt(Edge::EDGE_TYPE_USAGE), 42, typedefId);
StorageTransformationAnonymousTypedef::transform(storage);
Id targetNodeId = 0;
for (const StorageEdge& edge : storage->getStorageEdges())
{
if (edge.sourceNodeId == 42)
{
targetNodeId = edge.targetNodeId;
break;
}
}
std::string targetNodeName = "";
for (const StorageNode& node : storage->getStorageNodes())
{
if (node.id == targetNodeId)
{
targetNodeName = NameHierarchy::deserialize(node.serializedName).getQualifiedNameWithSignature();
break;
}
}
TS_ASSERT_EQUALS(targetNodeName, "ClassTypedef");
}
void test_transformation_keeps_outgoing_edges_of_renamed_anonymous_class()
{
std::shared_ptr<IntermediateStorage> storage = std::make_shared<IntermediateStorage>();
Id anonymousTypeId = storage->addNode(Node::typeToInt(Node::NODE_CLASS), NameHierarchy::serialize(NameHierarchy("anonymous class (input.cc<1:9>)", NAME_DELIMITER_CXX)));
Id typedefId = storage->addNode(Node::typeToInt(Node::NODE_TYPEDEF), NameHierarchy::serialize(NameHierarchy("ClassTypedef", NAME_DELIMITER_CXX)));
storage->addEdge(Edge::typeToInt(Edge::EDGE_TYPE_USAGE), typedefId, anonymousTypeId);
storage->addEdge(Edge::typeToInt(Edge::EDGE_TYPE_USAGE), anonymousTypeId, 42);
StorageTransformationAnonymousTypedef::transform(storage);
Id sourceNodeId = 0;
for (const StorageEdge& edge : storage->getStorageEdges())
{
if (edge.targetNodeId == 42)
{
sourceNodeId = edge.sourceNodeId;
break;
}
}
std::string sourceNodeName = "";
for (const StorageNode& node : storage->getStorageNodes())
{
if (node.id == sourceNodeId)
{
sourceNodeName = NameHierarchy::deserialize(node.serializedName).getQualifiedNameWithSignature();
break;
}
}
TS_ASSERT_EQUALS(sourceNodeName, "ClassTypedef");
}
void test_transformation_renames_child_node_of_anonymous_class()
{
std::shared_ptr<IntermediateStorage> storage = std::make_shared<IntermediateStorage>();
Id anonymousTypeId = storage->addNode(Node::typeToInt(Node::NODE_CLASS), NameHierarchy::serialize(NameHierarchy("anonymous class (input.cc<1:9>)", NAME_DELIMITER_CXX)));
Id typedefId = storage->addNode(Node::typeToInt(Node::NODE_TYPEDEF), NameHierarchy::serialize(NameHierarchy("ClassTypedef", NAME_DELIMITER_CXX)));
storage->addEdge(Edge::typeToInt(Edge::EDGE_TYPE_USAGE), typedefId, anonymousTypeId);
Id anonymousTypeMemberId = storage->addNode(
Node::typeToInt(Node::NODE_FIELD),
NameHierarchy::serialize(NameHierarchy(utility::createVectorFromElements<std::string>("anonymous class (input.cc<1:9>)", "field"), NAME_DELIMITER_CXX))
);
StorageTransformationAnonymousTypedef::transform(storage);
std::string memberNodeName = "";
for (const StorageNode& node : storage->getStorageNodes())
{
if (node.id == anonymousTypeMemberId)
{
memberNodeName = NameHierarchy::deserialize(node.serializedName).getQualifiedNameWithSignature();
break;
}
}
TS_ASSERT_EQUALS(memberNodeName, "ClassTypedef::field");
}
void test_transformation_does_not_rename_named_class_with_typedef_in_anonymous_namespace()
{
std::shared_ptr<IntermediateStorage> storage = std::make_shared<IntermediateStorage>();
Id typeId = storage->addNode(
Node::typeToInt(Node::NODE_CLASS),
NameHierarchy::serialize(NameHierarchy(utility::createVectorFromElements<std::string>("anonymous namespace (input.cc<1:9>)", "Type"), NAME_DELIMITER_CXX))
);
Id typedefId = storage->addNode(Node::typeToInt(Node::NODE_TYPEDEF), NameHierarchy::serialize(NameHierarchy("ClassTypedef", NAME_DELIMITER_CXX)));
storage->addEdge(Edge::typeToInt(Edge::EDGE_TYPE_USAGE), typedefId, typeId);
StorageTransformationAnonymousTypedef::transform(storage);
const std::vector<StorageNode> nodes = storage->getStorageNodes();
std::vector<std::string> nodeNames(nodes.size());
std::transform(nodes.begin(), nodes.end(), nodeNames.begin(), [](const StorageNode& node)
{
return NameHierarchy::deserialize(node.serializedName).getQualifiedNameWithSignature();
});
TS_ASSERT_EQUALS(2, nodeNames.size());
TS_ASSERT(utility::containsElement<std::string>(
nodeNames, "ClassTypedef"
));
TS_ASSERT(utility::containsElement<std::string>(
nodeNames, "anonymous namespace (input.cc<1:9>)::Type"
));
}
};
+3
View File
@@ -128,6 +128,7 @@ public:
std::vector<std::string> typedefs;
std::vector<std::string> builtinTypes;
std::vector<std::string> classes;
std::vector<std::string> unions;
std::vector<std::string> interfaces;
std::vector<std::string> enums;
std::vector<std::string> enumConstants;
@@ -171,6 +172,8 @@ private:
return &builtinTypes;
case SYMBOL_CLASS:
return &classes;
case SYMBOL_UNION:
return &unions;
case SYMBOL_INTERFACE:
return &interfaces;
case SYMBOL_ENUM: