#include "data/Storage.h" #include "data/graph/token_component/TokenComponentConst.h" #include "data/graph/token_component/TokenComponentDataType.h" #include "data/graph/token_component/TokenComponentStatic.h" #include "data/location/TokenLocation.h" #include "data/location/TokenLocationFile.h" #include "data/location/TokenLocationLine.h" #include "data/parser/ParseLocation.h" #include "data/parser/ParseTypeUsage.h" #include "data/parser/ParseVariable.h" #include "data/type/DataType.h" #include "utility/logging/logging.h" #include "utility/utilityString.h" Storage::Storage() { } Storage::~Storage() { } void Storage::clear() { m_graph.clear(); m_locationCollection.clear(); } void Storage::logGraph() const { LOG_INFO_STREAM(<< '\n' << m_graph); } void Storage::logLocations() const { LOG_INFO_STREAM(<< '\n' << m_locationCollection); } void Storage::onTypedefParsed( const ParseLocation& location, const std::string& fullName, const DataType& underlyingType, AccessType access ){ log("typedef", fullName + " -> " + underlyingType.getFullTypeName(), location); Node* node = m_graph.createNodeHierarchy(Node::NODE_TYPEDEF, fullName); addAccess(node, access); addTokenLocation(node, location); addTypeEdge(node, Edge::EDGE_TYPEDEF_OF, underlyingType); } void Storage::onClassParsed(const ParseLocation& location, const std::string& fullName, AccessType access) { log("class", fullName, location); Node* node = m_graph.createNodeHierarchy(Node::NODE_CLASS, fullName); addAccess(node, access); addTokenLocation(node, location); } void Storage::onStructParsed(const ParseLocation& location, const std::string& fullName, AccessType access) { log("struct", fullName, location); Node* node = m_graph.createNodeHierarchy(Node::NODE_STRUCT, fullName); addAccess(node, access); addTokenLocation(node, location); } void Storage::onGlobalVariableParsed(const ParseLocation& location, const ParseVariable& variable) { log("global", variable.fullName, location); Node* node = m_graph.createNodeHierarchy(Node::NODE_GLOBAL_VARIABLE, variable.fullName); if (variable.isStatic) { node->addComponentStatic(std::make_shared()); } addTypeEdge(node, Edge::EDGE_TYPE_OF, variable.type); addTokenLocation(node, location); } void Storage::onFieldParsed(const ParseLocation& location, const ParseVariable& variable, AccessType access) { log("field", variable.fullName, location); Node* node = m_graph.createNodeHierarchy(Node::NODE_FIELD, variable.fullName); if (variable.isStatic) { node->addComponentStatic(std::make_shared()); } if (access == ACCESS_NONE) { LOG_ERROR("Field needs to have access type [public, protected, private] but has none."); return; } addAccess(node, access); addTypeEdge(node, Edge::EDGE_TYPE_OF, variable.type); addTokenLocation(node, location); } void Storage::onFunctionParsed( const ParseLocation& location, const std::string& fullName, const ParseTypeUsage& returnType, const std::vector& parameters ) { log("function", fullName, location); Node* node = m_graph.createNodeHierarchyWithDistinctSignature( Node::NODE_FUNCTION, fullName, ParserClient::functionSignatureStr(returnType.dataType, fullName, parameters, false) ); addTokenLocation(node, location); addTypeEdge(node, Edge::EDGE_RETURN_TYPE_OF, returnType); for (const ParseTypeUsage& parameter : parameters) { addTypeEdge(node, Edge::EDGE_PARAMETER_TYPE_OF, parameter); } } void Storage::onMethodParsed( const ParseLocation& location, const std::string& fullName, const ParseTypeUsage& returnType, const std::vector& parameters, AccessType access, AbstractionType abstraction, bool isConst, bool isStatic ) { log("method", fullName, location); Node* node = m_graph.createNodeHierarchyWithDistinctSignature( Node::NODE_METHOD, fullName, ParserClient::functionSignatureStr(returnType.dataType, fullName, parameters, isConst) ); if (isConst) { node->addComponentConst(std::make_shared()); } if (isStatic) { node->addComponentStatic(std::make_shared()); } if (access == ACCESS_NONE) { LOG_ERROR("Method needs to have access type [public, protected, private] but has none."); return; } addAccess(node, access); addTokenLocation(node, location); addTypeEdge(node, Edge::EDGE_RETURN_TYPE_OF, returnType); for (const ParseTypeUsage& parameter : parameters) { addTypeEdge(node, Edge::EDGE_PARAMETER_TYPE_OF, parameter); } } void Storage::onNamespaceParsed(const ParseLocation& location, const std::string& fullName) { log("namespace", fullName, location); Node* node = m_graph.createNodeHierarchy(Node::NODE_NAMESPACE, fullName); addTokenLocation(node, location); } void Storage::onEnumParsed(const ParseLocation& location, const std::string& fullName, AccessType access) { log("enum", fullName, location); Node* node = m_graph.createNodeHierarchy(Node::NODE_ENUM, fullName); addAccess(node, access); addTokenLocation(node, location); } void Storage::onEnumFieldParsed(const ParseLocation& location, const std::string& fullName) { log("enum field", fullName, location); Node* node = m_graph.createNodeHierarchy(Node::NODE_FIELD, fullName); addTokenLocation(node, location); } void Storage::onInheritanceParsed( const ParseLocation& location, const std::string& fullName, const std::string& baseName, AccessType access) { log("inheritance", fullName + " : " + baseName, location); Node* node = m_graph.createNodeHierarchy(fullName); Node* baseNode = m_graph.createNodeHierarchy(baseName); Edge* edge = m_graph.createEdge(Edge::EDGE_INHERITANCE, node, baseNode); edge->addComponentAccess(std::make_shared(convertAccessType(access))); addTokenLocation(edge, location); } void Storage::onCallParsed(const ParseLocation& location, const std::string& callerName, const std::string& calleeName) { log("call", callerName + " -> " + calleeName, location); Node* callerNode = m_graph.createNodeHierarchy(callerName); Node* calleeNode = m_graph.createNodeHierarchy(calleeName); Edge* edge = m_graph.createEdge(Edge::EDGE_CALL, callerNode, calleeNode); addTokenLocation(edge, location); } void Storage::onFieldUsageParsed(const ParseLocation& location, const std::string& userName, const std::string& usedName) { log("usage", userName + " -> " + usedName, location); Node* userNode = m_graph.createNodeHierarchy(userName); Node* usedNode = m_graph.createNodeHierarchy(usedName); Edge* edge = m_graph.createEdge(Edge::EDGE_USAGE, userNode, usedNode); addTokenLocation(edge, location); } void Storage::onGlobalVariableUsageParsed( const ParseLocation& location, const std::string& userName, const std::string& usedName ) { log("usage", userName + " -> " + usedName, location); Node* userNode = m_graph.createNodeHierarchy(userName); Node* usedNode = m_graph.createNodeHierarchy(usedName); Edge* edge = m_graph.createEdge(Edge::EDGE_USAGE, userNode, usedNode); addTokenLocation(edge, location); } Id Storage::getIdForNodeWithName(const std::string& fullName) const { Node* node = m_graph.getNode(fullName); return (node ? node->getId() : 0); } std::string Storage::getNameForNodeWithId(Id id) const { Token* token = m_graph.getTokenById(id); if (!token) { return ""; } if (token->isEdge()) { return dynamic_cast(token)->getName(); } else { return dynamic_cast(token)->getFullName(); } } std::vector Storage::getNamesForNodesWithNamePrefix(const std::string& prefix) const { std::vector names; m_graph.forEachNode([&](Node* node){ const std::string& nodeName = node->getFullName(); if (utility::isPrefix(prefix, nodeName)) { names.push_back(nodeName); } }); return names; } std::vector Storage::getIdsOfNeighbours(const Id id) const { std::vector result; Node* node = m_graph.findNode([&](Node* node){ return node->getId() == id; }); if (node != NULL) { std::map addedIds; addedIds[id] = true; node->forEachEdge( [&result, &addedIds](Edge* e) { Id fromId = e->getFrom()->getId(); if (addedIds.find(fromId) == addedIds.end()) { result.push_back(fromId); addedIds[fromId] = true; } Id toId = e->getTo()->getId(); if (addedIds.find(toId) == addedIds.end()) { result.push_back(toId); addedIds[toId] = true; } } ); } return result; } std::vector> Storage::getNeighbourEdgesOfNode(const Id id) const { std::vector> result; Node* node = m_graph.findNode([&](Node* node){ return node->getId() == id; }); if (node != NULL) { node->forEachEdge( [&result](Edge* e) { result.push_back(std::tuple(e->getFrom()->getId(), e->getTo()->getId(), e->getId())); } ); } return result; } std::vector> Storage::getMemberEdgesOfNode(const Id id) const { return getEdgesOfTypeOfNode(id, Edge::EdgeType::EDGE_MEMBER); } std::vector> Storage::getUsageEdgesOfNode(const Id id) const { return getEdgesOfTypeOfNode(id, Edge::EdgeType::EDGE_USAGE); } std::vector> Storage::getCallEdgesOfNode(const Id id) const { return getEdgesOfTypeOfNode(id, Edge::EdgeType::EDGE_CALL); } std::vector> Storage::getTypeOfEdgesOfNode(const Id id) const { return getEdgesOfTypeOfNode(id, Edge::EdgeType::EDGE_TYPE_OF); } std::vector> Storage::getReturnTypeOfEdgesOfNode(const Id id) const { return getEdgesOfTypeOfNode(id, Edge::EdgeType::EDGE_RETURN_TYPE_OF); } std::vector> Storage::getParameterOfEdgesOfNode(const Id id) const { return getEdgesOfTypeOfNode(id, Edge::EdgeType::EDGE_PARAMETER_TYPE_OF); } std::vector> Storage::getInheritanceEdgesOfNode(const Id id) const { return getEdgesOfTypeOfNode(id, Edge::EdgeType::EDGE_INHERITANCE); } std::pair Storage::getNodesOfEdge(const Id id) const { std::pair result; Edge* edge = m_graph.findEdge([&](Edge* edge){ return edge->getId() == id; }); if(edge != NULL) { result.first = edge->getFrom()->getId(); result.second = edge->getTo()->getId(); } return result; } bool Storage::checkTokenIsNode(const Id id) const { Token* token = m_graph.findToken([&](Token* token){ return token->getId() == id; }); if(token != NULL) { return token->isNode(); } return false; } std::vector Storage::getActiveTokenIdsForId(Id tokenId) const { std::vector ret; Token* token = m_graph.getTokenById(tokenId); if (!token) { return ret; } Node* node; if (token->isEdge()) { node = dynamic_cast(token)->getTo(); } else { node = dynamic_cast(token); } ret.push_back(node->getId()); node->forEachEdge( [&node, &ret](Edge* e) { if (e->getTo() == node) { ret.push_back(e->getId()); } } ); return ret; } std::vector Storage::getLocationIdsForTokenIds(const std::vector& tokenIds) const { std::vector ret; for (Id tokenId : tokenIds) { Token* token = m_graph.getTokenById(tokenId); if (!token) { continue; } ret.insert(ret.end(), token->getLocationIds().begin(), token->getLocationIds().end()); } return ret; } TokenLocationCollection Storage::getTokenLocationsForLocationIds(const std::vector& locationIds) const { TokenLocationCollection ret; for (Id locationId: locationIds) { TokenLocation* location = m_locationCollection.findTokenLocationById(locationId); if (location->getOtherTokenLocation()) { ret.addTokenLocationAsPlainCopy(location); ret.addTokenLocationAsPlainCopy(location->getOtherTokenLocation()); } } return ret; } TokenLocationFile Storage::getTokenLocationsForFile(const std::string& filePath) const { TokenLocationFile ret(filePath); TokenLocationFile* locationFile = m_locationCollection.findTokenLocationFileByPath(filePath); if (!locationFile) { return ret; } locationFile->forEachTokenLocation( [&](TokenLocation* tokenLocation) -> void { ret.addTokenLocationAsPlainCopy(tokenLocation); } ); return ret; } TokenLocationFile Storage::getTokenLocationsForLinesInFile( const std::string& filePath, uint firstLineNumber, uint lastLineNumber ) const { TokenLocationFile ret(filePath); TokenLocationFile* locationFile = m_locationCollection.findTokenLocationFileByPath(filePath); if (!locationFile) { return ret; } for (uint i = firstLineNumber; i <= lastLineNumber; i++) { TokenLocationLine* locationLine = locationFile->findTokenLocationLineByNumber(i); if (!locationLine) { continue; } locationLine->forEachTokenLocation( [&](TokenLocation* tokenLocation) -> void { ret.addTokenLocationAsPlainCopy(tokenLocation); } ); } return ret; } TokenComponentAccess::AccessType Storage::convertAccessType(ParserClient::AccessType access) const { switch (access) { case ACCESS_PUBLIC: return TokenComponentAccess::ACCESS_PUBLIC; case ACCESS_PROTECTED: return TokenComponentAccess::ACCESS_PROTECTED; case ACCESS_PRIVATE: return TokenComponentAccess::ACCESS_PRIVATE; case ACCESS_NONE: return TokenComponentAccess::ACCESS_NONE; } } TokenComponentAccess* Storage::addAccess(Node* node, ParserClient::AccessType access) { if (access != ACCESS_NONE) { std::shared_ptr ptr = std::make_shared(convertAccessType(access)); node->getMemberEdge()->addComponentAccess(ptr); return ptr.get(); } return nullptr; } Edge* Storage::addTypeEdge(Node* node, Edge::EdgeType edgeType, const DataType& type) { Node* typeNode = m_graph.createNodeHierarchy(type.getRawTypeName()); Edge* edge = m_graph.createEdge(edgeType, node, typeNode); // FIXME: When a function uses the same type multiple times then we still only use one edge to save this, // but we can't store multiple DataTypes on this edge at the moment. if (!edge->getComponent()) { edge->addComponentDataType( std::make_shared(type.getQualifierList(), type.getModifierStack()) ); } return edge; } Edge* Storage::addTypeEdge(Node* node, Edge::EdgeType edgeType, const ParseTypeUsage& typeUsage) { if (!typeUsage.location.isValid()) { return nullptr; } Edge* edge = addTypeEdge(node, edgeType, typeUsage.dataType); addTokenLocation(edge, typeUsage.location); return edge; } TokenLocation* Storage::addTokenLocation(Token* token, const ParseLocation& loc) { if (!loc.isValid()) { return nullptr; } TokenLocation* location = m_locationCollection.addTokenLocation( token->getId(), loc.filePath, loc.startLineNumber, loc.startColumnNumber, loc.endLineNumber, loc.endColumnNumber ); token->addLocationId(location->getId()); return location; } void Storage::log(std::string type, std::string str, const ParseLocation& location) const { LOG_INFO_STREAM( << type << ": " << str << " <" << location.filePath << " " << location.startLineNumber << ":" << location.startColumnNumber << " " << location.endLineNumber << ":" << location.endColumnNumber << ">" ); } std::vector> Storage::getEdgesOfTypeOfNode(const Id id, const Edge::EdgeType type) const { std::vector> result; Node* node = m_graph.findNode([&](Node* node){ return node->getId() == id; }); if (node != NULL) { node->forEachEdge( [&result, &type](Edge* e) { if(e->getType() == type) { result.push_back(std::tuple(e->getFrom()->getId(), e->getTo()->getId(), e->getId())); } } ); } return result; }