From 598041f896ec2a77d55eff69dbab84b7560396b1 Mon Sep 17 00:00:00 2001 From: Eberhard Graether Date: Tue, 3 Mar 2015 00:33:13 +0100 Subject: [PATCH] data: parsing file dependencies This change adds the node NODE_FILE to the graph and the edge EDGE_INCLUDE, which determine the dependencies between files by parsing the include preprocessor directive. File nodes can be searched and displayed in the GraphView as file dependency graph. The filter "file" allows for selecting all files. The file depency information is used on project refresh do determine which files need to get reparsed. --- bin/test/data/log/test_log.txt | 91 ++++++----- src/app/qt/view/graphElements/QtGraphNode.cpp | 2 + src/lib/CMakeLists.txt | 2 + src/lib/Project.cpp | 29 ++-- .../component/controller/CodeController.cpp | 3 +- .../component/controller/GraphController.cpp | 1 + src/lib/data/Storage.cpp | 143 +++++++++++++++--- src/lib/data/Storage.h | 11 +- src/lib/data/access/GraphAccess.h | 1 - src/lib/data/access/GraphAccessProxy.cpp | 10 -- src/lib/data/access/GraphAccessProxy.h | 1 - src/lib/data/access/LocationAccess.h | 2 +- src/lib/data/access/LocationAccessProxy.cpp | 4 +- src/lib/data/access/LocationAccessProxy.h | 2 +- src/lib/data/graph/Edge.cpp | 9 ++ src/lib/data/graph/Edge.h | 4 +- src/lib/data/graph/Node.cpp | 15 +- src/lib/data/graph/Node.h | 4 +- .../graph/filter/GraphFilterConductor.cpp | 4 + src/lib/data/parser/ParserClient.h | 4 + src/lib/data/parser/cxx/ASTAction.cpp | 15 ++ src/lib/data/parser/cxx/ASTAction.h | 2 + .../data/parser/cxx/PreprocessorCallbacks.cpp | 52 +++++++ .../data/parser/cxx/PreprocessorCallbacks.h | 31 ++++ src/lib/data/query/QueryCommand.cpp | 2 + src/lib/data/query/QueryCommand.h | 4 +- src/lib/utility/file/FileManager.cpp | 27 ++-- src/lib/utility/file/FileManager.h | 15 +- src/test/CxxParserTestSuite.h | 20 +++ src/test/FileManagerTestSuite.h | 32 +--- src/test/GraphFilterConductorTestSuite.h | 31 ++-- src/test/StorageTestSuite.h | 77 +++++++++- 32 files changed, 482 insertions(+), 168 deletions(-) create mode 100644 src/lib/data/parser/cxx/PreprocessorCallbacks.cpp create mode 100644 src/lib/data/parser/cxx/PreprocessorCallbacks.h diff --git a/bin/test/data/log/test_log.txt b/bin/test/data/log/test_log.txt index 66447c43..5ef4bcdf 100644 --- a/bin/test/data/log/test_log.txt +++ b/bin/test/data/log/test_log.txt @@ -1,37 +1,11 @@ ConfigManager.cpp ERROR: value path/to/nowhere is not present in config. -Storage.cpp INFO: class: A -Storage.cpp INFO: method: A::A -Storage.cpp INFO: global usage: A::A -> A::count -Storage.cpp INFO: method: A::A -Storage.cpp INFO: global usage: A::A -> A::count -Storage.cpp INFO: method: A::getCount -Storage.cpp INFO: global usage: A::getCount -> A::count -Storage.cpp INFO: method: A::process -Storage.cpp INFO: field: A::count -Storage.cpp INFO: class: B -Storage.cpp INFO: inheritance: B : A -Storage.cpp INFO: method: B::process -Storage.cpp INFO: override: A::process -> B::process < 0:0 0:0> -Storage.cpp INFO: type usage: B::process -> int -Storage.cpp INFO: function: main -Storage.cpp INFO: type usage: main -> B -Storage.cpp INFO: call: main -> B::B -Storage.cpp INFO: call: main -> A::getCount -SearchMatch.cpp INFO: -1 matches for "main": -474 main - ^^^^ - -SearchMatch.cpp INFO: -1 matches for "main": -474 main - ^^^^ - -SearchMatch.cpp INFO: -1 matches for "A::A": -237 A::A - ^^^^ - +Token.cpp ERROR: Location Id was not referenced by this Token. +Node.cpp WARNING: Cannot change NodeType after it was already set from namespace to class +Edge.cpp ERROR: Nodes are not plain copies. +Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined +Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined +Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined +Storage.cpp INFO: file: input.cc < 0:0 0:0> Storage.cpp INFO: class: A Storage.cpp INFO: method: A::A Storage.cpp INFO: global usage: A::A -> A::count @@ -48,12 +22,40 @@ Storage.cpp INFO: function: main Storage.cpp INFO: type usage: main -> B Storage.cpp INFO: call: main -> B::B Storage.cpp INFO: call: main -> A::getCount -Token.cpp ERROR: Location Id was not referenced by this Token. -Node.cpp WARNING: Cannot change NodeType after it was already set from namespace to class -Edge.cpp ERROR: Nodes are not plain copies. -Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined -Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined -Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined +Storage.cpp INFO: file: input.cc < 0:0 0:0> +Storage.cpp INFO: class: A +Storage.cpp INFO: method: A::A +Storage.cpp INFO: global usage: A::A -> A::count +Storage.cpp INFO: method: A::A +Storage.cpp INFO: global usage: A::A -> A::count +Storage.cpp INFO: method: A::getCount +Storage.cpp INFO: global usage: A::getCount -> A::count +Storage.cpp INFO: method: A::process +Storage.cpp INFO: field: A::count +Storage.cpp INFO: class: B +Storage.cpp INFO: inheritance: B : A +Storage.cpp INFO: method: B::process +Storage.cpp INFO: override: A::process -> B::process < 0:0 0:0> +Storage.cpp INFO: type usage: B::process -> int +Storage.cpp INFO: function: _main_ +Storage.cpp INFO: type usage: _main_ -> B +Storage.cpp INFO: call: _main_ -> B::B +Storage.cpp INFO: call: _main_ -> A::getCount +SearchMatch.cpp INFO: +1 matches for "_main_": +755 _main_ + ^^^^^^ + +SearchMatch.cpp INFO: +1 matches for "_main_": +755 _main_ + ^^^^^^ + +SearchMatch.cpp INFO: +1 matches for "A::A": +237 A::A + ^^^^ + Settings.cpp WARNING: File for Settings not found. ConfigManager.cpp ERROR: value Bool is not present in config. ConfigManager.cpp ERROR: value Int is not present in config. @@ -69,7 +71,6 @@ ConfigManager.cpp ERROR: value Int is not present in config. ConfigManager.cpp ERROR: value Float is not present in config. ConfigManager.cpp ERROR: value String is not present in config. ConfigManager.cpp ERROR: value NewBool is not present in config. -Graph.cpp ERROR: Can't remove member edge, without removing the child node. Storage.cpp INFO: typedef: type -> int Storage.cpp INFO: class: Class Storage.cpp INFO: struct: Struct @@ -125,6 +126,16 @@ Storage.cpp INFO: call: main -> isTrue Storage.cpp INFO: function: isTrue Storage.cpp INFO: function: main Storage.cpp INFO: call: main -> isTrue +Storage.cpp INFO: file: file.h < 0:0 0:0> +Storage.cpp INFO: file: file.h < 0:0 0:0> +Storage.cpp INFO: file: file.cpp < 0:0 0:0> +Storage.cpp INFO: include: file.h +Storage.cpp INFO: file: f.h < 0:0 0:0> +Storage.cpp INFO: file: file.h < 0:0 0:0> +Storage.cpp INFO: file: file.cpp < 0:0 0:0> +Storage.cpp INFO: include: f.h +Storage.cpp INFO: include: file.h +Graph.cpp ERROR: Can't remove member edge, without removing the child node. TextAccess.cpp WARNING: Index 'firstLine' has to be lower or equal index 'lastLine', is 3 > 2 TextAccess.cpp WARNING: Tried to access index 10. Maximum index is 8 TextAccess.cpp WARNING: Tried to access index 10. Maximum index is 8 diff --git a/src/app/qt/view/graphElements/QtGraphNode.cpp b/src/app/qt/view/graphElements/QtGraphNode.cpp index 08592bdd..a1c23581 100644 --- a/src/app/qt/view/graphElements/QtGraphNode.cpp +++ b/src/app/qt/view/graphElements/QtGraphNode.cpp @@ -49,6 +49,7 @@ QFont QtGraphNode::getFontForNodeType(Node::NodeType type) case Node::NODE_ENUM: case Node::NODE_TYPEDEF: case Node::NODE_TEMPLATE_PARAMETER_TYPE: + case Node::NODE_FILE: font.setPixelSize(14); break; @@ -321,6 +322,7 @@ void QtGraphNode::setStyle() case Node::NODE_ENUM: case Node::NODE_TYPEDEF: case Node::NODE_TEMPLATE_PARAMETER_TYPE: + case Node::NODE_FILE: if (m_isActive) { font.setWeight(QFont::Bold); diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index ee215dd8..784c86f7 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -17,6 +17,8 @@ add_files( data/parser/cxx/CxxDiagnosticConsumer.h data/parser/cxx/CxxParser.cpp data/parser/cxx/CxxParser.h + data/parser/cxx/PreprocessorCallbacks.cpp + data/parser/cxx/PreprocessorCallbacks.h data/parser/cxx/utilityCxx.cpp data/parser/cxx/utilityCxx.h ) diff --git a/src/lib/Project.cpp b/src/lib/Project.cpp index 72eb5ee5..01514b87 100644 --- a/src/lib/Project.cpp +++ b/src/lib/Project.cpp @@ -84,33 +84,42 @@ void Project::parseCode() { std::vector includePaths; includePaths.push_back(sourcePath); + + // TODO: move this creation to another place (after projectsettings have been loaded) if (!m_fileManager) { std::vector sourcePaths; sourcePaths.push_back(sourcePath); + std::vector sourceExtensions; sourceExtensions.push_back(".cpp"); sourceExtensions.push_back(".cc"); + std::vector includeExtensions; includeExtensions.push_back(".h"); includeExtensions.push_back(".hpp"); - m_fileManager = std::make_shared(sourcePaths, includePaths, sourceExtensions, includeExtensions); // todo: move this creation to another place (after projectsettings have been loaded) + + m_fileManager = std::make_shared(sourcePaths, includePaths, sourceExtensions, includeExtensions); } m_fileManager->fetchFilePaths(); - std::vector addedFilePaths = m_fileManager->getAddedFilePaths(); - std::vector updatedFilePaths = m_fileManager->getUpdatedFilePaths(); - std::vector removedFilePaths = m_fileManager->getRemovedFilePaths(); + std::set addedFilePaths = m_fileManager->getAddedFilePaths(); + std::set updatedFilePaths = m_fileManager->getUpdatedFilePaths(); + std::set removedFilePaths = m_fileManager->getRemovedFilePaths(); + + std::set dependingFilePaths; + dependingFilePaths = m_storage->getDependingFilePathsAndRemoveFileNodes(updatedFilePaths); + updatedFilePaths.insert(dependingFilePaths.begin(), dependingFilePaths.end()); + + dependingFilePaths = m_storage->getDependingFilePathsAndRemoveFileNodes(removedFilePaths); + updatedFilePaths.insert(dependingFilePaths.begin(), dependingFilePaths.end()); - m_storage->clearFileData(addedFilePaths); m_storage->clearFileData(updatedFilePaths); m_storage->clearFileData(removedFilePaths); - std::vector filesToParse = addedFilePaths; - for (std::string updatedFilePath: updatedFilePaths) - { - filesToParse.push_back(updatedFilePath); - } + std::vector filesToParse; + filesToParse.insert(filesToParse.end(), addedFilePaths.begin(), addedFilePaths.end()); + filesToParse.insert(filesToParse.end(), updatedFilePaths.begin(), updatedFilePaths.end()); if (filesToParse.size() == 0) { diff --git a/src/lib/component/controller/CodeController.cpp b/src/lib/component/controller/CodeController.cpp index 57f85297..18dd93da 100644 --- a/src/lib/component/controller/CodeController.cpp +++ b/src/lib/component/controller/CodeController.cpp @@ -96,8 +96,7 @@ CodeView* CodeController::getView() std::vector CodeController::getSnippetsForActiveTokenIds( const std::vector& ids, Id declarationId ) const { - std::vector locationIds = m_graphAccess->getLocationIdsForTokenIds(ids); - TokenLocationCollection collection = m_locationAccess->getTokenLocationsForLocationIds(locationIds); + TokenLocationCollection collection = m_locationAccess->getTokenLocationsForTokenIds(ids); std::vector snippets; diff --git a/src/lib/component/controller/GraphController.cpp b/src/lib/component/controller/GraphController.cpp index 238181cb..ad7745a1 100644 --- a/src/lib/component/controller/GraphController.cpp +++ b/src/lib/component/controller/GraphController.cpp @@ -467,6 +467,7 @@ GraphController::Margins GraphController::getMarginsForDummyNode(DummyNode& node case Node::NODE_ENUM: case Node::NODE_TYPEDEF: case Node::NODE_TEMPLATE_PARAMETER_TYPE: + case Node::NODE_FILE: if (node.subNodes.size()) { margins.left = margins.right = 15; diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index 3c4c0c9e..176e2754 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -2,6 +2,7 @@ #include "utility/logging/logging.h" #include "utility/utilityString.h" +#include "utility/file/FileSystem.h" #include "data/graph/filter/GraphFilterConductor.h" #include "data/graph/token_component/TokenComponentConst.h" @@ -41,7 +42,7 @@ void Storage::clear() m_errorLocationCollection.clear(); } -void Storage::clearFileData(const std::vector& filePaths) +void Storage::clearFileData(const std::set& filePaths) { for (const std::string& filePath : filePaths) { @@ -98,6 +99,36 @@ void Storage::clearFileData(const std::vector& filePaths) } } +std::set Storage::getDependingFilePathsAndRemoveFileNodes(const std::set& filePaths) +{ + std::set dependingFilePaths; + + for (const std::string& filePath : filePaths) + { + SearchNode* searchNode = m_tokenIndex.getNode(filePath); + if (!searchNode || searchNode->getTokenIds().size() != 1) + { + continue; + } + + Node* fileNode = m_graph.getNodeById(searchNode->getFirstTokenId()); + if (!fileNode->isType(Node::NODE_FILE)) + { + LOG_ERROR("Node is not of type file."); + continue; + } + + addDependingFilePathsAndRemoveFileNodesRecursive(fileNode, &dependingFilePaths); + } + + for (const std::string& path : filePaths) + { + dependingFilePaths.erase(path); + } + + return dependingFilePaths; +} + void Storage::logGraph() const { LOG_INFO_STREAM(<< '\n' << m_graph); @@ -605,6 +636,27 @@ Id Storage::onTemplateFunctionSpecializationParsed( return specializedFunctionNode->getId(); } +Id Storage::onFileParsed(const std::string& filePath) +{ + log("file", filePath, ParseLocation()); + + Node* fileNode = addNodeHierarchy(Node::NODE_FILE, std::vector(1, FileSystem::absoluteFilePath(filePath))); + return fileNode->getId(); +} + +Id Storage::onFileIncludeParsed(const ParseLocation& location, const std::string& filePath, const std::string& includedPath) +{ + log("include", includedPath, location); + + Node* fileNode = addNodeHierarchy(Node::NODE_FILE, std::vector(1, FileSystem::absoluteFilePath(filePath))); + Node* includedFileNode = addNodeHierarchy(Node::NODE_FILE, std::vector(1, FileSystem::absoluteFilePath(includedPath))); + + Edge* edge = m_graph.createEdge(Edge::EDGE_INCLUDE, fileNode, includedFileNode); + addTokenLocation(edge, location); + + return edge->getId(); +} + Id Storage::getIdForNodeWithName(const std::string& fullName) const { SearchNode* node = m_tokenIndex.getNode(fullName); @@ -823,24 +875,6 @@ std::vector Storage::getActiveTokenIdsForLocationId(Id locationId) const 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; -} - std::vector Storage::getTokenIdsForQuery(std::string query) const { QueryTree tree(query); @@ -854,17 +888,43 @@ std::vector Storage::getTokenIdsForQuery(std::string query) const return outGraph.getTokenIds(); } -TokenLocationCollection Storage::getTokenLocationsForLocationIds(const std::vector& locationIds) const +TokenLocationCollection Storage::getTokenLocationsForTokenIds(const std::vector& tokenIds) const { TokenLocationCollection ret; - for (Id locationId: locationIds) + for (Id tokenId : tokenIds) { - TokenLocation* location = m_locationCollection.findTokenLocationById(locationId); - if (location->getOtherTokenLocation()) + Token* token = m_graph.getTokenById(tokenId); + if (!token) { - ret.addTokenLocationAsPlainCopy(location); - ret.addTokenLocationAsPlainCopy(location->getOtherTokenLocation()); + continue; + } + + if (token->isNode() && dynamic_cast(token)->isType(Node::NODE_FILE)) + { + TokenLocationFile* locationFile = + m_locationCollection.findTokenLocationFileByPath(dynamic_cast(token)->getFullName()); + if (locationFile) + { + locationFile->forEachTokenLocation( + [&ret](TokenLocation* tokenLocation) -> void + { + ret.addTokenLocationAsPlainCopy(tokenLocation); + } + ); + } + } + else + { + for (Id locationId: token->getLocationIds()) + { + TokenLocation* location = m_locationCollection.findTokenLocationById(locationId); + if (location->getOtherTokenLocation()) + { + ret.addTokenLocationAsPlainCopy(location); + ret.addTokenLocationAsPlainCopy(location->getOtherTokenLocation()); + } + } } } @@ -1177,6 +1237,39 @@ bool Storage::getQuerySearchResults(const std::string& query, const std::string& return true; } +void Storage::addDependingFilePathsAndRemoveFileNodesRecursive(Node* fileNode, std::set* filePaths) +{ + bool inserted = filePaths->insert(fileNode->getFullName()).second; + if (!inserted) + { + return; + } + + while (true) + { + Edge* edge = fileNode->findEdgeOfType(Edge::EDGE_INCLUDE); + if (!edge) + { + break; + } + + Node* dependantNode = nullptr; + if (edge->getTo() == fileNode) + { + dependantNode = edge->getFrom(); + } + + m_graph.removeEdge(edge); + + if (dependantNode) + { + addDependingFilePathsAndRemoveFileNodesRecursive(dependantNode, filePaths); + } + } + + removeNodeIfUnreferenced(fileNode); +} + void Storage::removeNodeIfUnreferenced(Node* node) { Id tokenId = node->getId(); diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index 7370b34a..45203d1f 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -23,7 +23,8 @@ public: virtual ~Storage(); void clear(); - void clearFileData(const std::vector& filePaths); + void clearFileData(const std::set& filePaths); + std::set getDependingFilePathsAndRemoveFileNodes(const std::set& filePaths); void logGraph() const; void logLocations() const; @@ -100,6 +101,10 @@ public: virtual Id onTemplateFunctionSpecializationParsed( const ParseLocation& location, const ParseFunction specializedFunction, const ParseFunction templateFunction); + virtual Id onFileParsed(const std::string& filePath); + virtual Id onFileIncludeParsed( + const ParseLocation& location, const std::string& filePath, const std::string& includedPath); + // GraphAccess implementation virtual Id getIdForNodeWithName(const std::string& fullName) const; virtual std::string getNameForNodeWithId(Id id) const; @@ -110,12 +115,11 @@ public: virtual std::vector getActiveTokenIdsForId(Id tokenId, Id* declarationId) const; virtual std::vector getActiveTokenIdsForLocationId(Id locationId) const; - virtual std::vector getLocationIdsForTokenIds(const std::vector& tokenIds) const; virtual std::vector getTokenIdsForQuery(std::string query) const; // LocationAccess implementation - virtual TokenLocationCollection getTokenLocationsForLocationIds(const std::vector& locationIds) const; + virtual TokenLocationCollection getTokenLocationsForTokenIds(const std::vector& tokenIds) const; virtual TokenLocationFile getTokenLocationsForFile(const std::string& filePath) const; virtual TokenLocationFile getTokenLocationsForLinesInFile( const std::string& filePath, uint firstLineNumber, uint lastLineNumber @@ -143,6 +147,7 @@ private: bool getQuerySearchResults(const std::string& query, const std::string& word, SearchResults* results) const; + void addDependingFilePathsAndRemoveFileNodesRecursive(Node* fileNode, std::set* filePaths); void removeNodeIfUnreferenced(Node* node); void log(std::string type, std::string str, const ParseLocation& location) const; diff --git a/src/lib/data/access/GraphAccess.h b/src/lib/data/access/GraphAccess.h index d0adb659..de0717ad 100644 --- a/src/lib/data/access/GraphAccess.h +++ b/src/lib/data/access/GraphAccess.h @@ -23,7 +23,6 @@ public: virtual std::vector getActiveTokenIdsForId(Id tokenId, Id* declarationId) const = 0; virtual std::vector getActiveTokenIdsForLocationId(Id locationId) const = 0; - virtual std::vector getLocationIdsForTokenIds(const std::vector& tokenIds) const = 0; virtual std::vector getTokenIdsForQuery(std::string query) const = 0; }; diff --git a/src/lib/data/access/GraphAccessProxy.cpp b/src/lib/data/access/GraphAccessProxy.cpp index 29d468f7..3784b104 100644 --- a/src/lib/data/access/GraphAccessProxy.cpp +++ b/src/lib/data/access/GraphAccessProxy.cpp @@ -89,16 +89,6 @@ std::vector GraphAccessProxy::getActiveTokenIdsForLocationId(Id locationId) return std::vector(); } -std::vector GraphAccessProxy::getLocationIdsForTokenIds(const std::vector& tokenIds) const -{ - if (hasSubject()) - { - return m_subject->getLocationIdsForTokenIds(tokenIds); - } - - return std::vector(); -} - std::vector GraphAccessProxy::getTokenIdsForQuery(std::string query) const { if (hasSubject()) diff --git a/src/lib/data/access/GraphAccessProxy.h b/src/lib/data/access/GraphAccessProxy.h index 311c6424..b45fa41f 100644 --- a/src/lib/data/access/GraphAccessProxy.h +++ b/src/lib/data/access/GraphAccessProxy.h @@ -22,7 +22,6 @@ public: virtual std::vector getActiveTokenIdsForId(Id tokenId, Id* declarationId) const; virtual std::vector getActiveTokenIdsForLocationId(Id locationId) const; - virtual std::vector getLocationIdsForTokenIds(const std::vector& tokenIds) const; virtual std::vector getTokenIdsForQuery(std::string query) const; diff --git a/src/lib/data/access/LocationAccess.h b/src/lib/data/access/LocationAccess.h index a0f7ea08..2ca2f3a4 100644 --- a/src/lib/data/access/LocationAccess.h +++ b/src/lib/data/access/LocationAccess.h @@ -13,7 +13,7 @@ class LocationAccess { public: virtual ~LocationAccess(); - virtual TokenLocationCollection getTokenLocationsForLocationIds(const std::vector& locationIds) const = 0; + virtual TokenLocationCollection getTokenLocationsForTokenIds(const std::vector& tokenIds) const = 0; virtual TokenLocationFile getTokenLocationsForFile(const std::string& filePath) const = 0; virtual TokenLocationFile getTokenLocationsForLinesInFile( const std::string& filePath, uint firstLineNumber, uint lastLineNumber diff --git a/src/lib/data/access/LocationAccessProxy.cpp b/src/lib/data/access/LocationAccessProxy.cpp index c067abad..97d05e53 100644 --- a/src/lib/data/access/LocationAccessProxy.cpp +++ b/src/lib/data/access/LocationAccessProxy.cpp @@ -29,11 +29,11 @@ void LocationAccessProxy::setSubject(LocationAccess* subject) m_subject = subject; } -TokenLocationCollection LocationAccessProxy::getTokenLocationsForLocationIds(const std::vector& locationIds) const +TokenLocationCollection LocationAccessProxy::getTokenLocationsForTokenIds(const std::vector& tokenIds) const { if (hasSubject()) { - return m_subject->getTokenLocationsForLocationIds(locationIds); + return m_subject->getTokenLocationsForTokenIds(tokenIds); } return TokenLocationCollection(); diff --git a/src/lib/data/access/LocationAccessProxy.h b/src/lib/data/access/LocationAccessProxy.h index 8b6b6445..e87caf36 100644 --- a/src/lib/data/access/LocationAccessProxy.h +++ b/src/lib/data/access/LocationAccessProxy.h @@ -13,7 +13,7 @@ public: void setSubject(LocationAccess* subject); // LocationAccess implementation - virtual TokenLocationCollection getTokenLocationsForLocationIds(const std::vector& locationIds) const; + virtual TokenLocationCollection getTokenLocationsForTokenIds(const std::vector& tokenIds) const; virtual TokenLocationFile getTokenLocationsForFile(const std::string& filePath) const; virtual TokenLocationFile getTokenLocationsForLinesInFile( const std::string& filePath, uint firstLineNumber, uint lastLineNumber diff --git a/src/lib/data/graph/Edge.cpp b/src/lib/data/graph/Edge.cpp index 8f04ee90..cec35d4c 100644 --- a/src/lib/data/graph/Edge.cpp +++ b/src/lib/data/graph/Edge.cpp @@ -141,6 +141,8 @@ std::string Edge::getTypeString(EdgeType type) const return "template default argument"; case EDGE_TEMPLATE_SPECIALIZATION_OF: return "template specialization"; + case EDGE_INCLUDE: + return "include"; case EDGE_AGGREGATION: return "aggregation"; } @@ -270,6 +272,13 @@ bool Edge::checkType() const } return true; + case EDGE_INCLUDE: + if (!m_from->isType(Node::NODE_FILE) || !m_to->isType(Node::NODE_FILE)) + { + break; + } + return true; + case EDGE_AGGREGATION: if (!m_from->isType(typeMask | variableMask | functionMask) || !m_to->isType(typeMask | variableMask | functionMask)) { diff --git a/src/lib/data/graph/Edge.h b/src/lib/data/graph/Edge.h index e438fe7c..22f5be5d 100644 --- a/src/lib/data/graph/Edge.h +++ b/src/lib/data/graph/Edge.h @@ -32,7 +32,9 @@ public: EDGE_TEMPLATE_DEFAULT_ARGUMENT_OF = 0x1000, EDGE_TEMPLATE_SPECIALIZATION_OF = 0x2000, - EDGE_AGGREGATION = 0x4000 + EDGE_INCLUDE = 0x4000, + + EDGE_AGGREGATION = 0x8000 }; Edge(EdgeType type, Node* from, Node* to); diff --git a/src/lib/data/graph/Node.cpp b/src/lib/data/graph/Node.cpp index 3f16198c..0b6e75f4 100644 --- a/src/lib/data/graph/Node.cpp +++ b/src/lib/data/graph/Node.cpp @@ -2,12 +2,14 @@ #include +#include "utility/file/FileSystem.h" +#include "utility/logging/logging.h" + #include "data/graph/token_component/TokenComponentAbstraction.h" #include "data/graph/token_component/TokenComponentConst.h" #include "data/graph/token_component/TokenComponentName.h" #include "data/graph/token_component/TokenComponentStatic.h" #include "data/graph/token_component/TokenComponentSignature.h" -#include "utility/logging/logging.h" Node::Node(NodeType type, std::shared_ptr nameComponent) : m_type(type) @@ -50,7 +52,14 @@ bool Node::isType(NodeTypeMask mask) const std::string Node::getName() const { - return m_nameComponent->getName(); + if (isType(NODE_FILE)) + { + return FileSystem::fileName(m_nameComponent->getName()); + } + else + { + return m_nameComponent->getName(); + } } std::string Node::getFullName() const @@ -342,6 +351,8 @@ std::string Node::getTypeString(NodeType type) const return "typedef"; case NODE_TEMPLATE_PARAMETER_TYPE: return "template parameter type"; + case NODE_FILE: + return "file"; } return ""; } diff --git a/src/lib/data/graph/Node.h b/src/lib/data/graph/Node.h index 9234dcef..34a7aff9 100644 --- a/src/lib/data/graph/Node.h +++ b/src/lib/data/graph/Node.h @@ -37,7 +37,9 @@ public: NODE_ENUM = 0x800, NODE_ENUM_CONSTANT = 0x1000, NODE_TYPEDEF = 0x2000, - NODE_TEMPLATE_PARAMETER_TYPE = 0x4000 + NODE_TEMPLATE_PARAMETER_TYPE = 0x4000, + + NODE_FILE = 0x8000 }; Node(NodeType type, std::shared_ptr nameComponent); diff --git a/src/lib/data/graph/filter/GraphFilterConductor.cpp b/src/lib/data/graph/filter/GraphFilterConductor.cpp index 023aa3b3..4dae0882 100644 --- a/src/lib/data/graph/filter/GraphFilterConductor.cpp +++ b/src/lib/data/graph/filter/GraphFilterConductor.cpp @@ -174,6 +174,10 @@ void GraphFilterConductor::filterCommandNode(const QueryCommand* node, const Fil GraphFilterCommandInheritance(false).apply(in, out); break; + case QueryCommand::COMMAND_FILE: + GraphFilterCommandNodeType(Node::NODE_FILE).apply(in, out); + break; + default: LOG_ERROR_STREAM(<< "QueryCommand not supported: " << node->getType()); GraphFilter().apply(in, out); diff --git a/src/lib/data/parser/ParserClient.h b/src/lib/data/parser/ParserClient.h index b90ce635..80ede54b 100644 --- a/src/lib/data/parser/ParserClient.h +++ b/src/lib/data/parser/ParserClient.h @@ -116,6 +116,10 @@ public: const ParseFunction function) = 0; virtual Id onTemplateFunctionSpecializationParsed( const ParseLocation& location, const ParseFunction specializedFunction, const ParseFunction templateFunction) = 0; + + virtual Id onFileParsed(const std::string& filePath) = 0; + virtual Id onFileIncludeParsed( + const ParseLocation& location, const std::string& filePath, const std::string& includedPath) = 0; }; #endif // PARSER_CLIENT_H diff --git a/src/lib/data/parser/cxx/ASTAction.cpp b/src/lib/data/parser/cxx/ASTAction.cpp index db37e4e1..97b28bb0 100644 --- a/src/lib/data/parser/cxx/ASTAction.cpp +++ b/src/lib/data/parser/cxx/ASTAction.cpp @@ -1,5 +1,9 @@ #include "data/parser/cxx/ASTAction.h" +#include "clang/Lex/Preprocessor.h" + +#include "data/parser/cxx/PreprocessorCallbacks.h" + ASTAction::ASTAction(ParserClient* client, FileManager* fileManager) : m_client(client) , m_fileManager(fileManager) @@ -14,3 +18,14 @@ std::unique_ptr ASTAction::CreateASTConsumer(clang::Compiler { return std::unique_ptr(new ASTConsumer(&compiler.getASTContext(), m_client, m_fileManager)); } + +bool ASTAction::BeginSourceFileAction(clang::CompilerInstance& compiler, llvm::StringRef filePath) +{ + m_client->onFileParsed(filePath.str()); + + clang::Preprocessor& preprocessor = compiler.getPreprocessor(); + preprocessor.addPPCallbacks( + llvm::make_unique(compiler.getSourceManager(), m_client, m_fileManager)); + + return true; +} diff --git a/src/lib/data/parser/cxx/ASTAction.h b/src/lib/data/parser/cxx/ASTAction.h index 60ab5690..8fc4a333 100644 --- a/src/lib/data/parser/cxx/ASTAction.h +++ b/src/lib/data/parser/cxx/ASTAction.h @@ -15,6 +15,8 @@ public: virtual std::unique_ptr CreateASTConsumer(clang::CompilerInstance& compiler, llvm::StringRef inFile); + virtual bool BeginSourceFileAction(clang::CompilerInstance& compiler, llvm::StringRef filePath); + private: ParserClient* m_client; FileManager* m_fileManager; diff --git a/src/lib/data/parser/cxx/PreprocessorCallbacks.cpp b/src/lib/data/parser/cxx/PreprocessorCallbacks.cpp new file mode 100644 index 00000000..9a4bf7bc --- /dev/null +++ b/src/lib/data/parser/cxx/PreprocessorCallbacks.cpp @@ -0,0 +1,52 @@ +#include "data/parser/cxx/PreprocessorCallbacks.h" + +#include "utility/file/FileManager.h" +#include "data/parser/ParserClient.h" +#include "data/parser/ParseLocation.h" + +PreprocessorCallbacks::PreprocessorCallbacks( + clang::SourceManager& sourceManager, ParserClient* client, FileManager* fileManager +) + : m_sourceManager(sourceManager) + , m_client(client) + , m_fileManager(fileManager) +{ +} + +void PreprocessorCallbacks::InclusionDirective( + clang::SourceLocation hashLocation, const clang::Token& includeToken, llvm::StringRef fileName, bool isAngled, + clang::CharSourceRange fileNameRange, const clang::FileEntry* fileEntry, llvm::StringRef searchPath, + llvm::StringRef relativePath, const clang::Module* imported +){ + const clang::FileEntry* baseFileEntry = m_sourceManager.getFileEntryForID(m_sourceManager.getFileID(hashLocation)); + if (fileEntry && baseFileEntry) + { + std::string baseFilePath = baseFileEntry->getName(); + std::string filePath = fileEntry->getName(); + + if (m_fileManager->hasFilePath(baseFilePath) && m_fileManager->hasFilePath(filePath)) + { + m_client->onFileIncludeParsed( + getParseLocation(fileNameRange.getAsRange()), baseFileEntry->getName(), fileEntry->getName()); + } + } +} + +ParseLocation PreprocessorCallbacks::getParseLocation(const clang::SourceRange& sourceRange) const +{ + if (sourceRange.isInvalid()) + { + return ParseLocation(); + } + + const clang::PresumedLoc& presumedBegin = m_sourceManager.getPresumedLoc(sourceRange.getBegin(), false); + const clang::PresumedLoc& presumedEnd = m_sourceManager.getPresumedLoc(sourceRange.getEnd(), false); + + return ParseLocation( + presumedBegin.getFilename(), + presumedBegin.getLine(), + presumedBegin.getColumn(), + presumedEnd.getLine(), + presumedEnd.getColumn() - 1 + ); +} diff --git a/src/lib/data/parser/cxx/PreprocessorCallbacks.h b/src/lib/data/parser/cxx/PreprocessorCallbacks.h new file mode 100644 index 00000000..e266224d --- /dev/null +++ b/src/lib/data/parser/cxx/PreprocessorCallbacks.h @@ -0,0 +1,31 @@ +#ifndef PREPROCESSOR_CALLBACKS_H +#define PREPROCESSOR_CALLBACKS_H + +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/PPCallbacks.h" + +class FileManager; +class ParserClient; + +struct ParseLocation; + +class PreprocessorCallbacks + : public clang::PPCallbacks +{ +public: + explicit PreprocessorCallbacks(clang::SourceManager& sourceManager, ParserClient* client, FileManager* fileManager); + + virtual void InclusionDirective( + clang::SourceLocation hashLocation, const clang::Token& includeToken, llvm::StringRef fileName, bool isAngled, + clang::CharSourceRange fileNameRange, const clang::FileEntry* fileEntry, llvm::StringRef searchPath, + llvm::StringRef relativePath, const clang::Module* imported); + +private: + ParseLocation getParseLocation(const clang::SourceRange& sourceRange) const; + + const clang::SourceManager& m_sourceManager; + ParserClient* m_client; + FileManager* m_fileManager; +}; + +#endif // PREPROCESSOR_CALLBACKS_H diff --git a/src/lib/data/query/QueryCommand.cpp b/src/lib/data/query/QueryCommand.cpp index 80955810..01f46d64 100644 --- a/src/lib/data/query/QueryCommand.cpp +++ b/src/lib/data/query/QueryCommand.cpp @@ -48,6 +48,8 @@ std::map QueryCommand::getCommandTypeMap commandMap.emplace("derived", COMMAND_SUB_CLASS); commandMap.emplace("subclass", COMMAND_SUB_CLASS); + commandMap.emplace("file", COMMAND_FILE); + return commandMap; } diff --git a/src/lib/data/query/QueryCommand.h b/src/lib/data/query/QueryCommand.h index cc011043..35fbe5e2 100644 --- a/src/lib/data/query/QueryCommand.h +++ b/src/lib/data/query/QueryCommand.h @@ -41,7 +41,9 @@ public: COMMAND_USAGE, COMMAND_SUPER_CLASS, - COMMAND_SUB_CLASS + COMMAND_SUB_CLASS, + + COMMAND_FILE }; static std::map getCommandTypeMap(); diff --git a/src/lib/utility/file/FileManager.cpp b/src/lib/utility/file/FileManager.cpp index 652a580a..32161202 100644 --- a/src/lib/utility/file/FileManager.cpp +++ b/src/lib/utility/file/FileManager.cpp @@ -4,7 +4,6 @@ #include #include "utility/file/FileSystem.h" -#include "ProjectSettings.h" FileManager::FileManager( std::vector sourcePaths, @@ -37,10 +36,9 @@ void FileManager::fetchFilePaths() m_updatedFiles.clear(); m_removedFiles.clear(); - std::set removedFileNames; for (std::map::iterator it = m_files.begin(); it != m_files.end(); it++) { - removedFileNames.insert(it->first); + m_removedFiles.insert(it->first); } std::vector, std::vector>> pathsExtensionsPairs; @@ -49,51 +47,52 @@ void FileManager::fetchFilePaths() for (size_t i = 0; i < pathsExtensionsPairs.size(); i++) { - std::vector fileInfos = FileSystem::getFileInfosFromDirectoryPaths(pathsExtensionsPairs[i].first, pathsExtensionsPairs[i].second); + std::vector fileInfos = + FileSystem::getFileInfosFromDirectoryPaths(pathsExtensionsPairs[i].first, pathsExtensionsPairs[i].second); + for (FileInfo fileInfo: fileInfos) { const std::string& filePath = fileInfo.path; std::map::iterator it = m_files.find(filePath); if (it != m_files.end()) { - removedFileNames.erase(filePath); + m_removedFiles.erase(filePath); if (fileInfo.lastWriteTime > it->second.lastWriteTime) { it->second.lastWriteTime = fileInfo.lastWriteTime; - m_updatedFiles.push_back(filePath); + m_updatedFiles.insert(fileInfo.path); } } else { m_files.insert(std::pair(filePath, fileInfo)); - m_addedFiles.push_back(filePath); + m_addedFiles.insert(filePath); } } } - for (std::set::iterator it = removedFileNames.begin(); it != removedFileNames.end(); it++) + for (const std::string filePath : m_removedFiles) { - m_files.erase(it->data()); - m_removedFiles.push_back(it->data()); + m_files.erase(filePath); } } -std::vector FileManager::getAddedFilePaths() const +std::set FileManager::getAddedFilePaths() const { return m_addedFiles; } -std::vector FileManager::getUpdatedFilePaths() const +std::set FileManager::getUpdatedFilePaths() const { return m_updatedFiles; } -std::vector FileManager::getRemovedFilePaths() const +std::set FileManager::getRemovedFilePaths() const { return m_removedFiles; } bool FileManager::hasFilePath(const std::string& filePath) const { - return (m_files.find(filePath) != m_files.end()); + return (m_files.find(FileSystem::absoluteFilePath(filePath)) != m_files.end()); } diff --git a/src/lib/utility/file/FileManager.h b/src/lib/utility/file/FileManager.h index aa715a10..fd899f54 100644 --- a/src/lib/utility/file/FileManager.h +++ b/src/lib/utility/file/FileManager.h @@ -1,7 +1,7 @@ #ifndef FILE_MANAGER_H #define FILE_MANAGER_H -#include +#include #include #include "FileInfo.h" @@ -19,9 +19,10 @@ public: void reset(); void fetchFilePaths(); - std::vector getAddedFilePaths() const; - std::vector getUpdatedFilePaths() const; - std::vector getRemovedFilePaths() const; + + std::set getAddedFilePaths() const; + std::set getUpdatedFilePaths() const; + std::set getRemovedFilePaths() const; virtual bool hasFilePath(const std::string& filePath) const; @@ -32,9 +33,9 @@ private: std::vector m_includeExtensions; std::map m_files; - std::vector m_addedFiles; - std::vector m_updatedFiles; - std::vector m_removedFiles; + std::set m_addedFiles; + std::set m_updatedFiles; + std::set m_removedFiles; }; #endif // FILE_MANAGER_H diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index 8cdb7f54..565b034b 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -1709,6 +1709,10 @@ public: TS_ASSERT_EQUALS(client.calls.size(), 2); TS_ASSERT_EQUALS(client.usages.size(), 3); TS_ASSERT_EQUALS(client.typeUses.size(), 8); + + TS_ASSERT_EQUALS(client.files.size(), 2); + TS_ASSERT_EQUALS(client.includes.size(), 1); + TS_ASSERT_EQUALS(client.includes[0], client.files[1] + " -> " + client.files[0]); } void test_cxx_parser_catches_error() @@ -1954,6 +1958,19 @@ private: return 0; } + virtual Id onFileParsed(const std::string& filePath) + { + files.push_back(filePath); + return 0; + } + + virtual Id onFileIncludeParsed( + const ParseLocation& location, const std::string& filePath, const std::string& includedPath) + { + includes.push_back(filePath + " -> " + includedPath); + return 0; + } + std::vector errors; std::vector typedefs; @@ -1977,6 +1994,9 @@ private: std::vector templateDefaultArgumentTypes; std::vector templateSpecializations; + std::vector files; + std::vector includes; + private: void addTypeUse(const ParseTypeUsage& use) { diff --git a/src/test/FileManagerTestSuite.h b/src/test/FileManagerTestSuite.h index ca9e93c0..e763f3d4 100644 --- a/src/test/FileManagerTestSuite.h +++ b/src/test/FileManagerTestSuite.h @@ -20,13 +20,9 @@ public: FileManager fm = FileManager(sourcePaths, includePaths, sourceExtensions, includeExtensions); - std::vector addedFilePaths = fm.getAddedFilePaths(); - std::vector updatedFilePaths = fm.getUpdatedFilePaths(); - std::vector removedFilePaths = fm.getRemovedFilePaths(); - - TS_ASSERT_EQUALS(addedFilePaths.size(), 0); - TS_ASSERT_EQUALS(updatedFilePaths.size(), 0); - TS_ASSERT_EQUALS(removedFilePaths.size(), 0); + TS_ASSERT_EQUALS(fm.getAddedFilePaths().size(), 0); + TS_ASSERT_EQUALS(fm.getUpdatedFilePaths().size(), 0); + TS_ASSERT_EQUALS(fm.getRemovedFilePaths().size(), 0); } void test_file_manager_has_added_file_paths_after_first_fetch() @@ -45,11 +41,7 @@ public: FileManager fm = FileManager(sourcePaths, includePaths, sourceExtensions, includeExtensions); fm.fetchFilePaths(); - std::vector addedFilePaths = fm.getAddedFilePaths(); - std::vector updatedFilePaths = fm.getUpdatedFilePaths(); - std::vector removedFilePaths = fm.getRemovedFilePaths(); - - TS_ASSERT_EQUALS(addedFilePaths.size(), 4); + TS_ASSERT_EQUALS(fm.getAddedFilePaths().size(), 4); } void test_file_manager_has_no_added_file_paths_after_second_fetch() @@ -69,11 +61,7 @@ public: fm.fetchFilePaths(); fm.fetchFilePaths(); - std::vector addedFilePaths = fm.getAddedFilePaths(); - std::vector updatedFilePaths = fm.getUpdatedFilePaths(); - std::vector removedFilePaths = fm.getRemovedFilePaths(); - - TS_ASSERT_EQUALS(addedFilePaths.size(), 0); + TS_ASSERT_EQUALS(fm.getAddedFilePaths().size(), 0); } void test_file_manager_has_updated_file_paths_after_second_fetch() @@ -99,12 +87,8 @@ public: fm.fetchFilePaths(); - std::vector addedFilePaths = fm.getAddedFilePaths(); - std::vector updatedFilePaths = fm.getUpdatedFilePaths(); - std::vector removedFilePaths = fm.getRemovedFilePaths(); - - TS_ASSERT_EQUALS(addedFilePaths.size(), 0); - TS_ASSERT_EQUALS(updatedFilePaths.size(), 1); - TS_ASSERT_EQUALS(removedFilePaths.size(), 0); + TS_ASSERT_EQUALS(fm.getAddedFilePaths().size(), 0); + TS_ASSERT_EQUALS(fm.getUpdatedFilePaths().size(), 1); + TS_ASSERT_EQUALS(fm.getRemovedFilePaths().size(), 0); } }; diff --git a/src/test/GraphFilterConductorTestSuite.h b/src/test/GraphFilterConductorTestSuite.h index 108ee899..84d11409 100644 --- a/src/test/GraphFilterConductorTestSuite.h +++ b/src/test/GraphFilterConductorTestSuite.h @@ -11,18 +11,18 @@ public: void test_token_query() { TS_ASSERT_EQUALS( - printedFilteredTestGraph("\"main\""), + printedFilteredTestGraph("\"_main_\""), - "1 nodes: function:main\n" + "1 nodes: function:_main_\n" "0 edges:\n" ); } void test_token_query_with_id() { - std::set ids = getIdsForNodeWithName("main"); + std::set ids = getIdsForNodeWithName("_main_"); std::stringstream ss; - ss << "\"main"; + ss << "\"_main_"; for (Id id : ids) { ss << ',' << id; @@ -30,16 +30,16 @@ public: ss << '"'; TS_ASSERT_EQUALS( - printedFilteredTestGraph(ss.str()), // "main," + printedFilteredTestGraph(ss.str()), // "_main_," - "1 nodes: function:main\n" + "1 nodes: function:_main_\n" "0 edges:\n" ); } void test_token_query_with_id_and_wrong_name_uses_id() { - std::set ids = getIdsForNodeWithName("main"); + std::set ids = getIdsForNodeWithName("_main_"); std::stringstream ss; ss << "\"hello"; for (Id id : ids) @@ -51,7 +51,7 @@ public: TS_ASSERT_EQUALS( printedFilteredTestGraph(ss.str()), // "hello," - "1 nodes: function:main\n" + "1 nodes: function:_main_\n" "0 edges:\n" ); } @@ -97,13 +97,12 @@ public: TS_ASSERT_EQUALS( printedFilteredTestGraph("!'method'"), - "7 nodes: " - "class:A field:A::count undefined_type:int undefined_type:void class:B function:main " - "undefined_function:B::B\n" - "14 edges: " - "child:A->A::count aggregation:A->int aggregation:A->void type_use:A::count->int inheritance:B->A " - "aggregation:B->void aggregation:A->B 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" + "8 nodes: " + "file:/Users/ebsi/Documents/masterproject/bin/test/input.cc class:A field:A::count undefined_type:int " + "undefined_type:void class:B function:_main_ undefined_function:B::B\n" + "14 edges: child:A->A::count aggregation:A->int aggregation:A->void type_use:A::count->int inheritance:B->A " + "aggregation:B->void aggregation:A->B 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" ); } @@ -219,7 +218,7 @@ private: " }\n" "};\n" "\n" - "int main()\n" + "int _main_()\n" "{\n" " B b;\n" "\n" diff --git a/src/test/StorageTestSuite.h b/src/test/StorageTestSuite.h index 601de9b3..b597cc81 100644 --- a/src/test/StorageTestSuite.h +++ b/src/test/StorageTestSuite.h @@ -573,7 +573,9 @@ public: TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 4); TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 3); - storage.clearFileData(std::vector(1, m_filePath)); + std::set files; + files.insert(m_filePath); + storage.clearFileData(files); TS_ASSERT_EQUALS(storage.graph().getNodeCount(), 0); TS_ASSERT_EQUALS(storage.graph().getEdgeCount(), 0); @@ -602,7 +604,9 @@ public: TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 9); TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 6); - storage.clearFileData(std::vector(1, "file.cpp")); + std::set files; + files.insert("file.cpp"); + storage.clearFileData(files); TS_ASSERT_EQUALS(storage.graph().getNodeCount(), 3); TS_ASSERT_EQUALS(storage.graph().getEdgeCount(), 2); @@ -631,7 +635,9 @@ public: TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 9); TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 5); - storage.clearFileData(std::vector(1, "file.h")); + std::set files; + files.insert("file.h"); + storage.clearFileData(files); TS_ASSERT_EQUALS(storage.graph().getNodeCount(), 4); TS_ASSERT_EQUALS(storage.graph().getEdgeCount(), 3); @@ -660,9 +666,9 @@ public: TS_ASSERT_EQUALS(storage.tokenLocationCollection().getTokenLocations().size(), 9); TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 5); - std::vector filePaths; - filePaths.push_back("file.cpp"); - filePaths.push_back("file.h"); + std::set filePaths; + filePaths.insert("file.cpp"); + filePaths.insert("file.h"); storage.clearFileData(filePaths); TS_ASSERT_EQUALS(storage.graph().getNodeCount(), 0); @@ -671,6 +677,65 @@ public: TS_ASSERT_EQUALS(storage.searchIndex().getNodeCount(), 0); } + void test_storage_saves_file_nodes() + { + TestStorage storage; + + Id id = storage.onFileParsed("file.h"); + Node* node = storage.getNodeWithId(id); + + TS_ASSERT(node); + TS_ASSERT_EQUALS(node->getName(), "file.h"); + TS_ASSERT_EQUALS(node->getType(), Node::NODE_FILE); + } + + void test_storage_saves_include_edge() + { + TestStorage storage; + + storage.onFileParsed("file.h"); + storage.onFileParsed("file.cpp"); + Id id = storage.onFileIncludeParsed(validLocation(7), "file.cpp", "file.h"); + + Edge* edge = storage.getEdgeWithId(id); + TS_ASSERT(edge); + TS_ASSERT_EQUALS(edge->getType(), Edge::EDGE_INCLUDE); + + TS_ASSERT_EQUALS(edge->getFrom()->getName(), "file.cpp"); + TS_ASSERT_EQUALS(edge->getTo()->getName(), "file.h"); + + std::vector locations = storage.getLocationsForId(id); + TS_ASSERT_EQUALS(locations.size(), 1); + TS_ASSERT(isValidLocation(locations[0], 7)); + } + + void test_storage_finds_and_removes_depending_file_nodes() + { + TestStorage storage; + + Id id1 = storage.onFileParsed("f.h"); + Id id2 = storage.onFileParsed("file.h"); + Id id3 = storage.onFileParsed("file.cpp"); + Id id4 = storage.onFileIncludeParsed(validLocation(), "file.h", "f.h"); + Id id5 = storage.onFileIncludeParsed(validLocation(), "file.cpp", "file.h"); + + std::string name1 = storage.getNodeWithId(id2)->getFullName(); + std::string name2 = storage.getNodeWithId(id3)->getFullName(); + + std::set filePaths; + filePaths.insert(name1); + std::set dependingFilePaths = storage.getDependingFilePathsAndRemoveFileNodes(filePaths); + + TS_ASSERT_EQUALS(dependingFilePaths.size(), 1); + TS_ASSERT_EQUALS(*dependingFilePaths.begin(), name2); + + TS_ASSERT(storage.getNodeWithId(id1)); + TS_ASSERT(!storage.getNodeWithId(id2)); + TS_ASSERT(!storage.getNodeWithId(id3)); + TS_ASSERT(!storage.getEdgeWithId(id4)); + TS_ASSERT(!storage.getEdgeWithId(id5)); + } + private: class TestStorage : public Storage