From 89b9dfed84f9235d70be2fe39934e3577abf388d Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Tue, 30 Jan 2018 18:41:45 +0100 Subject: [PATCH] Clang: Add source dependency saving to the symbol storage The source dependencies are simply a table which connects the include file with the included file. Change-Id: I5454e81a2b5b98f05c7ff3f6740a6d45e01772c3 Reviewed-by: Ivan Donchevskii --- .../source/clangrefactoringbackend-source.pri | 3 +- .../source/sourcedependency.h | 56 +++++++++++++++++++ .../source/storagesqlitestatementfactory.h | 31 ++++++++++ .../source/symbolstorage.h | 12 ++++ .../source/symbolstorageinterface.h | 2 + tests/unit/unittest/filepathstorage-test.cpp | 2 +- .../unit/unittest/mocksqlitewritestatement.h | 3 + tests/unit/unittest/mocksymbolstorage.h | 2 + .../storagesqlitestatementfactory-test.cpp | 39 ++++++++++++- tests/unit/unittest/symbolstorage-test.cpp | 17 ++++++ 10 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 src/tools/clangrefactoringbackend/source/sourcedependency.h diff --git a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri index 6c9cce056fe..f8ae8d34ff4 100644 --- a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri +++ b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri @@ -16,7 +16,8 @@ HEADERS += \ $$PWD/projectpartentry.h \ $$PWD/symbolsvisitorbase.h \ $$PWD/usedmacro.h \ - $$PWD/fileinformation.h + $$PWD/fileinformation.h \ + $$PWD/sourcedependency.h !isEmpty(LIBTOOLING_LIBS) { SOURCES += \ diff --git a/src/tools/clangrefactoringbackend/source/sourcedependency.h b/src/tools/clangrefactoringbackend/source/sourcedependency.h new file mode 100644 index 00000000000..af6db6a20ca --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/sourcedependency.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +#include + +namespace ClangBackEnd { + +class SourceDependency +{ +public: + SourceDependency(FilePathId filePathId, + FilePathId dependencyFilePathId) + : filePathId(filePathId), + dependencyFilePathId(dependencyFilePathId) + {} + + friend + bool operator==(SourceDependency first, SourceDependency second) + { + return first.filePathId == second.filePathId + && first.dependencyFilePathId == second.dependencyFilePathId; + } + +public: + FilePathId filePathId; + FilePathId dependencyFilePathId; +}; + +using SourceDependencies = std::vector; +} diff --git a/src/tools/clangrefactoringbackend/source/storagesqlitestatementfactory.h b/src/tools/clangrefactoringbackend/source/storagesqlitestatementfactory.h index e953f5e9629..5976b32df9a 100644 --- a/src/tools/clangrefactoringbackend/source/storagesqlitestatementfactory.h +++ b/src/tools/clangrefactoringbackend/source/storagesqlitestatementfactory.h @@ -95,12 +95,27 @@ public: return table; } + Sqlite::Table createNewSourceDependenciesTable() const + { + Sqlite::Table table; + table.setName("newSourceDependencies"); + table.setUseTemporaryTable(true); + const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer); + const Sqlite::Column &dependencySourceIdColumn = table.addColumn("dependencySourceId", Sqlite::ColumnType::Text); + table.addIndex({sourceIdColumn, dependencySourceIdColumn}); + + table.initialize(database); + + return table; + } + public: Sqlite::ImmediateTransaction transaction; Database &database; Sqlite::Table newSymbolsTablet{createNewSymbolsTable()}; Sqlite::Table newLocationsTable{createNewLocationsTable()}; Sqlite::Table newUsedMacroTable{createNewUsedMacrosTable()}; + Sqlite::Table newNewSourceDependenciesTable{createNewSourceDependenciesTable()}; WriteStatement insertSymbolsToNewSymbolsStatement{ "INSERT INTO newSymbols(temporarySymbolId, usr, symbolName) VALUES(?,?,?)", database}; @@ -186,6 +201,22 @@ public: "INSERT OR REPLACE INTO fileInformations(sourceId, size, lastModified) VALUES (?,?,?)", database }; + WriteStatement insertIntoNewSourceDependenciesStatement{ + "INSERT INTO newSourceDependencies(sourceId, dependencySourceId) VALUES (?,?)", + database + }; + WriteStatement syncNewSourceDependenciesStatement{ + "INSERT INTO sourceDependencies(sourceId, dependencySourceId) SELECT sourceId, dependencySourceId FROM newSourceDependencies WHERE NOT EXISTS (SELECT sourceId FROM sourceDependencies WHERE sourceDependencies.sourceId == newSourceDependencies.sourceId AND sourceDependencies.dependencySourceId == newSourceDependencies.dependencySourceId)", + database + }; + WriteStatement deleteOutdatedSourceDependenciesStatement{ + "DELETE FROM sourceDependencies WHERE sourceId IN (SELECT sourceId FROM newSourceDependencies) AND NOT EXISTS (SELECT sourceId FROM newSourceDependencies WHERE newSourceDependencies.sourceId == sourceDependencies.sourceId AND newSourceDependencies.dependencySourceId == sourceDependencies.dependencySourceId)", + database + }; + WriteStatement deleteNewSourceDependenciesStatement{ + "DELETE FROM newSourceDependencies", + database + }; }; } // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolstorage.h b/src/tools/clangrefactoringbackend/source/symbolstorage.h index fa22cc2eb2d..7e4775bfd5c 100644 --- a/src/tools/clangrefactoringbackend/source/symbolstorage.h +++ b/src/tools/clangrefactoringbackend/source/symbolstorage.h @@ -94,6 +94,18 @@ public: m_statementFactory.deleteNewUsedMacrosTableStatement.execute(); } + void insertOrUpdateSourceDependencies(const SourceDependencies &sourceDependencies) override + { + WriteStatement &insertStatement = m_statementFactory.insertIntoNewSourceDependenciesStatement; + for (SourceDependency sourceDependency : sourceDependencies) + insertStatement.write(sourceDependency.filePathId.filePathId, + sourceDependency.dependencyFilePathId.filePathId); + + m_statementFactory.syncNewSourceDependenciesStatement.execute(); + m_statementFactory.deleteOutdatedSourceDependenciesStatement.execute(); + m_statementFactory.deleteNewSourceDependenciesStatement.execute(); + } + void updateProjectPartSources(Utils::SmallStringView projectPartName, const FilePathIds &sourceFilePathIds) override { diff --git a/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h index 7cc1a89200c..dc7c657aaec 100644 --- a/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h +++ b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h @@ -28,6 +28,7 @@ #include "fileinformation.h" #include "projectpartentry.h" #include "sourcelocationentry.h" +#include "sourcedependency.h" #include "symbolentry.h" #include "usedmacro.h" @@ -52,6 +53,7 @@ public: const FilePathIds &sourceFilePathIds) = 0; virtual void insertOrUpdateUsedMacros(const UsedMacros &usedMacros) = 0; virtual void insertFileInformations(const FileInformations &fileInformations) = 0; + virtual void insertOrUpdateSourceDependencies(const SourceDependencies &sourceDependencies) = 0; }; } // namespace ClangBackEnd diff --git a/tests/unit/unittest/filepathstorage-test.cpp b/tests/unit/unittest/filepathstorage-test.cpp index b6373c3c6fc..c9249a89b73 100644 --- a/tests/unit/unittest/filepathstorage-test.cpp +++ b/tests/unit/unittest/filepathstorage-test.cpp @@ -393,7 +393,7 @@ void FilePathStorage::SetUp() .Times(AnyNumber()); EXPECT_CALL(insertIntoDirectories, write(An())) .Times(AnyNumber()); - EXPECT_CALL(insertIntoSources, write(An(), _)) + EXPECT_CALL(insertIntoSources, write(An(), A())) .Times(AnyNumber()); EXPECT_CALL(selectAllDirectories, valuesReturnStdVectorDirectory(_)) .Times(AnyNumber()); diff --git a/tests/unit/unittest/mocksqlitewritestatement.h b/tests/unit/unittest/mocksqlitewritestatement.h index 736a18ba7ef..ebecaeec521 100644 --- a/tests/unit/unittest/mocksqlitewritestatement.h +++ b/tests/unit/unittest/mocksqlitewritestatement.h @@ -76,5 +76,8 @@ public: MOCK_METHOD3(write, void (uint, uint, uint)); + MOCK_METHOD2(write, + void (uint, uint)); + Utils::SmallString sqlStatement; }; diff --git a/tests/unit/unittest/mocksymbolstorage.h b/tests/unit/unittest/mocksymbolstorage.h index dc6ef3377f9..f2bfd954a0a 100644 --- a/tests/unit/unittest/mocksymbolstorage.h +++ b/tests/unit/unittest/mocksymbolstorage.h @@ -48,4 +48,6 @@ public: void (const ClangBackEnd::UsedMacros &usedMacros)); MOCK_METHOD1(insertFileInformations, void (const ClangBackEnd::FileInformations &fileInformations)); + MOCK_METHOD1(insertOrUpdateSourceDependencies, + void (const ClangBackEnd::SourceDependencies &sourceDependencies)); }; diff --git a/tests/unit/unittest/storagesqlitestatementfactory-test.cpp b/tests/unit/unittest/storagesqlitestatementfactory-test.cpp index b798db3a230..b9a80f5b5fa 100644 --- a/tests/unit/unittest/storagesqlitestatementfactory-test.cpp +++ b/tests/unit/unittest/storagesqlitestatementfactory-test.cpp @@ -77,6 +77,16 @@ TEST_F(StorageSqliteStatementFactory, AddNewUsedMacroTable) factory.createNewUsedMacrosTable(); } +TEST_F(StorageSqliteStatementFactory, AddNewSourceDependenciesTable) +{ + InSequence s; + + EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE newSourceDependencies(sourceId INTEGER, dependencySourceId TEXT)"))); + EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_newSourceDependencies_sourceId_dependencySourceId ON newSourceDependencies(sourceId, dependencySourceId)"))); + + factory.createNewSourceDependenciesTable(); +} + TEST_F(StorageSqliteStatementFactory, AddTablesInConstructor) { InSequence s; @@ -89,6 +99,8 @@ TEST_F(StorageSqliteStatementFactory, AddTablesInConstructor) EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_newLocations_sourceId ON newLocations(sourceId)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE newUsedMacros(sourceId INTEGER, macroName TEXT)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_newUsedMacros_sourceId_macroName ON newUsedMacros(sourceId, macroName)"))); + EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE newSourceDependencies(sourceId INTEGER, dependencySourceId TEXT)"))); + EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_newSourceDependencies_sourceId_dependencySourceId ON newSourceDependencies(sourceId, dependencySourceId)"))); EXPECT_CALL(mockDatabase, commit()); StatementFactory factory{mockDatabase}; @@ -202,7 +214,7 @@ TEST_F(StorageSqliteStatementFactory, SyncNewUsedMacros) Eq("INSERT INTO usedMacros(sourceId, macroName) SELECT sourceId, macroName FROM newUsedMacros WHERE NOT EXISTS (SELECT sourceId FROM usedMacros WHERE usedMacros.sourceId == newUsedMacros.sourceId AND usedMacros.macroName == newUsedMacros.macroName)")); } -TEST_F(StorageSqliteStatementFactory, DeleteUnusedMacros) +TEST_F(StorageSqliteStatementFactory, DeleteOutdatedUnusedMacros) { ASSERT_THAT(factory.deleteOutdatedUsedMacrosStatement.sqlStatement, Eq("DELETE FROM usedMacros WHERE sourceId IN (SELECT sourceId FROM newUsedMacros) AND NOT EXISTS (SELECT sourceId FROM newUsedMacros WHERE newUsedMacros.sourceId == usedMacros.sourceId AND newUsedMacros.macroName == usedMacros.macroName)")); @@ -219,4 +231,29 @@ TEST_F(StorageSqliteStatementFactory, InsertFileInformations) ASSERT_THAT(factory.insertFileInformations.sqlStatement, Eq("INSERT OR REPLACE INTO fileInformations(sourceId, size, lastModified) VALUES (?,?,?)")); } + +TEST_F(StorageSqliteStatementFactory, InsertIntoNewSourceDependencies) +{ + ASSERT_THAT(factory.insertIntoNewSourceDependenciesStatement.sqlStatement, + Eq("INSERT INTO newSourceDependencies(sourceId, dependencySourceId) VALUES (?,?)")); +} + +TEST_F(StorageSqliteStatementFactory, SyncNewSourceDependencies) +{ + ASSERT_THAT(factory.syncNewSourceDependenciesStatement.sqlStatement, + Eq("INSERT INTO sourceDependencies(sourceId, dependencySourceId) SELECT sourceId, dependencySourceId FROM newSourceDependencies WHERE NOT EXISTS (SELECT sourceId FROM sourceDependencies WHERE sourceDependencies.sourceId == newSourceDependencies.sourceId AND sourceDependencies.dependencySourceId == newSourceDependencies.dependencySourceId)")); +} + +TEST_F(StorageSqliteStatementFactory, DeleteOutdatedSourceDependencies) +{ + ASSERT_THAT(factory.deleteOutdatedSourceDependenciesStatement.sqlStatement, + Eq("DELETE FROM sourceDependencies WHERE sourceId IN (SELECT sourceId FROM newSourceDependencies) AND NOT EXISTS (SELECT sourceId FROM newSourceDependencies WHERE newSourceDependencies.sourceId == sourceDependencies.sourceId AND newSourceDependencies.dependencySourceId == sourceDependencies.dependencySourceId)")); +} + +TEST_F(StorageSqliteStatementFactory, DeleteAllInNewSourceDependencies) +{ + ASSERT_THAT(factory.deleteNewSourceDependenciesStatement.sqlStatement, + Eq("DELETE FROM newSourceDependencies")); +} + } diff --git a/tests/unit/unittest/symbolstorage-test.cpp b/tests/unit/unittest/symbolstorage-test.cpp index 15ec994a054..be52f57389c 100644 --- a/tests/unit/unittest/symbolstorage-test.cpp +++ b/tests/unit/unittest/symbolstorage-test.cpp @@ -79,6 +79,10 @@ protected: MockSqliteWriteStatement &deleteOutdatedUsedMacrosStatement = statementFactory.deleteOutdatedUsedMacrosStatement; MockSqliteWriteStatement &deleteNewUsedMacrosTableStatement = statementFactory.deleteNewUsedMacrosTableStatement; MockSqliteWriteStatement &insertFileInformations = statementFactory.insertFileInformations; + MockSqliteWriteStatement &insertIntoNewSourceDependenciesStatement = statementFactory.insertIntoNewSourceDependenciesStatement; + MockSqliteWriteStatement &syncNewSourceDependenciesStatement = statementFactory.syncNewSourceDependenciesStatement; + MockSqliteWriteStatement &deleteOutdatedSourceDependenciesStatement = statementFactory.deleteOutdatedSourceDependenciesStatement; + MockSqliteWriteStatement &deleteNewSourceDependenciesStatement = statementFactory.deleteNewSourceDependenciesStatement; SymbolEntries symbolEntries{{1, {"functionUSR", "function"}}, {2, {"function2USR", "function2"}}}; SourceLocationEntries sourceLocations{{1, {1, 3}, {42, 23}, SymbolType::Declaration}, @@ -239,5 +243,18 @@ TEST_F(SymbolStorage, InsertFileInformations) storage.insertFileInformations({{{1, 42}, 1, 2}, {{1, 43}, 4, 5}}); } +TEST_F(SymbolStorage, InsertOrUpdateSourceDependencies) +{ + InSequence sequence; + + EXPECT_CALL(insertIntoNewSourceDependenciesStatement, write(TypedEq(42), TypedEq(1))); + EXPECT_CALL(insertIntoNewSourceDependenciesStatement, write(TypedEq(42), TypedEq(2))); + EXPECT_CALL(syncNewSourceDependenciesStatement, execute()); + EXPECT_CALL(deleteOutdatedSourceDependenciesStatement, execute()); + EXPECT_CALL(deleteNewSourceDependenciesStatement, execute()); + + storage.insertOrUpdateSourceDependencies({{{1, 42}, {1, 1}}, {{1, 42}, {1, 2}}}); +} + }