diff --git a/src/lib/Application.cpp b/src/lib/Application.cpp index 6a1a8e1d..a763d9cb 100644 --- a/src/lib/Application.cpp +++ b/src/lib/Application.cpp @@ -69,17 +69,17 @@ void Application::loadProject(const FilePath& projectSettingsFilePath) { MessageStatus("Loading Project: " + projectSettingsFilePath.str()).dispatch(); + updateRecentProjects(projectSettingsFilePath); + m_storageCache->clear(); m_componentManager->refreshViews(); m_project = Project::create(m_storageCache.get()); m_project->loadProjectSettings(projectSettingsFilePath); m_project->parseCode(); - - updateRecentProjects(projectSettingsFilePath); } -void Application::reloadProject() +void Application::refreshProject() { MessageStatus("Refreshing Project").dispatch(); @@ -142,10 +142,11 @@ void Application::handleMessage(MessageRefresh* message) if (message->uiOnly) { m_componentManager->refreshViews(); - return; } - - reloadProject(); + else + { + refreshProject(); + } } void Application::handleMessage(MessageSaveProject* message) diff --git a/src/lib/Application.h b/src/lib/Application.h index 568a3e40..4d425be8 100644 --- a/src/lib/Application.h +++ b/src/lib/Application.h @@ -28,7 +28,7 @@ public: ~Application(); void loadProject(const FilePath& projectSettingsFilePath); - void reloadProject(); + void refreshProject(); void saveProject(const FilePath& projectSettingsFilePath); private: diff --git a/src/lib/Project.cpp b/src/lib/Project.cpp index 4b6c9e92..fabe8427 100644 --- a/src/lib/Project.cpp +++ b/src/lib/Project.cpp @@ -29,7 +29,7 @@ bool Project::loadProjectSettings(const FilePath& projectSettingsFile) { m_projectSettingsFilepath = projectSettingsFile; - m_fileManager.reset(); + //m_fileManager.reset(); updateFileManager(); } return success; @@ -59,7 +59,7 @@ void Project::clearProjectSettings() m_projectSettingsFilepath = FilePath(); ProjectSettings::getInstance()->clear(); - m_fileManager.reset(); + //m_fileManager.reset(); } void Project::reloadProjectSettings() @@ -91,11 +91,13 @@ void Project::parseCode() std::set updatedFilePaths = m_fileManager.getUpdatedFilePaths(); std::set removedFilePaths = m_fileManager.getRemovedFilePaths(); - utility::append(updatedFilePaths, m_storage->getDependingFilePathsAndRemoveFileNodes(updatedFilePaths)); - utility::append(updatedFilePaths, m_storage->getDependingFilePathsAndRemoveFileNodes(removedFilePaths)); + utility::append(updatedFilePaths, m_storage->getDependingFilePaths(updatedFilePaths)); + utility::append(removedFilePaths, m_storage->getDependingFilePaths(removedFilePaths)); - m_storage->clearFileData(updatedFilePaths); - m_storage->clearFileData(removedFilePaths); + m_storage->clearFileElements(updatedFilePaths); + m_storage->clearFileElements(removedFilePaths); + + m_storage->removeUnusedNames(); std::vector filesToParse; filesToParse.insert(filesToParse.end(), addedFilePaths.begin(), addedFilePaths.end()); @@ -167,5 +169,6 @@ Parser::Arguments Project::getParserArguments() const Project::Project(StorageAccessProxy* storageAccessProxy) : m_storageAccessProxy(storageAccessProxy) + , m_fileManager(storageAccessProxy) { } diff --git a/src/lib/data/SqliteStorage.cpp b/src/lib/data/SqliteStorage.cpp index b155bc16..5236ea5c 100644 --- a/src/lib/data/SqliteStorage.cpp +++ b/src/lib/data/SqliteStorage.cpp @@ -2,6 +2,7 @@ #include "data/graph/Node.h" #include "data/location/TokenLocation.h" +#include "utility/logging/logging.h" SqliteStorage::SqliteStorage(const std::string& dbFilePath) { @@ -68,13 +69,13 @@ Id SqliteStorage::addNode(int type, Id nameId) return id; } -Id SqliteStorage::addFile(Id nameId, const std::string& filePath) +Id SqliteStorage::addFile(Id nameId, const std::string& filePath, const std::string& modificationTime) { Id id = addNode(Node::NODE_FILE, nameId); m_database.execDML(( - "INSERT INTO file(id, path) VALUES(" - + std::to_string(id) + ", '" + filePath + "');" + "INSERT INTO file(id, path, modification_time) VALUES(" + + std::to_string(id) + ", '" + filePath + "', '" + modificationTime + "');" ).c_str()); return id; @@ -126,6 +127,59 @@ void SqliteStorage::removeNameHierarchyElement(Id id) ).c_str()); } +void SqliteStorage::removeElementsWithLocationInFile(Id fileId) +{ + m_database.execDML(( + "DELETE FROM element WHERE id IN (SELECT element_id FROM source_location WHERE source_location.file_node_id == " + std::to_string(fileId) + ");" + ).c_str()); +} + +void SqliteStorage::removeFile(Id id) +{ + if (isFile(id)) + { + m_database.execDML(( + "DELETE FROM element WHERE id == " + std::to_string(id) + ";" + ).c_str()); + } + else + { + LOG_WARNING("Removing file from DB failed since there is no file element with id " + std::to_string(id)); + } +} + +void SqliteStorage::removeUnusedNameHierarchyElements() +{ + m_database.execDML( + "DELETE FROM name_hierarchy_element WHERE NOT EXISTS (SELECT * FROM node where node.name_id == name_hierarchy_element.id);" + ); +} + +std::vector SqliteStorage::getAllNodes() const +{ + std::vector nodes; + + CppSQLite3Query q = m_database.execQuery( + "SELECT id, type, name_id FROM node;" + ); + + while (!q.eof()) + { + const Id id = q.getIntField(0, 0); + const int type = q.getIntField(1, -1); + const Id nameId = q.getIntField(2, 0); + + if (id != 0 && type != -1 && nameId != 0) + { + nodes.push_back(StorageNode(id, type, nameId)); + } + + q.nextRow(); + } + + return nodes; +} + bool SqliteStorage::isEdge(Id elementId) const { int count = m_database.execScalar(("SELECT count(*) FROM edge WHERE id = " + std::to_string(elementId) + ";").c_str()); @@ -340,7 +394,7 @@ StorageNode SqliteStorage::getNodeByName(const std::string& nodeName) const StorageFile SqliteStorage::getFileById(const Id id) const { return getFirstFile( - "SELECT node.id, node.name_id, file.path FROM node INNER JOIN file ON node.id = file.id " + "SELECT node.id, node.name_id, file.path, file.modification_time FROM node INNER JOIN file ON node.id = file.id " "WHERE node.id == " + std::to_string(id) + ";" ); } @@ -349,12 +403,12 @@ StorageFile SqliteStorage::getFileByName(const std::string& fileName) const { Id nameId = getNameHierarchyElementIdByName(fileName); - StorageFile storageFile(0, 0, ""); + StorageFile storageFile(0, 0, "", ""); if (nameId != 0) { storageFile = getFirstFile( - "SELECT node.id, node.name_id, file.path FROM node INNER JOIN file ON node.id = file.id " + "SELECT node.id, node.name_id, file.path, file.modification_time FROM node INNER JOIN file ON node.id = file.id " "WHERE node.name_id == " + std::to_string(nameId) + ";" ); } @@ -362,6 +416,11 @@ StorageFile SqliteStorage::getFileByName(const std::string& fileName) const return storageFile; } +std::vector SqliteStorage::getAllFiles() const +{ + return getAllFiles("SELECT file.id, node.name_id, file.path, file.modification_time FROM file INNER JOIN node ON file.id = node.id;"); +} + void SqliteStorage::setNodeType(int type, Id nodeId) { m_database.execDML(( @@ -390,6 +449,31 @@ Id SqliteStorage::getNameHierarchyElementIdByNodeId(const Id nodeId) const ); } +std::vector SqliteStorage::getAllNameHierarchyElements() const +{ + std::vector ret; + + CppSQLite3Query q = m_database.execQuery( + "SELECT * FROM name_hierarchy_element;" + ); + + while (!q.eof()) + { + const Id id = q.getIntField(0, 0); + const std::string name = q.getStringField(1, ""); + const Id parent_id = q.getIntField(2, 0); + + + if (id != 0 && name != "" && parent_id != 0) + { + ret.push_back(StorageNameHierarchyElement(id, name, parent_id)); + } + q.nextRow(); + } + + return ret; +} + NameHierarchy SqliteStorage::getNameHierarchyById(const Id id) const { CppSQLite3Query q = m_database.execQuery(( @@ -554,6 +638,7 @@ void SqliteStorage::setupTables() "CREATE TABLE IF NOT EXISTS file(" "id INTEGER NOT NULL, " "path TEXT, " + "modification_time TEXT, " "PRIMARY KEY(id), " "FOREIGN KEY(id) REFERENCES node(id) ON DELETE CASCADE);" ); @@ -589,16 +674,40 @@ StorageFile SqliteStorage::getFirstFile(const std::string& query) const if (!q.eof()) { - const Id id = q.getIntField(0, 0); - const Id nameId = q.getIntField(1, 0); - const std::string filePath = q.getStringField(2, ""); + const Id id = q.getIntField(0, 0); + const Id nameId = q.getIntField(1, 0); + const std::string filePath = q.getStringField(2, ""); + const std::string modificationTime = q.getStringField(3, ""); if (id != 0 && nameId != 0) { - return StorageFile(id, nameId, filePath); + return StorageFile(id, nameId, filePath, modificationTime); } } - return StorageFile(0, 0, ""); + return StorageFile(0, 0, "", ""); +} + +std::vector SqliteStorage::getAllFiles(const std::string& query) const +{ + std::vector files; + + CppSQLite3Query q = m_database.execQuery(query.c_str()); + + while (!q.eof()) + { + const Id id = q.getIntField(0, 0); + const Id nameId = q.getIntField(1, 0); + const std::string filePath = q.getStringField(2, ""); + const std::string modificationTime = q.getStringField(3, ""); + + if (id != 0 && nameId != 0) + { + files.push_back(StorageFile(id, nameId, filePath, modificationTime)); + } + q.nextRow(); + } + + return files; } StorageSourceLocation SqliteStorage::getFirstSourceLocation(const std::string& query) const diff --git a/src/lib/data/SqliteStorage.h b/src/lib/data/SqliteStorage.h index cd85ddc3..f0d3a421 100644 --- a/src/lib/data/SqliteStorage.h +++ b/src/lib/data/SqliteStorage.h @@ -28,13 +28,18 @@ public: Id addEdge(int type, Id sourceNodeId, Id targetNodeId); Id addNode(int type, Id nameId); - Id addFile(Id nameId, const std::string& filePath); + Id addFile(Id nameId, const std::string& filePath, const std::string& modificationTime); int addSourceLocation(Id elementId, Id fileNodeId, uint startLine, uint startCol, uint endLine, uint endCol, bool isScope); Id addNameHierarchyElement(const std::string& name); Id addNameHierarchyElement(const std::string& name, Id parentId); void removeElement(Id id); void removeNameHierarchyElement(Id id); + void removeElementsWithLocationInFile(Id fileId); + void removeFile(Id id); + void removeUnusedNameHierarchyElements(); + + std::vector getAllNodes() const; bool isEdge(Id elementId) const; bool isNode(Id elementId) const; @@ -53,6 +58,7 @@ public: StorageFile getFileById(const Id id) const; StorageFile getFileByName(const std::string& fileName) const; + std::vector getAllFiles() const; void setNodeType(int type, Id nodeId); @@ -61,6 +67,8 @@ public: Id getNameHierarchyElementIdByNodeId(const Id nodeId) const; + std::vector getAllNameHierarchyElements() const; + NameHierarchy getNameHierarchyById(const Id id) const; StorageSourceLocation getSourceLocationById(const Id id) const; @@ -79,6 +87,7 @@ private: void setupTables(); StorageFile getFirstFile(const std::string& query) const; + std::vector getAllFiles(const std::string& query) const; StorageSourceLocation getFirstSourceLocation(const std::string& query) const; std::vector getAllSourceLocations(const std::string& query) const; diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index a0cc16ef..6f9498ad 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -3,9 +3,10 @@ #include #include +#include "utility/file/FileSystem.h" #include "utility/logging/logging.h" -#include "utility/utilityString.h" #include "utility/utility.h" +#include "utility/utilityString.h" #include "data/graph/token_component/TokenComponentAggregation.h" #include "data/graph/token_component/TokenComponentName.h" @@ -38,15 +39,66 @@ void Storage::clear() m_errorLocationCollection.clear(); } -void Storage::clearFileData(const std::set& filePaths) +void Storage::clearFileElements(const std::set& filePaths) { - // TODO: Implement this one + for (const FilePath& filePath: filePaths) + { + clearFileElements(filePath); + } } -std::set Storage::getDependingFilePathsAndRemoveFileNodes(const std::set& filePaths) +void Storage::clearFileElements(const FilePath& filePath) { - // TODO: Implement this one - return std::set(); + Id fileId = m_sqliteStorage.getFileByName(filePath.fileName()).id; + if (fileId != 0) + { + m_sqliteStorage.removeElementsWithLocationInFile(fileId); + m_sqliteStorage.removeFile(fileId); + } +} + +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; + + Id fileNodeId = m_sqliteStorage.getFileByName(filePath.fileName()).id; + std::vector incomingEdges = m_sqliteStorage.getEdgesByTargetType( + fileNodeId, Edge::typeToInt(Edge::EDGE_INCLUDE) + ); + for (StorageEdge incomingEdge: incomingEdges) + { + Id dependingFileId = incomingEdge.sourceNodeId; + FilePath dependingFilePath = FilePath(m_sqliteStorage.getFileById(dependingFileId).filePath); + + dependingFilePaths.insert(dependingFilePath); + + std::set dependingFilePathsSubset = getDependingFilePaths(dependingFilePath); + dependingFilePaths.insert(dependingFilePathsSubset.begin(), dependingFilePathsSubset.end()); + } + + return dependingFilePaths; +} + +void Storage::removeUnusedNames() +{ + m_sqliteStorage.removeUnusedNameHierarchyElements(); + m_tokenIndex.clear(); + + for (StorageNode node: m_sqliteStorage.getAllNodes()) + { + m_tokenIndex.addNode(m_sqliteStorage.getNameHierarchyById(node.nameId))->addTokenId(node.id); + } } void Storage::logGraph() const @@ -399,7 +451,7 @@ Id Storage::onTemplateArgumentTypeParsed( const NameHierarchy& templateNameHierarchy) { Id argumentNodeId = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, argumentNameHierarchy); - // TODO add location for arg + // does not need a source location because this type that is already defined (and therefore has a location). Id templateNodeId = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, templateNameHierarchy); @@ -413,7 +465,7 @@ Id Storage::onTemplateDefaultArgumentTypeParsed( const NameHierarchy& templateArgumentTypeNameHierarchy // actually this is the template parameter??? ){ Id defaultArgumentNodeId = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, defaultArgumentTypeUsage.dataType->getTypeNameHierarchy()); - // TODO add location for defarg + // does not need a source location because this type that is already defined (and therefore has a location). Id argumentNodeId = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, templateArgumentTypeNameHierarchy); @@ -427,7 +479,7 @@ Id Storage::onTemplateRecordParameterTypeParsed( const NameHierarchy& templateRecordNameHierarchy ){ Id parameterNodeId = addNodeHierarchy(Node::NODE_TEMPLATE_PARAMETER_TYPE, templateParameterTypeNameHierarchy); - // TODO add location for param + addSourceLocation(parameterNodeId, location, false); Id recordNodeId = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, templateRecordNameHierarchy); @@ -447,7 +499,7 @@ Id Storage::onTemplateRecordSpecializationParsed( } Id specializedNodeId = addNodeHierarchy(specializedRecordNodeType, specializedRecordNameHierarchy); - // TODO add location for specialized + addSourceLocation(specializedNodeId, location, false); Id recordNodeId = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, specializedFromNameHierarchy); @@ -460,7 +512,7 @@ Id Storage::onTemplateFunctionParameterTypeParsed( const ParseLocation& location, const NameHierarchy& templateParameterTypeNameHierarchy, const ParseFunction function ){ Id parameterNodeId = addNodeHierarchy(Node::NODE_TEMPLATE_PARAMETER_TYPE, templateParameterTypeNameHierarchy); - // TODO add location for parameter + addSourceLocation(parameterNodeId, location, false); Id functionNodeId = addNodeHierarchyWithDistinctSignature(Node::NODE_UNDEFINED_FUNCTION, function); @@ -473,7 +525,7 @@ Id Storage::onTemplateFunctionSpecializationParsed( const ParseLocation& location, const ParseFunction specializedFunction, const ParseFunction templateFunction ){ Id specializedNodeId = addNodeHierarchyWithDistinctSignature(Node::NODE_FUNCTION, specializedFunction); - // TODO add location for specialized + addSourceLocation(specializedNodeId, location, false); Id functionNodeId = addNodeHierarchyWithDistinctSignature(Node::NODE_UNDEFINED_FUNCTION, templateFunction); @@ -482,9 +534,9 @@ Id Storage::onTemplateFunctionSpecializationParsed( return specializedNodeId; } -Id Storage::onFileParsed(const std::string& filePath) +Id Storage::onFileParsed(const FileInfo& fileInfo) { - const std::string fileName = FilePath(filePath).fileName(); + const std::string fileName = fileInfo.path.fileName(); Id nameHierarchyElementId = m_sqliteStorage.getNameHierarchyElementIdByName(fileName); if (nameHierarchyElementId == 0) @@ -495,7 +547,11 @@ Id Storage::onFileParsed(const std::string& filePath) Id fileNodeId = m_sqliteStorage.getFileByName(fileName).id; if (fileNodeId == 0) { - fileNodeId = m_sqliteStorage.addFile(nameHierarchyElementId, filePath); + fileNodeId = m_sqliteStorage.addFile( + nameHierarchyElementId, + fileInfo.path.str(), + utility::timeToString(fileInfo.lastWriteTime) + ); } NameHierarchy nameHierarchy; @@ -505,10 +561,10 @@ Id Storage::onFileParsed(const std::string& filePath) return fileNodeId; } -Id Storage::onFileIncludeParsed(const ParseLocation& location, const std::string& filePath, const std::string& includedPath) +Id Storage::onFileIncludeParsed(const ParseLocation& location, const FileInfo& fileInfo, const FileInfo& includedFileInfo) { - const Id fileNodeId = onFileParsed(filePath); - const Id includedFileNodeId = onFileParsed(includedPath); + const Id fileNodeId = onFileParsed(fileInfo); + const Id includedFileNodeId = onFileParsed(includedFileInfo); addEdge(fileNodeId, includedFileNodeId, Edge::EDGE_INCLUDE, location); @@ -556,6 +612,27 @@ Id Storage::getIdForEdgeWithName(const std::string& name) const return m_sqliteStorage.getEdgeBySourceTargetType(sourceId, targetId, type).id; } +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; +} + std::string Storage::getNameForNodeWithId(Id nodeId) const { Id nameHierarchyElementId = m_sqliteStorage.getNameHierarchyElementIdByNodeId(nodeId); @@ -1035,11 +1112,11 @@ int Storage::addSourceLocation(int elementNodeId, const ParseLocation& location, } else { - Id fileNodeId = m_sqliteStorage.getFileByName(FilePath(location.filePath).fileName()).id; + Id fileNodeId = m_sqliteStorage.getFileByName(location.filePath.fileName()).id; if (fileNodeId == 0) { LOG_ERROR("No filenode created for file: " + location.filePath.str()); - fileNodeId = onFileParsed(location.filePath.str()); // TODO: make onFileParsed accept filePath + fileNodeId = onFileParsed(FileSystem::getFileInfoForPath(location.filePath)); } int locationId = m_sqliteStorage.addSourceLocation( elementNodeId, fileNodeId, location.startLineNumber, location.startColumnNumber, diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index 054f3d97..2cac3787 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -23,8 +23,11 @@ public: virtual ~Storage(); void clear(); - void clearFileData(const std::set& filePaths); - std::set getDependingFilePathsAndRemoveFileNodes(const std::set& filePaths); + void clearFileElements(const std::set& filePaths); + void clearFileElements(const FilePath& filePath); + std::set getDependingFilePaths(const std::set& filePaths); + std::set getDependingFilePaths(const FilePath& filePath); + void removeUnusedNames(); void logGraph() const; void logLocations() const; @@ -105,14 +108,16 @@ public: virtual Id onTemplateFunctionSpecializationParsed( const ParseLocation& location, const ParseFunction specializedFunction, const ParseFunction templateFunction); - virtual Id onFileParsed(const std::string& filePath); + virtual Id onFileParsed(const FileInfo& fileInfo); virtual Id onFileIncludeParsed( - const ParseLocation& location, const std::string& filePath, const std::string& includedPath); + const ParseLocation& location, const FileInfo& fileInfo, const FileInfo& includedFileInfo); // StorageAccess implementation virtual Id getIdForNodeWithName(const std::string& fullName) const; virtual Id getIdForEdgeWithName(const std::string& name) const; + virtual std::vector getInfoOnAllFiles() const; + virtual std::string getNameForNodeWithId(Id nodeId) const; virtual Node::NodeType getNodeTypeForNodeWithId(Id nodeId) const; virtual std::vector getAutocompletionMatches( diff --git a/src/lib/data/StorageTypes.h b/src/lib/data/StorageTypes.h index 7fed5739..5cef9e57 100644 --- a/src/lib/data/StorageTypes.h +++ b/src/lib/data/StorageTypes.h @@ -30,13 +30,14 @@ struct StorageNode struct StorageFile { - StorageFile(Id id, Id nameId, const std::string& filePath) - : id(id), nameId(nameId), filePath(filePath) + StorageFile(Id id, Id nameId, const std::string& filePath, const std::string& modificationTime) + : id(id), nameId(nameId), filePath(filePath), modificationTime(modificationTime) {} Id id; Id nameId; std::string filePath; + std::string modificationTime; }; struct StorageNameHierarchyElement diff --git a/src/lib/data/access/StorageAccess.h b/src/lib/data/access/StorageAccess.h index 33078cf3..63510487 100644 --- a/src/lib/data/access/StorageAccess.h +++ b/src/lib/data/access/StorageAccess.h @@ -11,6 +11,7 @@ #include "data/graph/Node.h" #include "data/search/SearchMatch.h" +struct FileInfo; class Graph; class TokenLocation; class TokenLocationCollection; @@ -24,6 +25,8 @@ public: virtual Id getIdForNodeWithName(const std::string& name) const = 0; virtual Id getIdForEdgeWithName(const std::string& name) const = 0; + virtual std::vector getInfoOnAllFiles() const = 0; + virtual std::string getNameForNodeWithId(Id id) const = 0; virtual Node::NodeType getNodeTypeForNodeWithId(Id id) const = 0; virtual std::vector getAutocompletionMatches( diff --git a/src/lib/data/access/StorageAccessProxy.cpp b/src/lib/data/access/StorageAccessProxy.cpp index 60e2241f..e47ef425 100644 --- a/src/lib/data/access/StorageAccessProxy.cpp +++ b/src/lib/data/access/StorageAccessProxy.cpp @@ -1,11 +1,12 @@ #include "data/access/StorageAccessProxy.h" -#include "utility/logging/logging.h" - #include "data/graph/Graph.h" #include "data/location/TokenLocationCollection.h" #include "data/location/TokenLocationFile.h" +#include "utility/logging/logging.h" +#include "utility/file/FileInfo.h" + StorageAccessProxy::StorageAccessProxy() : m_subject(nullptr) { @@ -51,6 +52,16 @@ Id StorageAccessProxy::getIdForEdgeWithName(const std::string& name) const return 0; } +std::vector StorageAccessProxy::getInfoOnAllFiles() const +{ + std::vector fileInfos; + if (hasSubject()) + { + fileInfos = m_subject->getInfoOnAllFiles(); + } + return fileInfos; +} + Node::NodeType StorageAccessProxy::getNodeTypeForNodeWithId(Id id) const { if(hasSubject()) diff --git a/src/lib/data/access/StorageAccessProxy.h b/src/lib/data/access/StorageAccessProxy.h index 231182c8..8090d9e4 100644 --- a/src/lib/data/access/StorageAccessProxy.h +++ b/src/lib/data/access/StorageAccessProxy.h @@ -16,6 +16,8 @@ public: virtual Id getIdForNodeWithName(const std::string& name) const; virtual Id getIdForEdgeWithName(const std::string& name) const; + virtual std::vector getInfoOnAllFiles() const; + virtual std::string getNameForNodeWithId(Id id) const; virtual Node::NodeType getNodeTypeForNodeWithId(Id id) const; virtual std::vector getAutocompletionMatches( diff --git a/src/lib/data/parser/ParserClient.h b/src/lib/data/parser/ParserClient.h index 4160935d..43102983 100644 --- a/src/lib/data/parser/ParserClient.h +++ b/src/lib/data/parser/ParserClient.h @@ -6,6 +6,7 @@ #include "utility/types.h" #include "data/name/NameHierarchy.h" +#include "utility/file/FileInfo.h" struct ParseFunction; struct ParseLocation; @@ -125,9 +126,9 @@ public: virtual Id onTemplateFunctionSpecializationParsed( const ParseLocation& location, const ParseFunction specializedFunction, const ParseFunction templateFunction) = 0; - virtual Id onFileParsed(const std::string& filePath) = 0; + virtual Id onFileParsed(const FileInfo& fileInfo) = 0; virtual Id onFileIncludeParsed( - const ParseLocation& location, const std::string& filePath, const std::string& includedPath) = 0; + const ParseLocation& location, const FileInfo& fileInfo, const FileInfo& includedFileInfo) = 0; }; #endif // PARSER_CLIENT_H diff --git a/src/lib/data/parser/cxx/ASTVisitor.cpp b/src/lib/data/parser/cxx/ASTVisitor.cpp index cd0d1765..ee6208a8 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.cpp +++ b/src/lib/data/parser/cxx/ASTVisitor.cpp @@ -345,16 +345,27 @@ bool ASTVisitor::VisitClassTemplateDecl(clang::ClassTemplateDecl* declaration) { clang::ClassTemplateSpecializationDecl* specializationDecl = *it; + ParseLocation specializationLocation = getParseLocationForNamedDecl(*it); + if (specializationDecl->getSpecializationKind() == clang::TSK_ImplicitInstantiation) + { + specializationLocation = getParseLocation(specializationDecl->getPointOfInstantiation()); + } + + NameHierarchy specializedRecordNameHierarchy = utility::getDeclNameHierarchy(specializationDecl); + + ParserClient::RecordType specializedRecordType = specializationDecl->isStruct() ? ParserClient::RECORD_STRUCT : ParserClient::RECORD_CLASS; + // The specializationParent can be an indirect specialization of the ClassTemplate (by specializing a partial specialization). NameHierarchy specializationParentNameHierarchy = utility::getTemplateSpecializationParentNameHierarchy(specializationDecl); - ParserClient::RecordType specializedRecordType = specializationDecl->isStruct() ? ParserClient::RECORD_STRUCT : ParserClient::RECORD_CLASS; - NameHierarchy specializedRecordNameHierarchy = utility::getDeclNameHierarchy(specializationDecl); m_client->onTemplateRecordSpecializationParsed( - getParseLocationForNamedDecl(*it), specializedRecordNameHierarchy, specializedRecordType, specializationParentNameHierarchy + specializationLocation, + specializedRecordNameHierarchy, + specializedRecordType, + specializationParentNameHierarchy ); - std::string specializationFilePath = getParseLocationForNamedDecl(specializationDecl).filePath.str(); + std::string specializationFilePath = specializationLocation.filePath.str(); const clang::TemplateArgumentList &argList = specializationDecl->getTemplateArgs(); for (size_t i = 0; i < argList.size(); i++) diff --git a/src/lib/data/parser/cxx/PreprocessorCallbacks.cpp b/src/lib/data/parser/cxx/PreprocessorCallbacks.cpp index e8074303..ae185249 100644 --- a/src/lib/data/parser/cxx/PreprocessorCallbacks.cpp +++ b/src/lib/data/parser/cxx/PreprocessorCallbacks.cpp @@ -26,7 +26,10 @@ void PreprocessorCallbacks::FileChanged( const clang::FileEntry *fileEntry = m_sourceManager.getFileEntryForID(m_sourceManager.getFileID(location)); if (fileEntry && m_fileRegister->getFileManager()->hasFilePath(fileEntry->getName())) { - m_client->onFileParsed(fileEntry->getName()); + m_client->onFileParsed(FileInfo( + FilePath(fileEntry->getName()), + boost::posix_time::from_time_t(fileEntry->getModificationTime()) + )); m_fileRegister->markIncludeFileParsing(fileEntry->getName()); } } @@ -40,12 +43,15 @@ void PreprocessorCallbacks::InclusionDirective( if (fileEntry && baseFileEntry) { std::string baseFilePath = baseFileEntry->getName(); - std::string filePath = fileEntry->getName(); + std::string includedFilePath = fileEntry->getName(); - if (m_fileRegister->getFileManager()->hasFilePath(baseFilePath) && - m_fileRegister->getFileManager()->hasFilePath(filePath)) + if (m_fileRegister->getFileManager()->hasFilePath(baseFilePath) && // check if file is in project + m_fileRegister->getFileManager()->hasFilePath(includedFilePath)) { - m_client->onFileIncludeParsed(getParseLocation(fileNameRange.getAsRange()), baseFilePath, filePath); + FileInfo baseFileInfo(baseFilePath, boost::posix_time::from_time_t(baseFileEntry->getModificationTime())); + FileInfo includedFileInfo(includedFilePath, boost::posix_time::from_time_t(fileEntry->getModificationTime())); + + m_client->onFileIncludeParsed(getParseLocation(fileNameRange.getAsRange()), baseFileInfo, includedFileInfo); } } } diff --git a/src/lib/utility/file/FileInfo.cpp b/src/lib/utility/file/FileInfo.cpp index a16ce432..e476940d 100644 --- a/src/lib/utility/file/FileInfo.cpp +++ b/src/lib/utility/file/FileInfo.cpp @@ -1,5 +1,11 @@ #include "FileInfo.h" +FileInfo::FileInfo() + : path(FilePath("")) + , lastWriteTime(boost::posix_time::not_a_date_time) +{ +} + FileInfo::FileInfo(const FilePath& path, boost::posix_time::ptime lastWriteTime) : path(path) , lastWriteTime(lastWriteTime) diff --git a/src/lib/utility/file/FileInfo.h b/src/lib/utility/file/FileInfo.h index 7ac31ac9..fa83402e 100644 --- a/src/lib/utility/file/FileInfo.h +++ b/src/lib/utility/file/FileInfo.h @@ -9,6 +9,7 @@ struct FileInfo { + FileInfo(); FileInfo(const FilePath& path, boost::posix_time::ptime lastWriteTime); FilePath path; diff --git a/src/lib/utility/file/FileManager.cpp b/src/lib/utility/file/FileManager.cpp index 318f69e8..d005de34 100644 --- a/src/lib/utility/file/FileManager.cpp +++ b/src/lib/utility/file/FileManager.cpp @@ -4,8 +4,10 @@ #include #include "utility/file/FileSystem.h" +#include "utility/utility.h" -FileManager::FileManager() +FileManager::FileManager(StorageAccessProxy* storageAccessProxy) + : m_storageAccessProxy(storageAccessProxy) { } @@ -35,58 +37,42 @@ void FileManager::setPaths( m_includeExtensions = includeExtensions; } -void FileManager::reset() -{ - m_files.clear(); - m_addedFiles.clear(); - m_updatedFiles.clear(); - m_removedFiles.clear(); -} - void FileManager::fetchFilePaths() { + std::map files; + for (FileInfo oldFileInfo: m_storageAccessProxy->getInfoOnAllFiles()) + { + files[oldFileInfo.path] = oldFileInfo; + } + m_addedFiles.clear(); m_updatedFiles.clear(); m_removedFiles.clear(); - for (std::map::iterator it = m_files.begin(); it != m_files.end(); it++) + for (std::map::iterator it = files.begin(); it != files.end(); it++) { m_removedFiles.insert(it->first); } - std::vector, std::vector>> pathsExtensionsPairs; - pathsExtensionsPairs.push_back(std::make_pair(m_includePaths, m_includeExtensions)); - pathsExtensionsPairs.push_back(std::make_pair(m_sourcePaths, m_sourceExtensions)); - - for (size_t i = 0; i < pathsExtensionsPairs.size(); i++) + std::vector fileInfos = getFileInfosInProject(); + for (FileInfo fileInfo: fileInfos) { - std::vector fileInfos = - FileSystem::getFileInfosFromPaths(pathsExtensionsPairs[i].first, pathsExtensionsPairs[i].second); - - for (FileInfo fileInfo: fileInfos) + const FilePath& filePath = fileInfo.path; + std::map::iterator it = files.find(filePath); + if (it != files.end()) { - const FilePath& filePath = fileInfo.path; - std::map::iterator it = m_files.find(filePath); - if (it != m_files.end()) + m_removedFiles.erase(filePath); + if (fileInfo.lastWriteTime > it->second.lastWriteTime) { - m_removedFiles.erase(filePath); - if (fileInfo.lastWriteTime > it->second.lastWriteTime) - { - it->second.lastWriteTime = fileInfo.lastWriteTime; - m_updatedFiles.insert(fileInfo.path); - } - } - else - { - m_files.insert(std::pair(filePath, fileInfo)); - m_addedFiles.insert(filePath); + it->second.lastWriteTime = fileInfo.lastWriteTime; + m_updatedFiles.insert(fileInfo.path); } } - } - - for (const FilePath& filePath : m_removedFiles) - { - m_files.erase(filePath); + else + { + files.insert(std::pair(filePath, fileInfo)); + m_addedFiles.insert(filePath); + } } } @@ -107,7 +93,16 @@ std::set FileManager::getRemovedFilePaths() const bool FileManager::hasFilePath(const FilePath& filePath) const { - return (m_files.find(filePath) != m_files.end()); + std::vector fileInfos = getFileInfosInProject(); + for (size_t i = 0; i < fileInfos.size(); i++) + { + if (fileInfos[i].path == filePath) + { + return true; + } + } + + return false; } bool FileManager::hasSourceExtension(const FilePath& filePath) const @@ -119,3 +114,22 @@ bool FileManager::hasIncludeExtension(const FilePath& filePath) const { return filePath.hasExtension(m_includeExtensions); } + +std::vector FileManager::getFileInfosInProject() const +{ + std::vector fileInfos; + + std::vector, std::vector>> pathsExtensionsPairs; + pathsExtensionsPairs.push_back(std::make_pair(m_includePaths, m_includeExtensions)); + pathsExtensionsPairs.push_back(std::make_pair(m_sourcePaths, m_sourceExtensions)); + + for (size_t i = 0; i < pathsExtensionsPairs.size(); i++) + { + utility::append( + fileInfos, + FileSystem::getFileInfosFromPaths(pathsExtensionsPairs[i].first, pathsExtensionsPairs[i].second) + ); + } + + return fileInfos; +} diff --git a/src/lib/utility/file/FileManager.h b/src/lib/utility/file/FileManager.h index f96002a9..81bb62f5 100644 --- a/src/lib/utility/file/FileManager.h +++ b/src/lib/utility/file/FileManager.h @@ -5,12 +5,13 @@ #include #include -#include "FileInfo.h" +#include "data/access/StorageAccessProxy.h" +#include "utility/file/FileInfo.h" class FileManager { public: - FileManager(); + FileManager(StorageAccessProxy* storageAccessProxy); virtual ~FileManager(); const std::vector& getSourcePaths() const; @@ -23,7 +24,6 @@ public: std::vector includeExtensions ); - void reset(); void fetchFilePaths(); std::set getAddedFilePaths() const; @@ -35,15 +35,18 @@ public: virtual bool hasIncludeExtension(const FilePath& filePath) const; private: + std::vector getFileInfosInProject() const; + std::vector m_sourcePaths; std::vector m_includePaths; std::vector m_sourceExtensions; std::vector m_includeExtensions; - std::map m_files; std::set m_addedFiles; std::set m_updatedFiles; std::set m_removedFiles; + + StorageAccessProxy* m_storageAccessProxy; }; #endif // FILE_MANAGER_H diff --git a/src/lib/utility/file/FileSystem.cpp b/src/lib/utility/file/FileSystem.cpp index a2ab34f0..90dd3167 100644 --- a/src/lib/utility/file/FileSystem.cpp +++ b/src/lib/utility/file/FileSystem.cpp @@ -52,7 +52,16 @@ std::vector FileSystem::getFileNamesFromDirectoryUpdatedAfter( return files; } - +FileInfo FileSystem::getFileInfoForPath(FilePath filePath) +{ + if (filePath.exists()) + { + std::time_t t = boost::filesystem::last_write_time(filePath.path()); + boost::posix_time::ptime lastWriteTime = boost::posix_time::from_time_t(t); + return FileInfo(filePath, lastWriteTime); + } + return FileInfo(); +} std::vector FileSystem::getFileInfosFromPaths( const std::vector& paths, const std::vector& fileExtensions @@ -85,7 +94,7 @@ std::vector FileSystem::getFileInfosFromPaths( return files; } -std::string FileSystem::getTimeStringNow() +std::string FileSystem::getTimeStringNow() // TODO: move to utility { return boost::posix_time::to_iso_string(boost::posix_time::second_clock::universal_time()); } diff --git a/src/lib/utility/file/FileSystem.h b/src/lib/utility/file/FileSystem.h index 638ade56..bc0e828d 100644 --- a/src/lib/utility/file/FileSystem.h +++ b/src/lib/utility/file/FileSystem.h @@ -14,6 +14,8 @@ public: static std::vector getFileNamesFromDirectoryUpdatedAfter( const std::string& path, const std::vector& extensions, const std::string& timeString); + static FileInfo getFileInfoForPath(FilePath filePath); + static std::vector getFileInfosFromPaths( const std::vector& paths, const std::vector& fileExtensions); diff --git a/src/lib/utility/utility.cpp b/src/lib/utility/utility.cpp index 061f5726..75a1331c 100644 --- a/src/lib/utility/utility.cpp +++ b/src/lib/utility/utility.cpp @@ -21,6 +21,23 @@ float utility::duration(std::function func) return duration(start); } +std::string utility::timeToString(const time_t time) +{ + char buff[20]; + strftime(buff, 20, "%Y-%m-%d %H:%M:%S", localtime(&time)); + return std::string(buff); +} + +std::string utility::timeToString(const boost::posix_time::ptime time) +{ + std::stringstream stream; + boost::posix_time::time_facet* facet = new boost::posix_time::time_facet(); + facet->format("%Y-%m-%d %H:%M:%S"); + stream.imbue(std::locale(std::locale::classic(), facet)); + stream << time; + return stream.str(); +} + bool utility::intersectionPoint(Vec2f a1, Vec2f b1, Vec2f a2, Vec2f b2, Vec2f* i) { Vec2f p = a1; diff --git a/src/lib/utility/utility.h b/src/lib/utility/utility.h index 76db2e49..a5b9fa28 100644 --- a/src/lib/utility/utility.h +++ b/src/lib/utility/utility.h @@ -4,6 +4,9 @@ #include #include #include +#include + +#include "boost/date_time/posix_time/posix_time.hpp" #include "utility/math/Vector2.h" @@ -15,6 +18,9 @@ namespace utility float duration(const TimePoint& start); float duration(std::function func); + std::string timeToString(const time_t time); + std::string timeToString(const boost::posix_time::ptime time); + template std::vector concat(const std::vector& a, const std::vector& b);