diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index 808f31ab..391b548a 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -238,26 +238,23 @@ void Storage::onGlobalVariableUsageParsed( addTokenLocation(edge, location); } -Id Storage::getIdForNodeWithName(const std::string& name) const +Id Storage::getIdForNodeWithName(const std::string& fullName) const { - Node* node = m_graph.findNode([&](Node* node){ - return node->getName() == name; - }); - + Node* node = m_graph.getNode(fullName); return (node ? node->getId() : 0); } std::string Storage::getNameForNodeWithId(Id id) const { Node* node = m_graph.getNodeById(id); - return (node ? node->getName() : ""); + return (node ? node->getFullName() : ""); } std::vector Storage::getNamesForNodesWithNamePrefix(const std::string& prefix) const { std::vector names; m_graph.forEachNode([&](Node* node){ - const std::string& nodeName = node->getName(); + const std::string& nodeName = node->getFullName(); if (utility::isPrefix(prefix, nodeName)) { names.push_back(nodeName); diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index 4e45deac..681ee4ea 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -64,7 +64,7 @@ public: const ParseLocation& location, const std::string& userName, const std::string& usedName); // GraphAccess implementation - virtual Id getIdForNodeWithName(const std::string& name) const; + virtual Id getIdForNodeWithName(const std::string& fullName) const; virtual std::string getNameForNodeWithId(Id id) const; virtual std::vector getNamesForNodesWithNamePrefix(const std::string& prefix) const; virtual std::vector getIdsOfNeighbours(const Id id) const; diff --git a/src/lib/data/graph/Graph.cpp b/src/lib/data/graph/Graph.cpp index 0a679360..e9a83904 100644 --- a/src/lib/data/graph/Graph.cpp +++ b/src/lib/data/graph/Graph.cpp @@ -16,12 +16,15 @@ Graph::~Graph() Node* Graph::getNode(const std::string& fullName) const { - return findNode( - [fullName](Node* n) - { - return n->getName() == fullName; - } - ); + std::deque names = utility::split>(fullName, DELIMITER); + Node* node = getLastValidNode(&names); + + if (node && !names.size()) + { + return node; + } + + return nullptr; } Edge* Graph::getEdge(Edge::EdgeType type, Node* from, Node* to) const @@ -71,8 +74,9 @@ Node* Graph::createNodeHierarchy(const std::string& fullName) Node* Graph::createNodeHierarchy(Node::NodeType type, const std::string& fullName) { - Node* node = getNode(fullName); - if (node) + std::deque names = utility::split>(fullName, DELIMITER); + Node* node = getLastValidNode(&names); + if (node && !names.size()) { if (type != Node::NODE_UNDEFINED) { @@ -81,7 +85,7 @@ Node* Graph::createNodeHierarchy(Node::NodeType type, const std::string& fullNam return node; } - return insertNodeHierarchy(type, fullName); + return insertNodeHierarchy(type, names, node); } Node* Graph::createNodeHierarchyWithDistinctSignature(const std::string& fullName, const std::string& signature) @@ -92,10 +96,12 @@ Node* Graph::createNodeHierarchyWithDistinctSignature(const std::string& fullNam Node* Graph::createNodeHierarchyWithDistinctSignature( Node::NodeType type, const std::string& fullName, const std::string& signature ){ - Node* node = getNode(fullName); - if (node) + std::deque names = utility::split>(fullName, DELIMITER); + Node* node = getLastValidNode(&names); + if (node && !names.size()) { - if (node->getComponent()->getSignature() == signature) + TokenComponentSignature* sigComponent = node->getComponent(); + if (sigComponent && sigComponent->getSignature() == signature) { if (type != Node::NODE_UNDEFINED) { @@ -104,11 +110,35 @@ Node* Graph::createNodeHierarchyWithDistinctSignature( return node; } - node = insertNode(type, fullName, node->getParentNode()); + Node* parentNode = node->getParentNode(); + const std::string& name = node->getName(); + + std::function findSignature = + [&name, &signature](Node* n) + { + TokenComponentSignature* c = n->getComponent(); + return n->getName() == name && c && c->getSignature() == signature; + }; + + if (parentNode) + { + node = parentNode->findChildNode(findSignature); + } + else + { + node = findNode(findSignature); + } + + if (node) + { + return node; + } + + node = insertNode(type, name, parentNode); } else { - node = insertNodeHierarchy(type, fullName); + node = insertNodeHierarchy(type, names, node); } node->addComponentSignature(std::make_shared(signature)); @@ -311,43 +341,60 @@ Edge* Graph::addEdgeAsPlainCopy(Edge* edge) const std::string Graph::DELIMITER = "::"; -Node* Graph::insertNodeHierarchy(Node::NodeType type, const std::string& fullName) +Node* Graph::getLastValidNode(std::deque* names) const { - Node* node = nullptr; - std::vector names = utility::split(fullName, DELIMITER); - std::string name; + const std::string& name = names->front(); - for (size_t i = 0; i < names.size(); i++) - { - if (i > 0) + Node* node = findNode( + [&name](Node* n) { - name += DELIMITER; + return n->getName() == name && n->getParentNode() == nullptr; } - name += names[i]; + ); - Node* childNode = getNode(name); + if (!node) + { + return nullptr; + } + + names->pop_front(); + + while (names->size()) + { + const std::string& name = names->front(); + Node* childNode = node->findChildNode( + [&name](Node* n) + { + return n->getName() == name; + } + ); if (!childNode) { - if (i == names.size() - 1) - { - childNode = insertNode(type, name, node); - } - else - { - childNode = insertNode(Node::NODE_UNDEFINED, name, node); - } + break; } node = childNode; + names->pop_front(); } return node; } -Node* Graph::insertNode(Node::NodeType type, const std::string& fullName, Node* parentNode) +Node* Graph::insertNodeHierarchy(Node::NodeType type, std::deque names, Node* parentNode) { - std::shared_ptr nodePtr = std::make_shared(type, fullName); + while (names.size()) + { + parentNode = insertNode(names.size() == 1 ? type : Node::NODE_UNDEFINED, names.front(), parentNode); + names.pop_front(); + } + + return parentNode; +} + +Node* Graph::insertNode(Node::NodeType type, const std::string& name, Node* parentNode) +{ + std::shared_ptr nodePtr = std::make_shared(type, name); m_nodes.push_back(nodePtr); Node* node = nodePtr.get(); diff --git a/src/lib/data/graph/Graph.h b/src/lib/data/graph/Graph.h index fb264e6a..a72f4d88 100644 --- a/src/lib/data/graph/Graph.h +++ b/src/lib/data/graph/Graph.h @@ -2,8 +2,9 @@ #define GRAPH_H #include -#include #include +#include +#include #include "data/graph/Edge.h" #include "data/graph/Node.h" @@ -54,8 +55,9 @@ protected: private: static const std::string DELIMITER; - Node* insertNodeHierarchy(Node::NodeType type, const std::string& fullName); - Node* insertNode(Node::NodeType type, const std::string& fullName, Node* parentNode); + Node* getLastValidNode(std::deque* names) const; + Node* insertNodeHierarchy(Node::NodeType type, std::deque names, Node* parentNode); + Node* insertNode(Node::NodeType type, const std::string& name, Node* parentNode); Edge* insertEdge(Edge::EdgeType type, Node* from, Node* to); void removeEdgeInternal(Edge* edge); diff --git a/src/lib/data/graph/Node.cpp b/src/lib/data/graph/Node.cpp index ce91d567..f81443cf 100644 --- a/src/lib/data/graph/Node.cpp +++ b/src/lib/data/graph/Node.cpp @@ -46,6 +46,19 @@ const std::string& Node::getName() const return m_name; } +std::string Node::getFullName() const +{ + Node* parent = getParentNode(); + if (parent) + { + return parent->getFullName() + "::" + m_name; + } + else + { + return m_name; + } +} + const std::vector& Node::getEdges() const { return m_edges; @@ -90,7 +103,7 @@ Edge* Node::findEdge(std::function func) const return *it; } - return NULL; + return nullptr; } Edge* Node::findEdgeOfType(Edge::EdgeType type) const @@ -116,7 +129,28 @@ Edge* Node::findEdgeOfType(Edge::EdgeType type, std::function func) return *it; } - return NULL; + return nullptr; +} + +Node* Node::findChildNode(std::function func) const +{ + std::vector::const_iterator it = find_if(m_edges.begin(), m_edges.end(), + [&func](Edge* e) + { + if (e->getType() == Edge::EDGE_MEMBER) + { + return func(e->getTo()); + } + return false; + } + ); + + if (it != m_edges.end()) + { + return (*it)->getTo(); + } + + return nullptr; } void Node::forEachEdge(std::function func) const @@ -137,6 +171,16 @@ void Node::forEachEdgeOfType(Edge::EdgeType type, std::function fun ); } +void Node::forEachChildNode(std::function func) const +{ + forEachEdgeOfType(Edge::EDGE_MEMBER, + [func](Edge* e) + { + func(e->getTo()); + } + ); +} + bool Node::isNode() const { return true; diff --git a/src/lib/data/graph/Node.h b/src/lib/data/graph/Node.h index dcfc9d5c..19af8ecd 100644 --- a/src/lib/data/graph/Node.h +++ b/src/lib/data/graph/Node.h @@ -38,6 +38,8 @@ public: void setType(NodeType type); const std::string& getName() const; + std::string getFullName() const; + const std::vector& getEdges() const; void addEdge(Edge* edge); @@ -49,9 +51,11 @@ public: Edge* findEdge(std::function func) const; Edge* findEdgeOfType(Edge::EdgeType type) const; Edge* findEdgeOfType(Edge::EdgeType type, std::function func) const; + Node* findChildNode(std::function func) const; void forEachEdge(std::function func) const; void forEachEdgeOfType(Edge::EdgeType type, std::function func) const; + void forEachChildNode(std::function func) const; // Token implementation. virtual bool isNode() const; diff --git a/src/lib/utility/utilityString.cpp b/src/lib/utility/utilityString.cpp index ec1a9119..84d17e79 100644 --- a/src/lib/utility/utilityString.cpp +++ b/src/lib/utility/utilityString.cpp @@ -2,28 +2,6 @@ namespace utility { - std::vector split(const std::string& str, char delimiter) - { - return split(str, std::string(1, delimiter)); - } - - std::vector split(const std::string& str, const std::string& delimiter) - { - size_t pos = 0; - size_t oldPos = 0; - std::vector vec; - - do - { - pos = str.find(delimiter, oldPos); - vec.push_back(str.substr(oldPos, pos - oldPos)); - oldPos = pos + delimiter.size(); - } - while (pos != std::string::npos); - - return vec; - } - bool isPrefix(const std::string& prefix, const std::string& text) { typedef std::pair ResType; diff --git a/src/lib/utility/utilityString.h b/src/lib/utility/utilityString.h index 884ef726..185e5c1b 100644 --- a/src/lib/utility/utilityString.h +++ b/src/lib/utility/utilityString.h @@ -6,10 +6,37 @@ namespace utility { - std::vector split(const std::string& str, char delimiter); - std::vector split(const std::string& str, const std::string& delimiter); + template> + ContainerType split(const std::string& str, char delimiter); + + template> + ContainerType split(const std::string& str, const std::string& delimiter); bool isPrefix(const std::string& prefix, const std::string& text); } +template +ContainerType utility::split(const std::string& str, char delimiter) +{ + return split(str, std::string(1, delimiter)); +} + +template +ContainerType utility::split(const std::string& str, const std::string& delimiter) +{ + size_t pos = 0; + size_t oldPos = 0; + ContainerType c; + + do + { + pos = str.find(delimiter, oldPos); + c.push_back(str.substr(oldPos, pos - oldPos)); + oldPos = pos + delimiter.size(); + } + while (pos != std::string::npos); + + return c; +} + #endif // UTILITY_STRING_H diff --git a/src/test/GraphTestSuite.h b/src/test/GraphTestSuite.h index 1b9239af..a8b764cd 100644 --- a/src/test/GraphTestSuite.h +++ b/src/test/GraphTestSuite.h @@ -169,6 +169,64 @@ public: TS_ASSERT_EQUALS(e.getType(), e2.getType()); } + void test_node_finds_child_node() + { + Node a(Node::NODE_UNDEFINED, "A"); + Node b(Node::NODE_UNDEFINED, "B"); + Node c(Node::NODE_UNDEFINED, "C"); + Edge e(Edge::EDGE_MEMBER, &a, &b); + Edge e2(Edge::EDGE_MEMBER, &a, &c); + + Node* x = a.findChildNode( + [](Node* n) + { + return n->getName() == "C"; + } + ); + + TS_ASSERT_EQUALS(x, &c); + TS_ASSERT_DIFFERS(x, &b); + } + + void test_node_can_not_find_child_node() + { + Node a(Node::NODE_UNDEFINED, "A"); + Node b(Node::NODE_UNDEFINED, "B"); + Node c(Node::NODE_UNDEFINED, "C"); + Edge e(Edge::EDGE_MEMBER, &a, &b); + Edge e2(Edge::EDGE_MEMBER, &a, &c); + + Node* x = a.findChildNode( + [](Node* n) + { + return n->getName() == "D"; + } + ); + + TS_ASSERT(!x); + } + + void test_node_visits_child_nodes() + { + Node a(Node::NODE_UNDEFINED, "A"); + Node b(Node::NODE_UNDEFINED, "B"); + Node c(Node::NODE_UNDEFINED, "C"); + Edge e(Edge::EDGE_MEMBER, &a, &b); + Edge e2(Edge::EDGE_MEMBER, &a, &c); + + std::vector children; + a.forEachChildNode( + [&children](Node* n) + { + return children.push_back(n); + } + ); + + TS_ASSERT_EQUALS(children.size(), 2); + TS_ASSERT_EQUALS(children[0], &b); + TS_ASSERT_EQUALS(children[1], &c); + } + void test_graph_saves_nodes() { TestGraph graph; @@ -284,6 +342,42 @@ public: TS_ASSERT(graph.getNode("A::C")); } + void test_node_in_graph_finds_child_node() + { + TestGraph graph; + Node* a = graph.createNodeHierarchy("A"); + Node* b = graph.createNodeHierarchy("A::B"); + Node* c = graph.createNodeHierarchy("A::C"); + + Node* x = a->findChildNode( + [](Node* n) + { + return n->getName() == "C"; + } + ); + + TS_ASSERT_EQUALS(x, c); + TS_ASSERT_DIFFERS(x, b); + } + + void test_graph_saves_nodes_with_distinct_signatures() + { + TestGraph graph; + Node* a1 = graph.createNodeHierarchyWithDistinctSignature(Node::NODE_FUNCTION, "A", "A1"); + Node* a2 = graph.createNodeHierarchyWithDistinctSignature(Node::NODE_FUNCTION, "A", "A2"); + Node* a3 = graph.createNodeHierarchyWithDistinctSignature(Node::NODE_FUNCTION, "A", "A2"); + + TS_ASSERT_DIFFERS(a1, a2); + TS_ASSERT_EQUALS(a2, a3); + + Node* c1 = graph.createNodeHierarchyWithDistinctSignature(Node::NODE_METHOD, "B::C", "C1"); + Node* c2 = graph.createNodeHierarchyWithDistinctSignature(Node::NODE_METHOD, "B::C", "C2"); + Node* c3 = graph.createNodeHierarchyWithDistinctSignature(Node::NODE_METHOD, "B::C", "C2"); + + TS_ASSERT_DIFFERS(c1, c2); + TS_ASSERT_EQUALS(c2, c3); + } + void test_graph_creates_multiple_nodes_as_undefined_nodes() { TestGraph graph; @@ -295,11 +389,11 @@ public: TS_ASSERT_EQUALS("A", graph.getNode("A")->getName()); TS_ASSERT_EQUALS(Node::NODE_UNDEFINED, graph.getNode("A")->getType()); - TS_ASSERT_EQUALS("A::B", graph.getNode("A::B")->getName()); + TS_ASSERT_EQUALS("A::B", graph.getNode("A::B")->getFullName()); TS_ASSERT_EQUALS(Node::NODE_UNDEFINED, graph.getNode("A::B")->getType()); TS_ASSERT_EQUALS(abc, graph.getNode("A::B::C")); - TS_ASSERT_EQUALS("A::B::C", graph.getNode("A::B::C")->getName()); + TS_ASSERT_EQUALS("A::B::C", graph.getNode("A::B::C")->getFullName()); TS_ASSERT_EQUALS(Node::NODE_UNDEFINED, graph.getNode("A::B::C")->getType()); Node* abcde = graph.createNodeHierarchy("A::B::C::D::E"); @@ -307,11 +401,11 @@ public: TS_ASSERT_EQUALS(5, graph.getNodeCount()); TS_ASSERT_EQUALS(4, graph.getEdgeCount()); - TS_ASSERT_EQUALS("A::B::C::D", graph.getNode("A::B::C::D")->getName()); + TS_ASSERT_EQUALS("A::B::C::D", graph.getNode("A::B::C::D")->getFullName()); TS_ASSERT_EQUALS(Node::NODE_UNDEFINED, graph.getNode("A::B::C::D")->getType()); TS_ASSERT_EQUALS(abcde, graph.getNode("A::B::C::D::E")); - TS_ASSERT_EQUALS("A::B::C::D::E", graph.getNode("A::B::C::D::E")->getName()); + TS_ASSERT_EQUALS("A::B::C::D::E", graph.getNode("A::B::C::D::E")->getFullName()); TS_ASSERT_EQUALS(Node::NODE_UNDEFINED, graph.getNode("A::B::C::D::E")->getType()); }