From 613db15cea6bdee29adb21dbabd36f03391f4a4f Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Mon, 6 Aug 2018 17:31:12 +0200 Subject: [PATCH] ClangRefactoring: Add project part queue Change-Id: Id137233a042181553ff7bb766c9dafa6eb9cf046 Reviewed-by: Ivan Donchevskii --- .../source/clangrefactoringbackend-source.pri | 6 +- .../source/projectpartqueue.cpp | 147 ++++++++++++++++++ .../source/projectpartqueue.h | 46 ++++++ tests/unit/unittest/projectpartqueue-test.cpp | 104 +++++++++++++ tests/unit/unittest/unittest.pro | 3 +- 5 files changed, 303 insertions(+), 3 deletions(-) create mode 100644 src/tools/clangrefactoringbackend/source/projectpartqueue.cpp create mode 100644 src/tools/clangrefactoringbackend/source/projectpartqueue.h create mode 100644 tests/unit/unittest/projectpartqueue-test.cpp diff --git a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri index 2a78fc0e113..c0d8efe87ac 100644 --- a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri +++ b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri @@ -21,7 +21,8 @@ HEADERS += \ $$PWD/projectpartartefactexception.h \ $$PWD/projectpartartefact.h \ $$PWD/filestatuscache.h \ - $$PWD/indexdataconsumer.h + $$PWD/indexdataconsumer.h \ + $$PWD/projectpartqueue.h !isEmpty(LIBTOOLING_LIBS) { SOURCES += \ @@ -66,4 +67,5 @@ SOURCES += \ $$PWD/sourcerangefilter.cpp \ $$PWD/symbolindexer.cpp \ $$PWD/projectpartartefact.cpp \ - $$PWD/filestatuscache.cpp + $$PWD/filestatuscache.cpp \ + $$PWD/projectpartqueue.cpp diff --git a/src/tools/clangrefactoringbackend/source/projectpartqueue.cpp b/src/tools/clangrefactoringbackend/source/projectpartqueue.cpp new file mode 100644 index 00000000000..d1fdc5a83d6 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/projectpartqueue.cpp @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#include "projectpartqueue.h" + +namespace ClangBackEnd { + +ProjectPartQueue::ProjectPartQueue() +{ + +} + +namespace { + +template +OutputIt set_union_merge(InputIt1 first1, + InputIt1 last1, + InputIt2 first2, + InputIt2 last2, + OutputIt d_first, + Compare comp, + Merge merge) +{ + for (; first1 != last1; ++d_first) { + if (first2 == last2) + return std::copy(first1, last1, d_first); + if (comp(*first2, *first1)) { + *d_first = *first2++; + } else { + if (comp(*first1, *first2)) { + *d_first = *first1; + } else { + *d_first = merge(*first1, *first2); + ++first2; + } + ++first1; + } + } + return std::copy(first2, last2, d_first); +} + +} + +void ProjectPartQueue::addProjectParts(V2::ProjectPartContainers &&projectParts) +{ + auto compare = [](const V2::ProjectPartContainer &first, const V2::ProjectPartContainer &second) { + return first.projectPartId < second.projectPartId; + }; + + auto merge = [](V2::ProjectPartContainer &&first, + V2::ProjectPartContainer &&second) { + first.arguments = std::move(second.arguments); + first.compilerMacros = std::move(second.compilerMacros); + first.includeSearchPaths = std::move(second.includeSearchPaths); + FilePathIds headerPathIds; + headerPathIds.reserve(first.headerPathIds.size() + second.headerPathIds.size()); + std::set_union(first.headerPathIds.begin(), + first.headerPathIds.end(), + second.headerPathIds.begin(), + second.headerPathIds.end(), + std::back_inserter(headerPathIds)); + first.headerPathIds = std::move(headerPathIds); + FilePathIds sourcePathIds; + headerPathIds.reserve(first.sourcePathIds.size() + second.sourcePathIds.size()); + std::set_union(first.sourcePathIds.begin(), + first.sourcePathIds.end(), + second.sourcePathIds.begin(), + second.sourcePathIds.end(), + std::back_inserter(sourcePathIds)); + first.sourcePathIds = std::move(sourcePathIds); + + return first; + }; + + V2::ProjectPartContainers mergedProjectParts; + mergedProjectParts.reserve(m_projectParts.size() + projectParts.size()); + set_union_merge(std::make_move_iterator(m_projectParts.begin()), + std::make_move_iterator(m_projectParts.end()), + std::make_move_iterator(projectParts.begin()), + std::make_move_iterator(projectParts.end()), + std::back_inserter(mergedProjectParts), + compare, + merge); + + m_projectParts = std::move(mergedProjectParts); +} + +class CompareDifference +{ +public: + bool operator()(const V2::ProjectPartContainer &first, const Utils::SmallString &second) + { + return first.projectPartId < second; + } + + bool operator()(const Utils::SmallString &first, const V2::ProjectPartContainer &second) + { + return first < second.projectPartId; + } +}; + +void ProjectPartQueue::removeProjectParts(const Utils::SmallStringVector &projectsPartIds) +{ + V2::ProjectPartContainers notToBeRemovedProjectParts; + notToBeRemovedProjectParts.reserve(m_projectParts.size()); + std::set_difference(std::make_move_iterator(m_projectParts.begin()), + std::make_move_iterator(m_projectParts.end()), + projectsPartIds.begin(), + projectsPartIds.end(), + std::back_inserter(notToBeRemovedProjectParts), + CompareDifference{}); + + m_projectParts = std::move(notToBeRemovedProjectParts); +} + +const V2::ProjectPartContainers &ProjectPartQueue::projectParts() const +{ + return m_projectParts; +} + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/projectpartqueue.h b/src/tools/clangrefactoringbackend/source/projectpartqueue.h new file mode 100644 index 00000000000..b885a1ccb28 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/projectpartqueue.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** 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 + +namespace ClangBackEnd { + +class ProjectPartQueue +{ +public: + ProjectPartQueue(); + + void addProjectParts(V2::ProjectPartContainers &&projectParts); + void removeProjectParts(const Utils::SmallStringVector &projectsPartIds); + + const V2::ProjectPartContainers &projectParts() const; + +private: + V2::ProjectPartContainers m_projectParts; +}; + +} // namespace ClangBackEnd diff --git a/tests/unit/unittest/projectpartqueue-test.cpp b/tests/unit/unittest/projectpartqueue-test.cpp new file mode 100644 index 00000000000..f13d0f55780 --- /dev/null +++ b/tests/unit/unittest/projectpartqueue-test.cpp @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#include "googletest.h" + +#include + +namespace { + +class ProjectPartQueue : public testing::Test +{ +protected: + ClangBackEnd::ProjectPartQueue queue; + ClangBackEnd::V2::ProjectPartContainer projectPart1{"ProjectPart1", + {"--yi"}, + {{"YI","1"}}, + {"/yi"}, + {{1, 1}}, + {{1, 2}}}; + ClangBackEnd::V2::ProjectPartContainer projectPart2{"ProjectPart2", + {"--er"}, + {{"ER","2"}}, + {"/bar"}, + {{2, 1}}, + {{2, 2}}}; + ClangBackEnd::V2::ProjectPartContainer projectPart2b{"ProjectPart2", + {"--liang"}, + {{"LIANG","3"}}, + {"/liang"}, + {{2, 3}}, + {{2, 2}, {2, 4}}}; + ClangBackEnd::V2::ProjectPartContainer projectPart3{"ProjectPart3", + {"--san"}, + {{"SAN","2"}}, + {"/SAN"}, + {{3, 1}}, + {{3, 2}}}; + ClangBackEnd::V2::ProjectPartContainer projectPartMerged{"ProjectPart2", + {"--liang"}, + {{"LIANG","3"}}, + {"/liang"}, + {{2, 1}, {2, 3}}, + {{2, 2}, {2, 4}}}; +}; + +TEST_F(ProjectPartQueue, AddProjectPart) +{ + queue.addProjectParts({projectPart1}); + + queue.addProjectParts({projectPart2}); + + ASSERT_THAT(queue.projectParts(), ElementsAre(projectPart1, projectPart2)); +} + +TEST_F(ProjectPartQueue, IgnoreIdenticalProjectPart) +{ + queue.addProjectParts({projectPart1, projectPart2}); + + queue.addProjectParts({projectPart1, projectPart2}); + + ASSERT_THAT(queue.projectParts(), ElementsAre(projectPart1, projectPart2)); +} + +TEST_F(ProjectPartQueue, MergeSameProjectPartWithSameId) +{ + queue.addProjectParts({projectPart1, projectPart2}); + + queue.addProjectParts({projectPart1, projectPart2b, projectPart3}); + + ASSERT_THAT(queue.projectParts(), ElementsAre(projectPart1, projectPartMerged, projectPart3)); +} + +TEST_F(ProjectPartQueue, RemoveProjectPart) +{ + queue.addProjectParts({projectPart1, projectPart2, projectPart3}); + + queue.removeProjectParts({projectPart2.projectPartId}); + + ASSERT_THAT(queue.projectParts(), ElementsAre(projectPart1, projectPart3)); +} + +} diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 88d56062506..3a390b525c7 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -92,7 +92,8 @@ SOURCES += \ projectpartartefact-test.cpp \ filestatuscache-test.cpp \ highlightingresultreporter-test.cpp \ - precompiledheaderstorage-test.cpp + precompiledheaderstorage-test.cpp \ + projectpartqueue-test.cpp !isEmpty(LIBCLANG_LIBS) { SOURCES += \