#include "data/Storage.h" #include #include #include "utility/file/FileSystem.h" #include "utility/logging/logging.h" #include "utility/messaging/type/MessageClearErrorCount.h" #include "utility/messaging/type/MessageShowErrors.h" #include "utility/TimePoint.h" #include "utility/utility.h" #include "utility/utilityString.h" #include "utility/Version.h" #include "utility/Cache.h" #include "data/graph/token_component/TokenComponentAggregation.h" #include "data/graph/token_component/TokenComponentSignature.h" #include "data/graph/Graph.h" #include "data/location/TokenLocation.h" #include "data/location/TokenLocationFile.h" #include "data/location/TokenLocationLine.h" #include "data/parser/ParseLocation.h" #include "data/type/DataType.h" #include "settings/ApplicationSettings.h" Storage::Storage(const FilePath& dbPath) : m_sqliteStorage(dbPath.str()) { } Storage::~Storage() { } Version Storage::getVersion() const { return m_sqliteStorage.getVersion(); } bool Storage::init() { m_commandIndex.addNode(NameHierarchy(SearchMatch::getCommandName(SearchMatch::COMMAND_ALL))); m_commandIndex.addNode(NameHierarchy(SearchMatch::getCommandName(SearchMatch::COMMAND_ERROR))); return m_sqliteStorage.init(); } void Storage::clear() { m_sqliteStorage.clear(); clearCaches(); } void Storage::clearCaches() { m_tokenIndex.clear(); m_fileNodeIds.clear(); m_hierarchyCache.clear(); } std::set Storage::getDependingFilePaths(const std::set& filePaths) { std::set dependingFilePaths; for (const FilePath& filePath: filePaths) { std::set dependingFilePathsSubset = getDependingFilePaths(filePath); dependingFilePaths.insert(dependingFilePathsSubset.begin(), dependingFilePathsSubset.end()); } return dependingFilePaths; } std::set Storage::getDependingFilePaths(const FilePath& filePath) { std::set dependingFilePaths; std::vector incomingEdges = m_sqliteStorage.getEdgesByTargetType( getFileNodeId(filePath), Edge::typeToInt(Edge::EDGE_INCLUDE) ); for (const StorageEdge& incomingEdge: incomingEdges) { FilePath dependingFilePath = getFileNodePath(incomingEdge.sourceNodeId); dependingFilePaths.insert(dependingFilePath); std::set dependingFilePathsSubset = getDependingFilePaths(dependingFilePath); dependingFilePaths.insert(dependingFilePathsSubset.begin(), dependingFilePathsSubset.end()); } return dependingFilePaths; } void Storage::clearFileElements(const std::vector& filePaths) { std::vector fileNodeIds; for (const FilePath& path : filePaths) { fileNodeIds.push_back(getFileNodeId(path)); } if (fileNodeIds.size()) { m_sqliteStorage.removeElementsWithLocationInFiles(fileNodeIds); m_sqliteStorage.removeElements(fileNodeIds); m_sqliteStorage.removeErrorsInFiles(filePaths); } } void Storage::removeUnusedNames() // maybe rename this function. look for callers first. { // m_sqliteStorage.removeUnusedNameHierarchyElements(); clearCaches(); } std::vector Storage::getInfoOnAllFiles() const { std::vector fileInfos; std::vector storageFiles = m_sqliteStorage.getAllFiles(); for (size_t i = 0; i < storageFiles.size(); i++) { boost::posix_time::ptime modificationTime = boost::posix_time::not_a_date_time; if (storageFiles[i].modificationTime != "not-a-date-time") { modificationTime = boost::posix_time::time_from_string(storageFiles[i].modificationTime); } fileInfos.push_back(FileInfo( FilePath(storageFiles[i].filePath), modificationTime )); } return fileInfos; } const SearchIndex& Storage::getSearchIndex() const { return m_tokenIndex; } void Storage::logStats() const { std::stringstream ss; StorageStats stats = getStorageStats(); ss << "\nGraph:\n"; ss << "\t" << stats.nodeCount << " Nodes\n"; ss << "\t" << stats.edgeCount << " Edges\n"; ss << "\nSearch:\n"; ss << "\t" << stats.charCount << " Characters\n"; ss << "\t" << stats.wordCount << " Words\n"; ss << "\t" << stats.searchNodeCount << " SearchNodes\n"; ss << "\nCode:\n"; ss << "\t" << stats.fileCount << " Files\n"; ss << "\t" << stats.fileLOCCount << " Lines of Code\n"; ss << "\t" << stats.sourceLocationCount << " Source Locations\n"; LOG_WARNING(ss.str()); } void Storage::startParsing() { MessageClearErrorCount().dispatch(); m_sqliteStorage.setVersion(Version::getApplicationVersion()); } void Storage::finishParsing() { buildSearchIndex(); buildHierarchyCache(); } void Storage::injectData(std::shared_ptr injectedStorage) { int totalErrorCount = getErrorCount().total; injectedStorage->transferToStorage(m_sqliteStorage); if (totalErrorCount != getErrorCount().total) { MessageShowErrors msg(getErrorCount()); msg.setSendAsTask(false); msg.dispatch(); } } Id Storage::getIdForNodeWithNameHierarchy(const NameHierarchy& nameHierarchy) const { return m_sqliteStorage.getNodeBySerializedName(NameHierarchy::serialize(nameHierarchy)).id; } Id Storage::getIdForNodeWithSearchNameHierarchy(const NameHierarchy& nameHierarchy) const { SearchNode* node = m_tokenIndex.getNode(nameHierarchy); if (node) { return node->getFirstTokenId(); } return 0; } Id Storage::getIdForEdge( Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy ) const { Id sourceId = getIdForNodeWithNameHierarchy(fromNameHierarchy); Id targetId = getIdForNodeWithNameHierarchy(toNameHierarchy); return m_sqliteStorage.getEdgeBySourceTargetType(sourceId, targetId, type).id; } Id Storage::getIdForFirstNode() const { return m_sqliteStorage.getFirstNode().id; } NameHierarchy Storage::getNameHierarchyForNodeWithId(Id nodeId) const { return NameHierarchy::deserialize(m_sqliteStorage.getNodeById(nodeId).serializedName); } Node::NodeType Storage::getNodeTypeForNodeWithId(Id nodeId) const { return Node::intToType(m_sqliteStorage.getNodeById(nodeId).type); } std::vector Storage::getAutocompletionMatches(const std::string& query) const { if (query.size() == m_cachedQuery.size() + 1 && query.find(m_cachedQuery) == 0 && m_cachedResults.size()) { m_cachedResults = m_tokenIndex.runFuzzySearchCached(query, m_cachedResults); } else { m_cachedResults = m_tokenIndex.runFuzzySearch(query); } m_cachedQuery = query; SearchResults results = m_cachedResults; SearchResults commandResults = m_commandIndex.runFuzzySearch(query); results.insert(commandResults.begin(), commandResults.end()); std::vector matches = SearchIndex::getMatches(results, query); LOG_INFO_STREAM(<< matches.size() << " matches for \"" << query << "\""); if (matches.size() > 100) { matches.resize(100); } for (SearchMatch& match : matches) { if (!match.tokenIds.size()) { match.searchType = SearchMatch::SEARCH_COMMAND; match.typeName = "command"; continue; } Id elementId = *(match.tokenIds.cbegin()); if (m_sqliteStorage.isNode(elementId)) { StorageNode node = m_sqliteStorage.getNodeById(elementId); match.nodeType = Node::intToType(node.type); match.typeName = Node::getTypeString(match.nodeType); if (!node.defined && match.nodeType != Node::NODE_UNDEFINED) { match.typeName = "undefined " + match.typeName; } } else { match.typeName = Edge::getTypeString(Edge::intToType(m_sqliteStorage.getEdgeById(elementId).type)); } match.searchType = SearchMatch::SEARCH_TOKEN; } return matches; } std::vector Storage::getSearchMatchesForTokenIds(const std::vector& tokenIds) const { std::vector matches; for (Id tokenId : tokenIds) { SearchMatch match; if (m_sqliteStorage.isFile(tokenId)) { match.nodeType = Node::NODE_FILE; } else if (m_sqliteStorage.isNode(tokenId)) { StorageNode node = m_sqliteStorage.getNodeById(tokenId); match.nodeType = Node::intToType(node.type); } else { continue; } match.tokenIds.insert(tokenId); match.nameHierarchy = m_tokenIndex.getNameHierarchyForTokenId(tokenId); match.searchType = SearchMatch::SEARCH_TOKEN; matches.push_back(match); } return matches; } std::shared_ptr Storage::getGraphForAll() const { std::shared_ptr graph = std::make_shared(); std::vector tokenIds; for (StorageNode node: m_sqliteStorage.getAllNodes()) { if (node.defined && (!m_hierarchyCache.isChildOfVisibleNodeOrInvisible(node.id) || Node::intToType(node.type) == Node::NODE_NAMESPACE)) { tokenIds.push_back(node.id); } } addNodesToGraph(tokenIds, graph.get()); return graph; } std::shared_ptr Storage::getGraphForActiveTokenIds(const std::vector& tokenIds, bool activeOnly) const { std::shared_ptr g = std::make_shared(); Graph* graph = g.get(); if (tokenIds.size() == 1 && !activeOnly) { const Id elementId = tokenIds[0]; if (m_sqliteStorage.isNode(elementId)) { const StorageNode node = m_sqliteStorage.getNodeById(elementId); addNodeAndAllChildrenToGraph(getLastVisibleParentNodeId(node.id), graph); std::vector edges = m_sqliteStorage.getEdgesBySourceOrTargetId(node.id); for (size_t i = 0; i < edges.size(); i++) { if (Edge::intToType(edges[i].type) != Edge::EDGE_MEMBER) { addEdgeAndAllChildrenToGraph(edges[i].id, graph); } } addAggregationEdgesToGraph(elementId, graph); } else if (m_sqliteStorage.isEdge(elementId)) { addEdgeAndAllChildrenToGraph(elementId, graph); } } else if (tokenIds.size() >= 1) { for (size_t i = 0; i < tokenIds.size(); i++) { const Id elementId = tokenIds[i]; if (m_sqliteStorage.isNode(elementId)) { addNodeAndAllChildrenToGraph(getLastVisibleParentNodeId(elementId), graph); } else { addEdgeAndAllChildrenToGraph(elementId, graph); } } } addComponentAccessToGraph(graph); return g; } std::vector Storage::getActiveTokenIdsForTokenIds(const std::vector& tokenIds) const { bool different = false; std::vector activeIds; for (Id id : tokenIds) { if (m_sqliteStorage.isNode(id)) { m_hierarchyCache.addFirstVisibleChildIdsForNodeId(id, &activeIds); if (id != activeIds.back()) { different = true; } } else { activeIds.push_back(id); } } if (!different) { return tokenIds; } std::set idSet(activeIds.begin(), activeIds.end()); activeIds.clear(); activeIds.insert(activeIds.end(), idSet.begin(), idSet.end()); return activeIds; } // TODO: rename: getActiveElementIdsForId; TODO: make separate function for declarationId std::vector Storage::getActiveTokenIdsForId(Id tokenId, Id* declarationId) const { std::vector activeTokenIds; if (!(m_sqliteStorage.isEdge(tokenId) || m_sqliteStorage.isNode(tokenId))) { return activeTokenIds; } activeTokenIds.push_back(tokenId); if (m_sqliteStorage.isNode(tokenId)) { *declarationId = tokenId; std::vector incomingEdges = m_sqliteStorage.getEdgesByTargetId(tokenId); for (size_t i = 0; i < incomingEdges.size(); i++) { activeTokenIds.push_back(incomingEdges[i].id); } } return activeTokenIds; } std::vector Storage::getNodeIdsForLocationIds(const std::vector& locationIds) const { std::set nodeIds; std::set edgeIds; for (Id locationId : locationIds) { Id elementId = m_sqliteStorage.getElementIdByLocationId(locationId); StorageEdge edge = m_sqliteStorage.getEdgeById(elementId); if (edge.id != 0) // here we test if location is an edge. { edgeIds.insert(edge.targetNodeId); } else { nodeIds.insert(elementId); } } if (nodeIds.size()) { return utility::toVector(nodeIds); } return utility::toVector(edgeIds); } std::vector Storage::getTokenIdsForMatches(const std::vector& matches) const { std::set idSet; for (const SearchMatch& match : matches) { SearchNode* searchNode = m_tokenIndex.getNode(match.nameHierarchy); if (searchNode) { utility::append(idSet, searchNode->getTokenIds()); } } std::vector ids; for (std::set::const_iterator it = idSet.begin(); it != idSet.end(); it++) { ids.push_back(*it); } return ids; } Id Storage::getTokenIdForFileNode(const FilePath& filePath) const { return m_sqliteStorage.getFileByPath(filePath.str()).id; } std::vector Storage::getTokenIdsForAggregationEdge(Id sourceId, Id targetId) const { std::vector edgeIds; std::vector aggregationEndpointsA = getAllChildNodeIds(sourceId); std::set aggregationEndpointsB; aggregationEndpointsB.insert(targetId); for (const Id targetChildId: getAllChildNodeIds(targetId)) { aggregationEndpointsB.insert(targetChildId); } for (size_t i = 0; i < aggregationEndpointsA.size(); i++) { std::vector outgoingEdges = m_sqliteStorage.getEdgesBySourceId(aggregationEndpointsA[i]); for (size_t j = 0; j < outgoingEdges.size(); j++) { if (aggregationEndpointsB.find(outgoingEdges[j].targetNodeId) != aggregationEndpointsB.end()) { edgeIds.push_back(outgoingEdges[j].id); } } std::vector incomingEdges = m_sqliteStorage.getEdgesByTargetId(aggregationEndpointsA[i]); for (size_t j = 0; j < incomingEdges.size(); j++) { if (aggregationEndpointsB.find(incomingEdges[j].sourceNodeId) != aggregationEndpointsB.end()) { edgeIds.push_back(incomingEdges[j].id); } } } return edgeIds; } std::shared_ptr Storage::getTokenLocationsForTokenIds(const std::vector& tokenIds) const { std::shared_ptr collection = std::make_shared(); std::vector fileIds; std::vector nonFileIds; for (size_t i = 0; i < tokenIds.size(); i++) { if (m_sqliteStorage.isFile(tokenIds[i])) { fileIds.push_back(tokenIds[i]); } else { nonFileIds.push_back(tokenIds[i]); } } for (Id fileId: fileIds) { StorageFile storageFile = m_sqliteStorage.getFileById(fileId); collection->addTokenLocationFileAsPlainCopy(m_sqliteStorage.getTokenLocationsForFile(storageFile.filePath).get()); } Cache filePathCache( [this](Id id) -> std::string { return m_sqliteStorage.getFileById(id).filePath; } ); std::vector locations = m_sqliteStorage.getTokenLocationsForElementIds(nonFileIds); for (size_t i = 0; i < locations.size(); i++) { const StorageSourceLocation& location = locations[i]; std::string filePath = filePathCache.getValue(location.fileNodeId); TokenLocation* loc = collection->addTokenLocation( location.id, location.elementId, filePath, location.startLine, location.startCol, location.endLine, location.endCol ); if (loc) { loc->setType(location.isScope ? TokenLocation::LOCATION_SCOPE : TokenLocation::LOCATION_TOKEN); } } return collection; } std::shared_ptr Storage::getTokenLocationsForLocationIds(const std::vector& locationIds) const { std::shared_ptr collection = std::make_shared(); for (size_t i = 0; i < locationIds.size(); i++) { StorageSourceLocation location = m_sqliteStorage.getSourceLocationById(locationIds[i]); collection->addTokenLocation( location.id, location.elementId, m_sqliteStorage.getFileById(location.fileNodeId).filePath, // TODO: optimize: only once per file! location.startLine, location.startCol, location.endLine, location.endCol)->setType(location.isScope ? TokenLocation::LOCATION_SCOPE : TokenLocation::LOCATION_TOKEN ); } return collection; } std::shared_ptr Storage::getTokenLocationsForFile(const std::string& filePath) const { std::shared_ptr locationFile = m_sqliteStorage.getTokenLocationsForFile(filePath); locationFile->isWholeCopy = true; return locationFile; } std::shared_ptr Storage::getTokenLocationsForLinesInFile( const std::string& filePath, uint firstLineNumber, uint lastLineNumber ) const { return m_sqliteStorage.getTokenLocationsForFile(filePath)->getFilteredByLines(firstLineNumber, lastLineNumber); } TokenLocationCollection Storage::getErrorTokenLocations(std::vector* errorMessages) const { TokenLocationCollection errorCollection; std::vector errors = m_sqliteStorage.getAllErrors(); for (size_t i = 0; i < errors.size(); i++) { const StorageError& error = errors[i]; errorCollection.addTokenLocation( i, i, error.filePath, error.lineNumber, error.columnNumber, error.lineNumber, error.columnNumber); errorMessages->push_back(error.message); } return errorCollection; } std::shared_ptr Storage::getCommentLocationsInFile(const FilePath& filePath) const { std::shared_ptr file = std::make_shared(filePath); std::vector storageLocations = m_sqliteStorage.getCommentLocationsInFile(filePath); for (size_t i = 0; i < storageLocations.size(); i++) { file->addTokenLocation( storageLocations[i].id, 0, // comment token location has no element. storageLocations[i].startLine, storageLocations[i].startCol, storageLocations[i].endLine, storageLocations[i].endCol ); } return file; } std::shared_ptr Storage::getFileContent(const FilePath& filePath) const { return m_sqliteStorage.getFileContentByPath(filePath.str()); } TimePoint Storage::getFileModificationTime(const FilePath& filePath) const { return TimePoint(m_sqliteStorage.getFileByPath(filePath.str()).modificationTime); } ErrorCountInfo Storage::getErrorCount() const { return ErrorCountInfo(m_sqliteStorage.getAllErrors().size(), m_sqliteStorage.getFatalErrors().size()); } StorageStats Storage::getStorageStats() const { StorageStats stats; stats.nodeCount = m_sqliteStorage.getNodeCount(); stats.edgeCount = m_sqliteStorage.getEdgeCount(); // Takes too much time // stats.charCount = m_tokenIndex.getCharCount(); // stats.wordCount = m_tokenIndex.getWordCount(); // stats.searchNodeCount = m_tokenIndex.getNodeCount(); stats.fileCount = m_sqliteStorage.getFileCount(); stats.fileLOCCount = m_sqliteStorage.getFileLOCCount(); stats.sourceLocationCount = m_sqliteStorage.getSourceLocationCount(); stats.errorCount = getErrorCount(); return stats; } Id Storage::addNodeHierarchy(Node::NodeType nodeType, NameHierarchy nameHierarchy, bool defined) { if (nameHierarchy.size() == 0) { return 0; } Id parentNodeId = 0; bool nodeMayExist = true; NameHierarchy currentNameHierarchy; for (size_t i = 0; i < nameHierarchy.size(); i++) { currentNameHierarchy.push(nameHierarchy[i]); const bool isLastElement = (i == nameHierarchy.size() - 1); Node::NodeType type = (isLastElement ? nodeType : Node::NODE_UNDEFINED); StorageNode node(0, 0, "", false); if (nodeMayExist) { node = m_sqliteStorage.getNodeBySerializedName(NameHierarchy::serialize(currentNameHierarchy)); } Id nodeId = node.id; if (nodeId && !node.defined && isLastElement && defined) // todo: move this down! { m_sqliteStorage.setNodeDefined(true, nodeId); } if (nodeId == 0) { nodeMayExist = false; nodeId = m_sqliteStorage.addNode(Node::typeToInt(type), NameHierarchy::serialize(currentNameHierarchy), isLastElement && defined); if (parentNodeId != 0) { addEdge(parentNodeId, nodeId, Edge::EDGE_MEMBER); } } else if (isLastElement) // Update the type of the last node if the new type is more specific. { Node::NodeType storedType = Node::intToType(node.type); if (!node.defined && type > storedType) { m_sqliteStorage.setNodeType(Node::typeToInt(type), nodeId); } } parentNodeId = nodeId; } return parentNodeId; } Id Storage::addSourceLocation(Id elementNodeId, const ParseLocation &location, bool isScope) { if (!location.isValid()) { return 0; } if (location.filePath.empty()) { LOG_ERROR("no filename set!"); return 0; } else { Id fileNodeId = getFileNodeId(location.filePath); if (!fileNodeId) { LOG_ERROR("Can't create source location, file node does not exist for: " + location.filePath.str()); return 0; } Id locationId = m_sqliteStorage.addSourceLocation( elementNodeId, fileNodeId, location.startLineNumber, location.startColumnNumber, location.endLineNumber, location.endColumnNumber, isScope ); return locationId; } } Id Storage::addEdge(Id sourceNodeId, Id targetNodeId, Edge::EdgeType type) { if (!sourceNodeId || !targetNodeId) { return 0; } Id edgeId = m_sqliteStorage.getEdgeBySourceTargetType(sourceNodeId, targetNodeId, type).id; if (!edgeId) { edgeId = m_sqliteStorage.addEdge(type, sourceNodeId, targetNodeId); } return edgeId; } Id Storage::addEdge(Id sourceNodeId, Id targetNodeId, Edge::EdgeType type, ParseLocation location) { if (!sourceNodeId || !targetNodeId) { return 0; } Id edgeId = addEdge(sourceNodeId, targetNodeId, type); addSourceLocation(edgeId, location, false); return edgeId; } Id Storage::getFileNodeId(const FilePath& filePath) const { std::map::const_iterator it = m_fileNodeIds.find(filePath); if (it != m_fileNodeIds.end()) { return it->second; } if (filePath.empty()) { LOG_ERROR("No file path set"); return 0; } StorageFile storageFile = m_sqliteStorage.getFileByPath(filePath.str()); if (storageFile.id == 0) { return 0; } m_fileNodeIds.emplace(filePath, storageFile.id); return storageFile.id; } FilePath Storage::getFileNodePath(Id fileId) const { for (const std::pair& p : m_fileNodeIds) { if (p.second == fileId) { return p.first; } } return m_sqliteStorage.getFileById(fileId).filePath; } Id Storage::getLastVisibleParentNodeId(const Id nodeId) const { return m_hierarchyCache.getLastVisibleParentNodeId(nodeId); } std::vector Storage::getAllChildNodeIds(const Id nodeId) const { std::vector childNodeIds; std::vector edgeIds; m_hierarchyCache.addAllChildIdsForNodeId(nodeId, &childNodeIds, &edgeIds); return childNodeIds; } void Storage::addEdgeAndAllChildrenToGraph(const Id edgeId, Graph* graph) const { StorageEdge storageEdge = m_sqliteStorage.getEdgeById(edgeId); Node* sourceNode = graph->getNodeById(storageEdge.sourceNodeId); Node* targetNode = graph->getNodeById(storageEdge.targetNodeId); if (!sourceNode) { addNodeAndAllChildrenToGraph(getLastVisibleParentNodeId(storageEdge.sourceNodeId), graph); sourceNode = graph->getNodeById(storageEdge.sourceNodeId); } if (!targetNode) { addNodeAndAllChildrenToGraph(getLastVisibleParentNodeId(storageEdge.targetNodeId), graph); targetNode = graph->getNodeById(storageEdge.targetNodeId); } graph->createEdge(edgeId, Edge::intToType(storageEdge.type), sourceNode, targetNode); } Node* Storage::addNodeAndAllChildrenToGraph(const Id nodeId, Graph* graph) const { Node* node = graph->getNodeById(nodeId); if (node) { return node; } std::vector nodeIdsToAdd; std::vector edgeIdsToAdd; nodeIdsToAdd.push_back(nodeId); m_hierarchyCache.addAllChildIdsForNodeId(nodeId, &nodeIdsToAdd, &edgeIdsToAdd); addNodesToGraph(nodeIdsToAdd, graph); addEdgesToGraph(edgeIdsToAdd, graph); return graph->getNodeById(nodeId); } void Storage::addAggregationEdgesToGraph(const Id nodeId, Graph* graph) const { struct EdgeInfo { Id edgeId; bool forward; }; // build aggregation edges: // get all children of the active node std::vector childNodeIds = getAllChildNodeIds(nodeId); // get all edges of the children std::map> connectedNodeIds; std::vector outgoingEdges = m_sqliteStorage.getEdgesBySourceIds(childNodeIds); for (size_t j = 0; j < outgoingEdges.size(); j++) { EdgeInfo edgeInfo; edgeInfo.edgeId = outgoingEdges[j].id; edgeInfo.forward = true; connectedNodeIds[outgoingEdges[j].targetNodeId].push_back(edgeInfo); } std::vector incomingEdges = m_sqliteStorage.getEdgesByTargetIds(childNodeIds); for (size_t j = 0; j < incomingEdges.size(); j++) { EdgeInfo edgeInfo; edgeInfo.edgeId = incomingEdges[j].id; edgeInfo.forward = false; connectedNodeIds[incomingEdges[j].sourceNodeId].push_back(edgeInfo); } // get all parent nodes of all connected nodes (up to last level except namespace/undefined) Id nodeParentNodeId = getLastVisibleParentNodeId(nodeId); std::map> connectedParentNodeIds; for (const std::pair>& p : connectedNodeIds) { Id parentNodeId = getLastVisibleParentNodeId(p.first); if (parentNodeId != nodeParentNodeId) { utility::append(connectedParentNodeIds[parentNodeId], p.second); } } // add hierarchies for these parents and create aggregation edges between parents and active node Node* sourceNode = graph->getNodeById(nodeId); for (const std::pair> p : connectedParentNodeIds) { const Id aggregationTargetNodeId = p.first; Node* targetNode = graph->getNodeById(aggregationTargetNodeId); if (!targetNode) { targetNode = addNodeAndAllChildrenToGraph(aggregationTargetNodeId, graph); } std::shared_ptr componentAggregation = std::make_shared(); for (const EdgeInfo& edgeInfo: p.second) { componentAggregation->addAggregationId(edgeInfo.edgeId, edgeInfo.forward); } Edge* edge = graph->createEdge( *componentAggregation->getAggregationIds().begin(), Edge::EDGE_AGGREGATION, sourceNode, targetNode ); edge->addComponentAggregation(componentAggregation); } } void Storage::addNodesToGraph(const std::vector nodeIds, Graph* graph) const { std::vector storageNodes = m_sqliteStorage.getNodesByIds(nodeIds); for (const StorageNode& storageNode : storageNodes) { NameHierarchy nameHierarchy = NameHierarchy::deserialize(storageNode.serializedName); Node::NodeType type = Node::intToType(storageNode.type); Node* node = graph->createNode( storageNode.id, type, nameHierarchy, storageNode.defined ); if (type == Node::NODE_FUNCTION || type == Node::NODE_METHOD) { std::string signatureString = nameHierarchy.getRawNameWithSignature(); if (signatureString.size() > 0) // this should always be the case since functions and methods must have sigs. { node->addComponentSignature( std::make_shared(signatureString) ); } } } } void Storage::addEdgesToGraph(const std::vector edgeIds, Graph* graph) const { std::vector storageEdges = m_sqliteStorage.getEdgesByIds(edgeIds); for (const StorageEdge& storageEdge : storageEdges) { Node* sourceNode = graph->getNodeById(storageEdge.sourceNodeId); Node* targetNode = graph->getNodeById(storageEdge.targetNodeId); if (sourceNode && targetNode) { graph->createEdge(storageEdge.id, Edge::intToType(storageEdge.type), sourceNode, targetNode); } else { LOG_ERROR("Can't add edge because nodes are not present"); } } } void Storage::addComponentAccessToGraph(Graph* graph) const { std::vector memberEdgeIds; graph->forEachEdge( [&memberEdgeIds](Edge* edge) { if (!edge->isType(Edge::EDGE_MEMBER)) { return; } memberEdgeIds.push_back(edge->getId()); } ); std::vector accesses = m_sqliteStorage.getComponentAccessByMemberEdgeIds(memberEdgeIds); for (const StorageComponentAccess& access : accesses) { if (access.memberEdgeId && access.type) { graph->getEdgeById(access.memberEdgeId)->addComponentAccess( std::make_shared(TokenComponentAccess::intToType(access.type))); } } } void Storage::buildSearchIndex() { for (StorageNode node: m_sqliteStorage.getAllNodes()) { m_tokenIndex.addTokenId(m_tokenIndex.addNode(NameHierarchy::deserialize(node.serializedName)), node.id); } } void Storage::buildHierarchyCache() { std::vector memberEdges = m_sqliteStorage.getEdgesByType(Edge::typeToInt(Edge::EDGE_MEMBER)); Cache nodeTypeCache([this](Id id){ return Node::intToType(m_sqliteStorage.getNodeById(id).type); }); for (const StorageEdge& edge : memberEdges) { bool isVisible = !(nodeTypeCache.getValue(edge.sourceNodeId) & Node::NODE_NOT_VISIBLE); m_hierarchyCache.createConnection(edge.id, edge.sourceNodeId, edge.targetNodeId, isVisible); } }