diff --git a/src/app/qt/view/QtGraphView.cpp b/src/app/qt/view/QtGraphView.cpp index f7585901..11d67f89 100644 --- a/src/app/qt/view/QtGraphView.cpp +++ b/src/app/qt/view/QtGraphView.cpp @@ -246,7 +246,7 @@ std::shared_ptr QtGraphView::createEdge(QGraphicsView* view, const } else { - LOG_WARNING("Couldn't find owner or target node."); + LOG_WARNING_STREAM(<< "Couldn't find owner or target node for edge: " << edge.data->getName()); return NULL; } } diff --git a/src/app/qt/view/graphElements/QtGraphEdge.cpp b/src/app/qt/view/graphElements/QtGraphEdge.cpp index 9a79a37e..41a3ae85 100644 --- a/src/app/qt/view/graphElements/QtGraphEdge.cpp +++ b/src/app/qt/view/graphElements/QtGraphEdge.cpp @@ -1,68 +1,86 @@ #include "qt/view/graphElements/QtGraphEdge.h" +#include + #include #include #include #include +#include "utility/messaging/type/MessageActivateToken.h" +#include "utility/messaging/type/MessageActivateTokens.h" + #include "component/view/graphElements/GraphNode.h" +#include "data/graph/token_component/TokenComponentAggregation.h" +#include "qt/graphics/QtGraphicsRoundedRectItem.h" - -QtStraightConnection::QtStraightConnection(Vec4i ownerRect, Vec4i targetRect, QGraphicsItem* parent) +QtStraightConnection::QtStraightConnection(Vec4i ownerRect, Vec4i targetRect, int number, QGraphicsItem* parent) : QGraphicsLineItem(parent) { const Vec4i& o = ownerRect; const Vec4i& t = targetRect; - Vec2f po[2] = { Vec2f(o.x, (o.y + 2 * o.w) / 3), Vec2f(o.z, (o.y + 2 * o.w) / 3) }; - Vec2f pt[2] = { Vec2f(t.x, (2 * t.y + t.w) / 3), Vec2f(t.z, (2 * t.y + t.w) / 3) }; + Vec2f a((o.x + o.z) / 2, (o.y + o.w) / 2); + Vec2f b((t.x + t.z) / 2, (t.y + t.w) / 2); - int io = -1; - int it = -1; - float dist = -1; - - for (int i = 0; i < 2; i++) - { - for (int j = 0; j < 2; j++) - { - Vec2f diff = po[i] - pt[j]; - if (dist < 0 || diff.getLength() < dist) - { - dist = diff.getLength(); - io = i; - it = j; - } - } - } - - this->setLine(po[io].x, po[io].y, pt[it].x, pt[it].y); + this->setLine(a.x, a.y, b.x, b.y); this->setAcceptHoverEvents(true); + + Vec2f u = b - a; + u.normalize(); + + float alpha = atan2(u.y, u.x); + + Vec2f w; + w.x = (o.z - o.x) / 2 * cos(alpha); + w.y = (o.w - o.y) / 2 * sin(alpha); + a += u * w.getLength(); + + w.x = (t.z - t.x) / 2 * cos(alpha); + w.y = (t.w - t.y) / 2 * sin(alpha); + b += u * -w.getLength(); + + Vec2f mid = (a + b) / 2; + + m_circle = new QtGraphicsRoundedRectItem(this); + m_circle->setRect(mid.x - 10, mid.y - 10, 20, 20); + m_circle->setRadius(10); + m_circle->setPen(QPen(QColor("#F8F8F8"), 2)); + m_circle->setBrush(QBrush(QColor("#FFF"))); + m_circle->setAcceptHoverEvents(true); + + QFont font; + font.setFamily("Myriad Pro"); + font.setWeight(QFont::Normal); + font.setPixelSize(9); + + m_number = new QGraphicsSimpleTextItem(this); + m_number->setFont(font); + + QString numberStr = QString::number(number); + m_number->setText(numberStr); + m_number->setBrush(QBrush(QColor("#666"))); + m_number->setPos( + mid.x - QFontMetrics(m_number->font()).width(numberStr) / 2, + mid.y - QFontMetrics(m_number->font()).height() / 2 + ); } QtStraightConnection::~QtStraightConnection() { } -QPainterPath QtStraightConnection::shape() const +void QtStraightConnection::setColor(QColor color) { - QPainterPath path; - QLineF l = line(); - QLineF n = l.normalVector(); - n.setLength(5.0f); + QPen p = this->pen(); + p.setColor(color); + this->setPen(p); - qreal x = n.x2() - n.x1(); - qreal y = n.y2() - n.y1(); - - path.moveTo(l.x1() + x, l.y1() + y); - path.lineTo(l.x2() + x, l.y2() + y); - path.lineTo(l.x2() - x, l.y2() - y); - path.lineTo(l.x1() - x, l.y1() - y); - path.closeSubpath(); - - return path; + p = m_circle->pen(); + p.setColor(color); + m_circle->setPen(p); } - QtCorneredConnection::QtCorneredConnection( Vec4i ownerRect, Vec4i targetRect, Vec4i ownerParentRect, Vec4i targetParentRect, QGraphicsItem* parent ) @@ -323,7 +341,7 @@ QtGraphEdge::QtGraphEdge(const std::weak_ptr& owner, const std::weak_ , m_mouseMoved(false) { this->setAcceptHoverEvents(true); - this->setZValue(1); // Used to draw edges always on top of nodes. + this->setZValue(getZValue(false)); // Used to draw edges always on top of nodes. this->updateLine(); } @@ -358,11 +376,19 @@ void QtGraphEdge::updateLine() delete m_child; } - m_child = new QtCorneredConnection( - owner->getBoundingRect(), target->getBoundingRect(), - owner->getParentBoundingRect(), target->getParentBoundingRect(), - this - ); + if (isAggregation()) + { + m_child = + new QtStraightConnection(owner->getBoundingRect(), target->getBoundingRect(), getAggregationCount(), this); + } + else + { + m_child = new QtCorneredConnection( + owner->getBoundingRect(), target->getBoundingRect(), + owner->getParentBoundingRect(), target->getParentBoundingRect(), + this + ); + } QColor color; @@ -377,12 +403,17 @@ void QtGraphEdge::updateLine() case Edge::EDGE_INHERITANCE: color = QColor("#CC5E89"); break; + case Edge::EDGE_AGGREGATION: + color = QColor("#F8F8F8"); + break; default: color = QColor("#878787"); break; } - m_child->setPen(QPen(color, 1)); + m_child->setPen(QPen(color, getPenWidth())); + + setIsActive(m_isActive); } bool QtGraphEdge::getIsActive() const @@ -394,23 +425,47 @@ void QtGraphEdge::setIsActive(bool isActive) { m_isActive = isActive; - QPen p = m_child->pen(); if (isActive) { - p.setWidth(2); - this->setZValue(5); + if (isAggregation()) + { + dynamic_cast(m_child)->setColor(QColor("#EEE")); + } + else + { + QPen p = m_child->pen(); + p.setWidth(getPenWidth() + 1); + m_child->setPen(p); + } + this->setZValue(getZValue(isActive)); } else { - p.setWidth(1); - this->setZValue(1); + if (isAggregation()) + { + dynamic_cast(m_child)->setColor(QColor("#F8F8F8")); + } + else + { + QPen p = m_child->pen(); + p.setWidth(getPenWidth()); + m_child->setPen(p); + } + this->setZValue(getZValue(isActive)); } - m_child->setPen(p); } void QtGraphEdge::onClick() { - MessageActivateToken(getData()->getId()).dispatch(); + if (isAggregation()) + { + const std::set& ids = getData()->getComponent()->getAggregationIds(); + MessageActivateTokens(std::vector(ids.begin(), ids.end())).dispatch(); + } + else + { + MessageActivateToken(getData()->getId()).dispatch(); + } } void QtGraphEdge::mousePressEvent(QGraphicsSceneMouseEvent* event) @@ -448,3 +503,44 @@ void QtGraphEdge::hoverLeaveEvent(QGraphicsSceneHoverEvent* event) { this->setIsActive(m_isActive); } + +bool QtGraphEdge::isAggregation() const +{ + return getData()->getType() == Edge::EDGE_AGGREGATION; +} + +int QtGraphEdge::getZValue(bool active) const +{ + if (isAggregation()) + { + if (active) + { + return -1; + } + return -5; + } + + if (active) + { + return 5; + } + return 1; +} + +int QtGraphEdge::getPenWidth() const +{ + if (isAggregation()) + { + return getAggregationCount() + 1; + } + return 1; +} + +int QtGraphEdge::getAggregationCount() const +{ + if (isAggregation()) + { + return getData()->getComponent()->getAggregationCount(); + } + return 0; +} diff --git a/src/app/qt/view/graphElements/QtGraphEdge.h b/src/app/qt/view/graphElements/QtGraphEdge.h index 6091d69c..ddafab30 100644 --- a/src/app/qt/view/graphElements/QtGraphEdge.h +++ b/src/app/qt/view/graphElements/QtGraphEdge.h @@ -6,20 +6,24 @@ #include #include "utility/math/Vector2.h" -#include "utility/messaging/type/MessageActivateToken.h" #include "component/view/graphElements/GraphEdge.h" class GraphNode; +class QtGraphicsRoundedRectItem; class QtStraightConnection : public QGraphicsLineItem { public: - QtStraightConnection(Vec4i ownerRect, Vec4i targetRect, QGraphicsItem* parent); + QtStraightConnection(Vec4i ownerRect, Vec4i targetRect, int number, QGraphicsItem* parent); virtual ~QtStraightConnection(); - virtual QPainterPath shape() const; + void setColor(QColor color); + +private: + QtGraphicsRoundedRectItem* m_circle; + QGraphicsSimpleTextItem* m_number; }; class QtCorneredConnection @@ -71,6 +75,11 @@ protected: virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent* event); private: + bool isAggregation() const; + int getZValue(bool active) const; + int getPenWidth() const; + int getAggregationCount() const; + std::weak_ptr m_owner; std::weak_ptr m_target; diff --git a/src/app/qt/view/graphElements/QtGraphNode.cpp b/src/app/qt/view/graphElements/QtGraphNode.cpp index 8420007f..4a2fd615 100644 --- a/src/app/qt/view/graphElements/QtGraphNode.cpp +++ b/src/app/qt/view/graphElements/QtGraphNode.cpp @@ -161,14 +161,14 @@ Vec4i QtGraphNode::getParentBoundingRect() const bool QtGraphNode::addOutEdge(const std::shared_ptr& edge) { - for (std::list>::iterator it = m_outEdges.begin(); it != m_outEdges.end(); it++) - { - if ((*it)->getOwner().lock() == edge->getOwner().lock() && - (*it)->getTarget().lock() == edge->getTarget().lock()) - { - return false; - } - } + // for (std::list>::iterator it = m_outEdges.begin(); it != m_outEdges.end(); it++) + // { + // if ((*it)->getOwner().lock() == edge->getOwner().lock() && + // (*it)->getTarget().lock() == edge->getTarget().lock()) + // { + // return false; + // } + // } m_outEdges.push_back(edge); return true; @@ -176,18 +176,18 @@ bool QtGraphNode::addOutEdge(const std::shared_ptr& edge) bool QtGraphNode::addInEdge(const std::weak_ptr& edge) { - for (std::list>::iterator it = m_inEdges.begin(); it != m_inEdges.end(); it++) - { - std::shared_ptr existingEdge = it->lock(); - if (existingEdge != NULL) - { - if (existingEdge->getOwner().lock() == edge.lock()->getOwner().lock() && - existingEdge->getTarget().lock() == edge.lock()->getTarget().lock()) - { - return false; - } - } - } + // for (std::list>::iterator it = m_inEdges.begin(); it != m_inEdges.end(); it++) + // { + // std::shared_ptr existingEdge = it->lock(); + // if (existingEdge != NULL) + // { + // if (existingEdge->getOwner().lock() == edge.lock()->getOwner().lock() && + // existingEdge->getTarget().lock() == edge.lock()->getTarget().lock()) + // { + // return false; + // } + // } + // } m_inEdges.push_back(edge); return true; @@ -258,7 +258,7 @@ void QtGraphNode::setStyle() QPen p(Qt::transparent); QFont font(getFontForNodeType(m_data->getType())); - bool undefined = false; + bool useUndefinedPattern = false; bool useUndefinedColor = false; Vec2i padding; @@ -266,9 +266,9 @@ void QtGraphNode::setStyle() switch (m_data->getType()) { case Node::NODE_UNDEFINED: - undefined = true; + p.setStyle(Qt::DashLine); case Node::NODE_NAMESPACE: - color = Qt::white; + color = Qt::transparent; p.setColor("#cc8d91"); p.setWidth(1); @@ -279,7 +279,7 @@ void QtGraphNode::setStyle() break; case Node::NODE_UNDEFINED_TYPE: - undefined = true; + useUndefinedPattern = true; case Node::NODE_STRUCT: case Node::NODE_CLASS: case Node::NODE_ENUM: @@ -315,7 +315,7 @@ void QtGraphNode::setStyle() break; case Node::NODE_UNDEFINED_FUNCTION: - undefined = true; + useUndefinedPattern = true; useUndefinedColor = true; case Node::NODE_FUNCTION: case Node::NODE_METHOD: @@ -335,7 +335,7 @@ void QtGraphNode::setStyle() break; case Node::NODE_UNDEFINED_VARIABLE: - undefined = true; + useUndefinedPattern = true; useUndefinedColor = true; case Node::NODE_GLOBAL_VARIABLE: case Node::NODE_FIELD: @@ -365,7 +365,7 @@ void QtGraphNode::setStyle() m_rect->setBrush(QBrush(color)); m_rect->setRadius(radius); - if (undefined) + if (useUndefinedPattern) { QtDeviceScaledPixmap pixmap("data/gui/graph_view/images/pattern.png"); pixmap.scaleToHeight(10); diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index e48cd8e3..f30f0f4f 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -87,6 +87,8 @@ add_files( data/graph/token_component/TokenComponentAbstraction.h data/graph/token_component/TokenComponentAccess.cpp data/graph/token_component/TokenComponentAccess.h + data/graph/token_component/TokenComponentAggregation.cpp + data/graph/token_component/TokenComponentAggregation.h data/graph/token_component/TokenComponentConst.cpp data/graph/token_component/TokenComponentConst.h data/graph/token_component/TokenComponentName.cpp diff --git a/src/lib/component/controller/GraphController.cpp b/src/lib/component/controller/GraphController.cpp index 0e5d0fd3..106d394c 100644 --- a/src/lib/component/controller/GraphController.cpp +++ b/src/lib/component/controller/GraphController.cpp @@ -168,7 +168,14 @@ DummyNode GraphController::createDummyNodeTopDown(Node* node) return; } - result.connected = true; + if (edge->isType(Edge::EDGE_AGGREGATION)) + { + result.aggregated = true; + } + else + { + result.connected = true; + } for (const DummyEdge& dummy : m_dummyEdges) { @@ -189,7 +196,7 @@ void GraphController::setActiveAndVisibility(const std::vector& activeTokenI { for (DummyNode& node : m_dummyNodes) { - setNodeActiveAndVisibilityRecursiveBottomUp(node, activeTokenIds); + setNodeActiveAndVisibilityRecursiveBottomUp(node, activeTokenIds, false); } for (DummyEdge& edge : m_dummyEdges) @@ -203,7 +210,7 @@ void GraphController::setActiveAndVisibility(const std::vector& activeTokenI } bool GraphController::setNodeActiveAndVisibilityRecursiveBottomUp( - DummyNode& node, const std::vector& activeTokenIds + DummyNode& node, const std::vector& activeTokenIds, bool aggregated ) const { node.visible = false; node.active = false; @@ -216,13 +223,13 @@ bool GraphController::setNodeActiveAndVisibilityRecursiveBottomUp( bool childVisible = false; for (DummyNode& subNode : node.subNodes) { - if (setNodeActiveAndVisibilityRecursiveBottomUp(subNode, activeTokenIds)) + if (setNodeActiveAndVisibilityRecursiveBottomUp(subNode, activeTokenIds, aggregated | node.aggregated)) { childVisible = true; } } - if (node.active || node.connected || childVisible) + if (node.active || node.connected || childVisible || (!aggregated && node.aggregated)) { setNodeVisibilityRecursiveTopDown(node); } diff --git a/src/lib/component/controller/GraphController.h b/src/lib/component/controller/GraphController.h index 676a74cb..d1918b75 100644 --- a/src/lib/component/controller/GraphController.h +++ b/src/lib/component/controller/GraphController.h @@ -59,7 +59,8 @@ private: DummyNode createDummyNodeTopDown(Node* node); void setActiveAndVisibility(const std::vector& activeTokenIds); - bool setNodeActiveAndVisibilityRecursiveBottomUp(DummyNode& node, const std::vector& activeTokenIds) const; + bool setNodeActiveAndVisibilityRecursiveBottomUp( + DummyNode& node, const std::vector& activeTokenIds, bool aggregated) const; void setNodeVisibilityRecursiveTopDown(DummyNode& node) const; void layoutNesting(); diff --git a/src/lib/component/view/graphElements/GraphNode.h b/src/lib/component/view/graphElements/GraphNode.h index 3f2ef26c..8e782f5d 100644 --- a/src/lib/component/view/graphElements/GraphNode.h +++ b/src/lib/component/view/graphElements/GraphNode.h @@ -52,6 +52,7 @@ struct DummyNode , accessType(TokenComponentAccess::ACCESS_NONE) , active(false) , connected(false) + , aggregated(false) , expanded(false) , invisibleSubNodeCount(0) , visible(false) @@ -63,6 +64,7 @@ struct DummyNode , accessType(accessType) , active(false) , connected(false) + , aggregated(false) , expanded(false) , invisibleSubNodeCount(0) , visible(false) @@ -77,6 +79,7 @@ struct DummyNode bool active; bool connected; + bool aggregated; bool expanded; size_t invisibleSubNodeCount; diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index 5e27e82a..1579976e 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -481,9 +481,16 @@ std::shared_ptr Storage::getGraphForActiveTokenIds(const std::vector& graph->addNodeAndAllChildrenAsPlainCopy(node->getLastParentNode()); node->forEachEdge( - [graph](Edge* edge) + [graph, node](Edge* edge) { - graph->addEdgeAndAllChildrenAsPlainCopy(edge); + const Node::NodeTypeMask varFuncMask = + Node::NODE_UNDEFINED_FUNCTION | Node::NODE_FUNCTION | Node::NODE_METHOD | + Node::NODE_UNDEFINED_VARIABLE | Node::NODE_GLOBAL_VARIABLE | Node::NODE_FIELD; + + if (!node->isType(varFuncMask) || !edge->isType(Edge::EDGE_AGGREGATION)) + { + graph->addEdgeAndAllChildrenAsPlainCopy(edge); + } } ); } diff --git a/src/lib/data/graph/Edge.cpp b/src/lib/data/graph/Edge.cpp index 0cf2b5a0..22af22c7 100644 --- a/src/lib/data/graph/Edge.cpp +++ b/src/lib/data/graph/Edge.cpp @@ -3,6 +3,7 @@ #include #include "data/graph/Node.h" +#include "data/graph/token_component/TokenComponentAggregation.h" #include "data/graph/token_component/TokenComponentAccess.h" #include "utility/logging/logging.h" @@ -76,6 +77,22 @@ bool Edge::isEdge() const return true; } +void Edge::addComponentAggregation(std::shared_ptr component) +{ + if (getComponent()) + { + LOG_ERROR("TokenComponentAggregation has been set before!"); + } + else if (m_type != EDGE_AGGREGATION) + { + LOG_ERROR("TokenComponentAggregation can't be set on edge of type: " + getTypeString()); + } + else + { + addComponent(component); + } +} + void Edge::addComponentAccess(std::shared_ptr component) { if (getComponent()) @@ -118,6 +135,8 @@ std::string Edge::getTypeString(EdgeType type) const return "template parameter"; case EDGE_TEMPLATE_SPECIALIZATION_OF: return "template specialization"; + case EDGE_AGGREGATION: + return "aggregation"; } return ""; } @@ -132,10 +151,16 @@ std::string Edge::getAsString() const std::stringstream str; str << "[" << getId() << "] " << getTypeString() << ": \"" << m_from->getName() << "\" -> \"" + m_to->getName() << "\""; - TokenComponentAccess* component = getComponent(); - if (component) + TokenComponentAccess* access = getComponent(); + if (access) { - str << " " << component->getAccessString(); + str << " " << access->getAccessString(); + } + + TokenComponentAggregation* aggregation = getComponent(); + if (aggregation) + { + str << " " << aggregation->getAggregationCount(); } return str.str(); @@ -222,6 +247,13 @@ bool Edge::checkType() const break; } return true; + + case EDGE_AGGREGATION: + if (!m_from->isType(typeMask | variableMask | functionMask) || !m_to->isType(typeMask | variableMask | functionMask)) + { + break; + } + return true; } LOG_ERROR_STREAM( diff --git a/src/lib/data/graph/Edge.h b/src/lib/data/graph/Edge.h index 34883d4a..c18174fc 100644 --- a/src/lib/data/graph/Edge.h +++ b/src/lib/data/graph/Edge.h @@ -7,6 +7,7 @@ #include "data/graph/Token.h" class Node; +class TokenComponentAggregation; class TokenComponentAccess; class TokenComponentDataType; @@ -26,7 +27,9 @@ public: EDGE_INHERITANCE = 0x80, EDGE_TYPEDEF_OF = 0x100, EDGE_TEMPLATE_PARAMETER_OF = 0x200, - EDGE_TEMPLATE_SPECIALIZATION_OF = 0x400 + EDGE_TEMPLATE_SPECIALIZATION_OF = 0x400, + + EDGE_AGGREGATION = 0x800 }; Edge(EdgeType type, Node* from, Node* to); @@ -46,6 +49,7 @@ public: virtual bool isEdge() const; // Component setters + void addComponentAggregation(std::shared_ptr component); void addComponentAccess(std::shared_ptr component); // Logging. diff --git a/src/lib/data/graph/StorageGraph.cpp b/src/lib/data/graph/StorageGraph.cpp index d43ba326..2ccb81d9 100644 --- a/src/lib/data/graph/StorageGraph.cpp +++ b/src/lib/data/graph/StorageGraph.cpp @@ -1,5 +1,6 @@ #include "data/graph/StorageGraph.h" +#include "data/graph/token_component/TokenComponentAggregation.h" #include "data/graph/token_component/TokenComponentName.h" #include "utility/logging/logging.h" #include "utility/utilityString.h" @@ -87,7 +88,16 @@ Edge* StorageGraph::createEdge(Edge::EdgeType type, Node* from, Node* to) return edge; } - return insertEdge(type, from, to); + edge = insertEdge(type, from, to); + + if (from->getLastParentNode() != to->getLastParentNode()) + { + Id edgeId = edge->getId(); + updateAggregationEdges(from->getParentNode(), to, edgeId); + updateAggregationEdges(from, to->getParentNode(), edgeId); + } + + return edge; } Node* StorageGraph::insertNodeHierarchy(Node::NodeType type, SearchNode* searchNode) @@ -140,3 +150,39 @@ Edge* StorageGraph::insertEdge(Edge::EdgeType type, Node* from, Node* to) m_edges.emplace(edgePtr->getId(), edgePtr); return edgePtr.get(); } + +void StorageGraph::updateAggregationEdges(Node* from, Node* to, Id edgeId) +{ + if (!from || !to || from == to) + { + return; + } + + const Node::NodeTypeMask mask = Node::NODE_UNDEFINED_TYPE | Node::NODE_CLASS | Node::NODE_STRUCT | Node::NODE_ENUM; + const Node::NodeTypeMask varFuncMask = + Node::NODE_UNDEFINED_FUNCTION | Node::NODE_FUNCTION | Node::NODE_UNDEFINED_VARIABLE | Node::NODE_GLOBAL_VARIABLE; + + if ((from->isType(mask) && to->isType(mask | varFuncMask)) || + (from->isType(mask | varFuncMask) && to->isType(mask))) + { + Edge* edge = from->findEdgeOfType(Edge::EDGE_AGGREGATION, + [from, to](Edge* e) + { + const Node* f = e->getFrom(); + const Node* t = e->getTo(); + return (f == from && t == to) || (f == to && t == from); + } + ); + + if (!edge) + { + edge = insertEdge(Edge::EDGE_AGGREGATION, from, to); + edge->addComponentAggregation(std::make_shared()); + } + + edge->getComponent()->addAggregationId(edgeId); + } + + updateAggregationEdges(from->getParentNode(), to, edgeId); + updateAggregationEdges(from, to->getParentNode(), edgeId); +} diff --git a/src/lib/data/graph/StorageGraph.h b/src/lib/data/graph/StorageGraph.h index f7915993..66dc1744 100644 --- a/src/lib/data/graph/StorageGraph.h +++ b/src/lib/data/graph/StorageGraph.h @@ -21,6 +21,8 @@ private: Node* insertNodeHierarchy(Node::NodeType type, SearchNode* searchNode); Node* insertNode(Node::NodeType type, Node* parentNode, SearchNode* searchNode); Edge* insertEdge(Edge::EdgeType type, Node* from, Node* to); + + void updateAggregationEdges(Node* from, Node* to, Id edgeId); }; #endif // STORAGE_GRAPH_H diff --git a/src/lib/data/graph/token_component/TokenComponentAggregation.cpp b/src/lib/data/graph/token_component/TokenComponentAggregation.cpp new file mode 100644 index 00000000..5110d06d --- /dev/null +++ b/src/lib/data/graph/token_component/TokenComponentAggregation.cpp @@ -0,0 +1,29 @@ +#include "data/graph/token_component/TokenComponentAggregation.h" + +TokenComponentAggregation::TokenComponentAggregation() +{ +} + +TokenComponentAggregation::~TokenComponentAggregation() +{ +} + +std::shared_ptr TokenComponentAggregation::copy() const +{ + return std::make_shared(*this); +} + +int TokenComponentAggregation::getAggregationCount() const +{ + return m_ids.size(); +} + +void TokenComponentAggregation::addAggregationId(Id id) +{ + m_ids.insert(id); +} + +const std::set& TokenComponentAggregation::getAggregationIds() const +{ + return m_ids; +} diff --git a/src/lib/data/graph/token_component/TokenComponentAggregation.h b/src/lib/data/graph/token_component/TokenComponentAggregation.h new file mode 100644 index 00000000..c384994e --- /dev/null +++ b/src/lib/data/graph/token_component/TokenComponentAggregation.h @@ -0,0 +1,27 @@ +#ifndef TOKEN_COMPONENT_AGGREGATION_H +#define TOKEN_COMPONENT_AGGREGATION_H + +#include + +#include "utility/types.h" + +#include "data/graph/token_component/TokenComponent.h" + +class TokenComponentAggregation + : public TokenComponent +{ +public: + TokenComponentAggregation(); + virtual ~TokenComponentAggregation(); + + virtual std::shared_ptr copy() const; + + int getAggregationCount() const; + void addAggregationId(Id id); + const std::set& getAggregationIds() const; + +private: + std::set m_ids; +}; + +#endif // TOKEN_COMPONENT_AGGREGATION_H diff --git a/src/lib/utility/math/VectorBase.h b/src/lib/utility/math/VectorBase.h index 71927ec4..98e5dcfe 100644 --- a/src/lib/utility/math/VectorBase.h +++ b/src/lib/utility/math/VectorBase.h @@ -39,11 +39,11 @@ public: void assign(const VectorBase& other); template - VectorBase add(const VectorBase& other); + VectorBase& add(const VectorBase& other); template - VectorBase subtract(const VectorBase& other); + VectorBase& subtract(const VectorBase& other); template - VectorBase scalarMultiplication(const U& scalar); + VectorBase& scalarMultiplication(const U& scalar); template T dotProduct(const VectorBase& other); @@ -71,13 +71,13 @@ public: VectorBase operator/(const U& scalar) const; template - VectorBase operator+=(const VectorBase& other); + VectorBase& operator+=(const VectorBase& other); template - VectorBase operator-=(const VectorBase& other); + VectorBase& operator-=(const VectorBase& other); template - VectorBase operator*=(const U& scalar); + VectorBase& operator*=(const U& scalar); template - VectorBase operator/=(const U& scalar); + VectorBase& operator/=(const U& scalar); // Checks whether all values are the same. template @@ -238,7 +238,7 @@ void VectorBase::assign(const VectorBase& other) template template -VectorBase VectorBase::add(const VectorBase& other) +VectorBase& VectorBase::add(const VectorBase& other) { T tmpValues[N]; for (unsigned int i = 0; i < N; i++) @@ -253,7 +253,7 @@ VectorBase VectorBase::add(const VectorBase& other) template template -VectorBase VectorBase::subtract(const VectorBase& other) +VectorBase& VectorBase::subtract(const VectorBase& other) { T tmpValues[N]; for (unsigned int i = 0; i < N; i++) @@ -268,7 +268,7 @@ VectorBase VectorBase::subtract(const VectorBase& other) template template -VectorBase VectorBase::scalarMultiplication(const U& scalar) +VectorBase& VectorBase::scalarMultiplication(const U& scalar) { T tmpValues[N]; for (unsigned int i = 0; i < N; i++) @@ -371,28 +371,28 @@ VectorBase VectorBase::operator/(const U& scalar) const template template -VectorBase VectorBase::operator+=(const VectorBase& other) +VectorBase& VectorBase::operator+=(const VectorBase& other) { return add(other); } template template -VectorBase VectorBase::operator-=(const VectorBase& other) +VectorBase& VectorBase::operator-=(const VectorBase& other) { return subtract(other); } template template -VectorBase VectorBase::operator*=(const U& scalar) +VectorBase& VectorBase::operator*=(const U& scalar) { return scalarMultiplication(scalar); } template template -VectorBase VectorBase::operator/=(const U& scalar) +VectorBase& VectorBase::operator/=(const U& scalar) { return scalarMultiplication(1.0f / scalar); } diff --git a/src/test/GraphFilterConductorTestSuite.h b/src/test/GraphFilterConductorTestSuite.h index 6aa93969..4e6a6f6d 100644 --- a/src/test/GraphFilterConductorTestSuite.h +++ b/src/test/GraphFilterConductorTestSuite.h @@ -99,9 +99,10 @@ public: "7 nodes: " "class:A field:A::count undefined_type:int undefined_type:void class:B function:main " "undefined_function:B::B\n" - "7 edges: " - "child:A->A::count type_use:A::count->int inheritance:B->A return_type:main->int type_usage:main->B " - "child:B->B::B call:main->B::B\n" + "13 edges: " + "child:A->A::count aggregation:A->int aggregation:A->void type_use:A::count->int inheritance:B->A " + "aggregation:B->void aggregation:B->int return_type:main->int type_usage:main->B child:B->B::B " + "call:main->B::B aggregation:main->B aggregation:main->A\n" ); } diff --git a/src/test/StorageGraphTestSuite.h b/src/test/StorageGraphTestSuite.h index 0b6c7751..9e872fc3 100644 --- a/src/test/StorageGraphTestSuite.h +++ b/src/test/StorageGraphTestSuite.h @@ -1,5 +1,6 @@ #include "cxxtest/TestSuite.h" +#include "data/graph/token_component/TokenComponentAggregation.h" #include "data/graph/StorageGraph.h" #include "data/search/SearchIndex.h" @@ -74,6 +75,32 @@ public: TS_ASSERT_EQUALS(ab->getParentNode(), a); } + void test_graph_creates_aggregation_edges() + { + TestStorageGraph graph; + Node* a = graph.createNodeHierarchy(Node::NODE_CLASS, "A"); + Node* ab = graph.createNodeHierarchy(Node::NODE_CLASS, "A::B"); + Node* c = graph.createNodeHierarchy(Node::NODE_CLASS, "C"); + Node* cd = graph.createNodeHierarchy(Node::NODE_CLASS, "C::D"); + Node* cdd = graph.createNodeHierarchy(Node::NODE_METHOD, "C::D::D"); + Edge* i = graph.createEdge(Edge::EDGE_INHERITANCE, ab, cd); + Edge* t = graph.createEdge(Edge::EDGE_TYPE_USAGE, cdd, a); + + TS_ASSERT_EQUALS(5, graph.getNodeCount()); + TS_ASSERT_EQUALS(8, graph.getEdgeCount()); + + Edge* e1 = graph.getEdge(Edge::EDGE_AGGREGATION, a, c); + TS_ASSERT(e1); + TS_ASSERT_EQUALS(2, e1->getComponent()->getAggregationCount()); + TS_ASSERT_EQUALS(i->getId(), *e1->getComponent()->getAggregationIds().begin()); + TS_ASSERT_EQUALS(t->getId(), *(++e1->getComponent()->getAggregationIds().begin())); + + Edge* e2 = graph.getEdge(Edge::EDGE_AGGREGATION, ab, c); + TS_ASSERT(e2); + TS_ASSERT_EQUALS(1, e2->getComponent()->getAggregationCount()); + TS_ASSERT_EQUALS(i->getId(), *e2->getComponent()->getAggregationIds().begin()); + } + void test_graph_removes_nodes() { TestStorageGraph graph; @@ -278,14 +305,14 @@ public: } ); - TS_ASSERT_EQUALS(4, plainGraph.getNodeCount()); - TS_ASSERT_EQUALS(3, plainGraph.getEdgeCount()); + TS_ASSERT_EQUALS(5, plainGraph.getNodeCount()); + TS_ASSERT_EQUALS(4, plainGraph.getEdgeCount()); TS_ASSERT(plainGraph.getNode("A")); TS_ASSERT(plainGraph.getNode("A::B")); TS_ASSERT(plainGraph.getNode("A::B::C")); TS_ASSERT(plainGraph.getNode("D")); - TS_ASSERT(!plainGraph.getNode("E")); + TS_ASSERT(plainGraph.getNode("E")); } private: