From e2ec5ffee23a0141c85a19a377c2c7a4db058787 Mon Sep 17 00:00:00 2001 From: Eberhard Graether Date: Thu, 10 Jul 2014 16:08:59 +0200 Subject: [PATCH] data: compare signatures when storing overloaded functions and methods Function and method nodes are now distincted by their signature when added to the graph. A different node for each overloaded declaration is created with the signature as member field. fortune cookie message = Deine harte Arbeit wird schnell belohnt werden. --- src/lib/data/Storage.cpp | 36 ++++++++- src/lib/data/graph/Edge.cpp | 2 +- src/lib/data/graph/Edge.h | 2 +- src/lib/data/graph/Graph.cpp | 45 ++++++++++-- src/lib/data/graph/Graph.h | 2 + src/lib/data/graph/Node.cpp | 78 +++++++++++++++++--- src/lib/data/graph/Node.h | 7 ++ src/lib/data/parser/ParserClient.cpp | 106 +++++++++++++++++++++++++++ src/lib/data/parser/ParserClient.h | 20 +++++ src/test/CxxParserTestSuite.h | 84 +-------------------- src/test/GraphTestSuite.h | 7 +- 11 files changed, 283 insertions(+), 106 deletions(-) diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index efae811b..186cfe16 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -119,7 +119,11 @@ void Storage::onFunctionParsed( { log("function", fullName, location); - Node* node = m_graph.createNodeHierarchy(fullName); // Todo: compare signatures in case of overloading. + Node* node = m_graph.createNodeHierarchyWithDistinctSignature( + fullName, + ParserClient::functionSignatureStr(returnType, fullName, parameters, false) + ); + node->setType(Node::NODE_FUNCTION); Edge* returnTypeEdge = m_graph.createEdge( @@ -130,12 +134,22 @@ void Storage::onFunctionParsed( for (const ParseVariable& parameter : parameters) { Edge* parameterEdge = m_graph.createEdge( - Edge::EDGE_PARAMETER_OF, node, m_graph.createNodeHierarchy(parameter.type.getRawTypeName())); + Edge::EDGE_PARAMETER_TYPE_OF, node, m_graph.createNodeHierarchy(parameter.type.getRawTypeName())); parameterEdge->addComponent(std::make_shared( parameter.type.getQualifierList(), parameter.type.getModifierStack())); } addTokenLocation(node, location); + + // TODO: move this into suitable TestSuite + if (node->getSignature() != ParserClient::functionSignatureStr(returnType, fullName, parameters, false)) + { + std::stringstream ss; + ss << "Parsed and saved signatures don't match: "; + ss << node->getSignature() << " - "; + ss << ParserClient::functionSignatureStr(returnType, fullName, parameters, false); + LOG_ERROR(ss.str()); + } } void Storage::onMethodParsed( @@ -146,7 +160,11 @@ void Storage::onMethodParsed( { log("method", fullName, location); - Node* node = m_graph.createNodeHierarchy(fullName); // Todo: compare signatures in case of overloading. + Node* node = m_graph.createNodeHierarchyWithDistinctSignature( + fullName, + ParserClient::functionSignatureStr(returnType, fullName, parameters, isConst) + ); + node->setType(Node::NODE_METHOD); node->setConst(isConst); node->setStatic(isStatic); @@ -166,12 +184,22 @@ void Storage::onMethodParsed( for (const ParseVariable& parameter : parameters) { Edge* parameterEdge = m_graph.createEdge( - Edge::EDGE_PARAMETER_OF, node, m_graph.createNodeHierarchy(parameter.type.getRawTypeName())); + Edge::EDGE_PARAMETER_TYPE_OF, node, m_graph.createNodeHierarchy(parameter.type.getRawTypeName())); parameterEdge->addComponent(std::make_shared( parameter.type.getQualifierList(), parameter.type.getModifierStack())); } addTokenLocation(node, location); + + // TODO: move this into suitable TestSuite + if (node->getSignature() != ParserClient::functionSignatureStr(returnType, fullName, parameters, isConst)) + { + std::stringstream ss; + ss << "Parsed and saved signatures don't match: "; + ss << node->getSignature() << " - "; + ss << ParserClient::functionSignatureStr(returnType, fullName, parameters, isConst); + LOG_ERROR(ss.str()); + } } void Storage::onNamespaceParsed(const ParseLocation& location, const std::string& fullName) diff --git a/src/lib/data/graph/Edge.cpp b/src/lib/data/graph/Edge.cpp index 9ee7de19..11a10636 100644 --- a/src/lib/data/graph/Edge.cpp +++ b/src/lib/data/graph/Edge.cpp @@ -97,7 +97,7 @@ std::string Edge::getTypeString() const return "is type of"; case EDGE_RETURN_TYPE_OF: return "has return type"; - case EDGE_PARAMETER_OF: + case EDGE_PARAMETER_TYPE_OF: return "has parameter of type"; case EDGE_INHERITANCE: return "is derived from"; diff --git a/src/lib/data/graph/Edge.h b/src/lib/data/graph/Edge.h index 7805ce1f..d1babb95 100644 --- a/src/lib/data/graph/Edge.h +++ b/src/lib/data/graph/Edge.h @@ -17,7 +17,7 @@ public: EDGE_MEMBER, EDGE_TYPE_OF, EDGE_RETURN_TYPE_OF, - EDGE_PARAMETER_OF, + EDGE_PARAMETER_TYPE_OF, EDGE_USAGE, EDGE_CALL, EDGE_INHERITANCE diff --git a/src/lib/data/graph/Graph.cpp b/src/lib/data/graph/Graph.cpp index 768db2cd..28ed0b6e 100644 --- a/src/lib/data/graph/Graph.cpp +++ b/src/lib/data/graph/Graph.cpp @@ -74,6 +74,27 @@ Node* Graph::createNodeHierarchy(const std::string& fullName) return insertNodeHierarchy(fullName); } +Node* Graph::createNodeHierarchyWithDistinctSignature(const std::string& fullName, const std::string& signature) +{ + Node* node = getNode(fullName); + if (node) + { + if (node->getSignature() == signature) + { + return node; + } + + node = insertNode(fullName, node->getParentNode()); + } + else + { + node = insertNodeHierarchy(fullName); + } + + node->setSignature(signature); + return node; +} + Edge* Graph::createEdge(Edge::EdgeType type, Node* from, Node* to) { Edge* edge = getEdge(type, from, to); @@ -288,14 +309,7 @@ Node* Graph::insertNodeHierarchy(const std::string& fullName) if (!childNode) { - std::shared_ptr childNodePtr = std::make_shared(Node::NODE_UNDEFINED, name); - m_nodes.push_back(childNodePtr); - childNode = childNodePtr.get(); - - if (node) - { - createEdge(Edge::EDGE_MEMBER, node, childNode); - } + childNode = insertNode(name, node); } node = childNode; @@ -304,6 +318,21 @@ Node* Graph::insertNodeHierarchy(const std::string& fullName) return node; } +Node* Graph::insertNode(const std::string& fullName, Node* parentNode) +{ + std::shared_ptr nodePtr = std::make_shared(Node::NODE_UNDEFINED, fullName); + m_nodes.push_back(nodePtr); + + Node* node = nodePtr.get(); + + if (parentNode) + { + createEdge(Edge::EDGE_MEMBER, parentNode, node); + } + + return node; +} + Edge* Graph::insertEdge(Edge::EdgeType type, Node* from, Node* to) { std::shared_ptr edgePtr = std::make_shared(type, from, to); diff --git a/src/lib/data/graph/Graph.h b/src/lib/data/graph/Graph.h index f6dacd96..4b64a548 100644 --- a/src/lib/data/graph/Graph.h +++ b/src/lib/data/graph/Graph.h @@ -22,6 +22,7 @@ public: Token* getTokenById(Id id) const; Node* createNodeHierarchy(const std::string& fullName); + Node* createNodeHierarchyWithDistinctSignature(const std::string& fullName, const std::string& signature); Edge* createEdge(Edge::EdgeType type, Node* from, Node* to); void removeNode(Node* node); @@ -48,6 +49,7 @@ private: static const std::string DELIMITER; Node* insertNodeHierarchy(const std::string& fullName); + Node* insertNode(const std::string& fullName, 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 00ab9850..75de53b6 100644 --- a/src/lib/data/graph/Node.cpp +++ b/src/lib/data/graph/Node.cpp @@ -2,6 +2,8 @@ #include +// #include "data/graph/edgeComponent/EdgeComponentDataType.h" +// #include "data/type/DataType.h" #include "utility/logging/logging.h" Node::Node(NodeType type, const std::string& name) @@ -62,24 +64,24 @@ void Node::removeEdge(Edge* edge) m_edges.erase(find(m_edges.begin(), m_edges.end(), edge)); } +Node* Node::getParentNode() const +{ + Edge* edge = getMemberEdge(); + if (edge) + { + return edge->getFrom(); + } + return nullptr; +} + Edge* Node::getMemberEdge() const { - Edge* edge = findEdgeOfType(Edge::EDGE_MEMBER, + return findEdgeOfType(Edge::EDGE_MEMBER, [this](Edge* e) { return e->getTo() == this; } ); - - if (edge) - { - return edge; - } - else - { - LOG_WARNING("Child edge was not found, node " + getName() + " has no parent node."); - return nullptr; - } } Edge* Node::findEdge(std::function func) const @@ -94,6 +96,11 @@ Edge* Node::findEdge(std::function func) const return NULL; } +Edge* Node::findEdgeOfType(Edge::EdgeType type) const +{ + return findEdgeOfType(type, [](Edge* e){ return true; }); +} + Edge* Node::findEdgeOfType(Edge::EdgeType type, std::function func) const { std::vector::const_iterator it = find_if(m_edges.begin(), m_edges.end(), @@ -188,6 +195,55 @@ void Node::setStatic(bool isStatic) m_isStatic = isStatic; } +std::string Node::getSignature() const +{ + // Signature generation from edges failed, because parameter edges to same type are bundled. + // std::string str; + + // Edge* returnTypeEdge = findEdgeOfType(Edge::EDGE_RETURN_TYPE_OF); + // str += returnTypeEdge->getComponent()->getDataType().getFullTypeName() + " " + m_name + "("; + + // forEachEdgeOfType(Edge::EDGE_PARAMETER_TYPE_OF, + // [&str](Edge* edge) + // { + // str += edge->getComponent()->getDataType().getFullTypeName() + ", "; + // } + // ); + + // if (*str.rbegin() == ' ') + // { + // str.pop_back(); + // str.pop_back(); + // } + // str += ")"; + + // if (isConst()) + // { + // str += " const"; + // } + + // return str; + + return m_signature; +} + +void Node::setSignature(const std::string& signature) +{ + if (m_type != NODE_FUNCTION && m_type != NODE_METHOD && m_type != NODE_UNDEFINED) + { + LOG_ERROR("Signature is not supported on node of type " + getTypeString(m_type)); + return; + } + + if (m_signature.size()) + { + LOG_ERROR("Signature was already set before."); + return; + } + + m_signature = signature; +} + std::string Node::getTypeString(NodeType type) const { switch (type) diff --git a/src/lib/data/graph/Node.h b/src/lib/data/graph/Node.h index dc2b471d..ba236a41 100644 --- a/src/lib/data/graph/Node.h +++ b/src/lib/data/graph/Node.h @@ -39,9 +39,11 @@ public: void addEdge(Edge* edge); void removeEdge(Edge* edge); + Node* getParentNode() const; Edge* getMemberEdge() const; Edge* findEdge(std::function func) const; + Edge* findEdgeOfType(Edge::EdgeType type) const; Edge* findEdgeOfType(Edge::EdgeType type, std::function func) const; void forEachEdge(std::function func) const; @@ -60,6 +62,9 @@ public: bool isStatic() const; void setStatic(bool isStatic); + std::string getSignature() const; + void setSignature(const std::string& signature); + // Logging. std::string getTypeString(NodeType type) const; std::string getAsString() const; @@ -76,6 +81,8 @@ private: // Additional fields for different NodeTypes. bool m_isConst; bool m_isStatic; + + std::string m_signature; }; std::ostream& operator<<(std::ostream& ostream, const Node& node); diff --git a/src/lib/data/parser/ParserClient.cpp b/src/lib/data/parser/ParserClient.cpp index 9bebea4c..bf0e89cc 100644 --- a/src/lib/data/parser/ParserClient.cpp +++ b/src/lib/data/parser/ParserClient.cpp @@ -1,5 +1,111 @@ #include "data/parser/ParserClient.h" +#include + +#include "data/parser/ParseLocation.h" +#include "data/parser/ParseVariable.h" +#include "data/type/DataType.h" + +std::string ParserClient::addAccessPrefix(const std::string& str, AccessType access) +{ + switch (access) + { + case ACCESS_PUBLIC: + return "public " + str; + case ACCESS_PROTECTED: + return "protected " + str; + case ACCESS_PRIVATE: + return "private " + str; + case ACCESS_NONE: + return str; + } +} + +std::string ParserClient::addAbstractionPrefix(const std::string& str, AbstractionType abstraction) +{ + switch (abstraction) + { + case ABSTRACTION_VIRTUAL: + return "virtual " + str; + case ABSTRACTION_PURE_VIRTUAL: + return "pure virtual " + str; + case ABSTRACTION_NONE: + return str; + } +} + +std::string ParserClient::addStaticPrefix(const std::string& str, bool isStatic) +{ + if (isStatic) + { + return "static " + str; + } + return str; +} + +std::string ParserClient::addConstPrefix(const std::string& str, bool isConst, bool atFront) +{ + if (isConst) + { + return atFront ? "const " + str : str + " const"; + } + return str; +} + +std::string ParserClient::addLocationSuffix(const std::string& str, const ParseLocation& location) +{ + std::stringstream ss; + ss << str << " <" << location.startLineNumber << ":" << location.startColumnNumber << " "; + ss << location.endLineNumber << ":" << location.endColumnNumber << ">"; + return ss.str(); +} + +std::string ParserClient::variableStr(const ParseVariable& variable, bool withName) +{ + std::string str = variable.type.getFullTypeName(); + if (withName) + { + str += " " + variable.fullName; + } + return addStaticPrefix(str, variable.isStatic); +} + +std::string ParserClient::parameterStr(const std::vector parameters, bool withName) +{ + std::string str = "("; + for (size_t i = 0; i < parameters.size(); i++) + { + str += variableStr(parameters[i], withName); + if (i < parameters.size() - 1) + { + str += ", "; + } + } + return str + ")"; +} + +std::string ParserClient::functionStr( + const DataType& returnType, + const std::string& fullName, + const std::vector& parameters, + bool isConst +){ + return addConstPrefix( + returnType.getFullTypeName() + " " + fullName + parameterStr(parameters), + isConst, + false + ); +} + +std::string ParserClient::functionSignatureStr( + const DataType& returnType, + const std::string& fullName, + const std::vector& parameters, + bool isConst +){ + return addConstPrefix(fullName + parameterStr(parameters, false), isConst, false); +} + ParserClient::ParserClient() { } diff --git a/src/lib/data/parser/ParserClient.h b/src/lib/data/parser/ParserClient.h index 851ffc95..c38692bd 100644 --- a/src/lib/data/parser/ParserClient.h +++ b/src/lib/data/parser/ParserClient.h @@ -24,6 +24,26 @@ public: ABSTRACTION_NONE }; + static std::string addAccessPrefix(const std::string& str, AccessType access); + static std::string addAbstractionPrefix(const std::string& str, AbstractionType abstraction); + static std::string addStaticPrefix(const std::string& str, bool isStatic); + static std::string addConstPrefix(const std::string& str, bool isConst, bool atFront); + static std::string addLocationSuffix(const std::string& str, const ParseLocation& location); + static std::string variableStr(const ParseVariable& variable, bool withName = true); + static std::string parameterStr(const std::vector parameters, bool withName = true); + static std::string functionStr( + const DataType& returnType, + const std::string& fullName, + const std::vector& parameters, + bool isConst + ); + static std::string functionSignatureStr( + const DataType& returnType, + const std::string& fullName, + const std::vector& parameters, + bool isConst + ); + ParserClient(); virtual ~ParserClient(); diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index 83528503..b6742ff4 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -732,9 +732,8 @@ private: virtual void onFunctionParsed( const ParseLocation& location, const std::string& fullName, const DataType& returnType, const std::vector& parameters - ) - { - std::string str = returnType.getFullTypeName() + " " + fullName + parameterStr(parameters); + ){ + std::string str = functionStr(returnType, fullName, parameters, false); functions.push_back(addLocationSuffix(str, location)); } @@ -744,9 +743,9 @@ private: bool isConst, bool isStatic ) { - std::string str = returnType.getFullTypeName() + " " + fullName + parameterStr(parameters); + std::string str = functionStr(returnType, fullName, parameters, isConst); str = addStaticPrefix(addAbstractionPrefix(str, abstraction), isStatic); - str = addConstPrefix(addAccessPrefix(str, access), isConst, false); + str = addAccessPrefix(str, access); str = addLocationSuffix(str, location); methods.push_back(str); } @@ -791,81 +790,6 @@ private: std::vector structs; std::vector inheritances; std::vector calls; - - private: - std::string addAccessPrefix(const std::string& str, AccessType access) - { - switch (access) - { - case ACCESS_PUBLIC: - return "public " + str; - case ACCESS_PROTECTED: - return "protected " + str; - case ACCESS_PRIVATE: - return "private " + str; - case ACCESS_NONE: - return str; - } - } - - std::string addAbstractionPrefix(const std::string& str, AbstractionType abstraction) - { - switch (abstraction) - { - case ABSTRACTION_VIRTUAL: - return "virtual " + str; - case ABSTRACTION_PURE_VIRTUAL: - return "pure virtual " + str; - case ABSTRACTION_NONE: - return str; - } - } - - std::string addStaticPrefix(const std::string& str, bool isStatic) - { - if (isStatic) - { - return "static " + str; - } - return str; - } - - std::string addConstPrefix(const std::string& str, bool isConst, bool atFront) - { - if (isConst) - { - return atFront ? "const " + str : str + " const"; - } - return str; - } - - std::string variableStr(const ParseVariable& variable) - { - std::string str = variable.type.getFullTypeName() + " " + variable.fullName; - return addStaticPrefix(str, variable.isStatic); - } - - std::string parameterStr(const std::vector parameters) - { - std::string str = "("; - for (size_t i = 0; i < parameters.size(); i++) - { - str += variableStr(parameters[i]); - if (i < parameters.size() - 1) - { - str += ", "; - } - } - return str + ")"; - } - - std::string addLocationSuffix(const std::string& str, const ParseLocation& location) - { - std::stringstream ss; - ss << str << " <" << location.startLineNumber << ":" << location.startColumnNumber << " "; - ss << location.endLineNumber << ":" << location.endColumnNumber << ">"; - return ss.str(); - } }; std::shared_ptr parseCode(std::string code) const diff --git a/src/test/GraphTestSuite.h b/src/test/GraphTestSuite.h index e16c8f99..9145c8d8 100644 --- a/src/test/GraphTestSuite.h +++ b/src/test/GraphTestSuite.h @@ -105,7 +105,12 @@ public: TS_ASSERT_EQUALS(2, graph.getNodeCount()); TS_ASSERT_EQUALS(1, graph.getEdgeCount()); + TS_ASSERT(ab->getMemberEdge()); TS_ASSERT(graph.getEdge(Edge::EDGE_MEMBER, a, ab)); + TS_ASSERT_EQUALS(ab->getMemberEdge(), graph.getEdge(Edge::EDGE_MEMBER, a, ab)); + TS_ASSERT_EQUALS(ab->getMemberEdge()->getFrom(), a); + TS_ASSERT_EQUALS(ab->getMemberEdge()->getTo(), ab); + TS_ASSERT_EQUALS(ab->getParentNode(), a); } void test_graph_removes_nodes() @@ -161,7 +166,7 @@ public: TS_ASSERT(graph.getNode("A::C")); } - void test_graph_creates_multiple_nodes_as_type_nodes() + void test_graph_creates_multiple_nodes_as_undefined_nodes() { TestGraph graph; Node* abc = graph.createNodeHierarchy("A::B::C");