From b5c3d5a40df2ced8ac96144acdc6b29785dcf5e5 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 7 Feb 2018 16:11:28 +0100 Subject: [PATCH] Clang: Improve ProjectPartArtefact Empty strings were only handled by accident and wrongly formatted ones were never handled. Now we do nothing for empty strings and throw an exception from wrongly formatted strings. The exceptions are very helpful in the test code because the show errors the the testing data. Change-Id: I87d1678eda7502fdc3f74f51fad491803d28582b Reviewed-by: Ivan Donchevskii --- .../source/clangrefactoringbackend-source.pri | 6 +- .../source/projectpartartefact.cpp | 105 ++++++++++++++++++ ...tpartartefacts.h => projectpartartefact.h} | 56 +++------- .../source/projectpartartefactexception.h | 40 +++++++ .../source/symbolstorageinterface.h | 2 +- .../unit/unittest/gtest-creator-printing.cpp | 2 +- tests/unit/unittest/mocksqlitereadstatement.h | 2 +- .../unittest/projectpartartefact-test.cpp | 29 ++++- tests/unit/unittest/symbolindexer-test.cpp | 10 +- tests/unit/unittest/symbolstorage-test.cpp | 2 +- tests/unit/unittest/unittest.pro | 1 + 11 files changed, 203 insertions(+), 52 deletions(-) create mode 100644 src/tools/clangrefactoringbackend/source/projectpartartefact.cpp rename src/tools/clangrefactoringbackend/source/{projectpartartefacts.h => projectpartartefact.h} (57%) create mode 100644 src/tools/clangrefactoringbackend/source/projectpartartefactexception.h diff --git a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri index 36dfedb41c3..67fb24df110 100644 --- a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri +++ b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri @@ -18,7 +18,7 @@ HEADERS += \ $$PWD/usedmacro.h \ $$PWD/sourcedependency.h \ $$PWD/filestatus.h \ - $$PWD/projectpartartefacts.h + $$PWD/projectpartartefact.h !isEmpty(LIBTOOLING_LIBS) { SOURCES += \ @@ -65,4 +65,6 @@ SOURCES += \ $$PWD/sourcerangefilter.cpp \ $$PWD/symbolindexer.cpp \ $$PWD/symbolentry.cpp \ - $$PWD/symbolstorageinterface.cpp + $$PWD/symbolstorageinterface.cpp \ + $$PWD/projectpartartefact.cpp + diff --git a/src/tools/clangrefactoringbackend/source/projectpartartefact.cpp b/src/tools/clangrefactoringbackend/source/projectpartartefact.cpp new file mode 100644 index 00000000000..b1431c34073 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/projectpartartefact.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "projectpartartefact.h" + +#include + +#include +#include +#include + +namespace ClangBackEnd { + +ProjectPartArtefact::ProjectPartArtefact(Utils::SmallStringView compilerArgumentsText, Utils::SmallStringView compilerMacrosText, int projectPartId) + : compilerArguments(toStringVector(compilerArgumentsText)), + compilerMacros(toCompilerMacros(compilerMacrosText)), + projectPartId(projectPartId) +{ +} + +Utils::SmallStringVector ProjectPartArtefact::toStringVector(Utils::SmallStringView jsonText) +{ + if (jsonText.isEmpty()) + return {}; + + QJsonDocument document = createJsonDocument(jsonText, "Compiler arguments parsing error"); + + return Utils::transform(document.array(), [] (const QJsonValue &value) { + return Utils::SmallString{value.toString()}; + }); +} + +CompilerMacros ProjectPartArtefact::createCompilerMacrosFromDocument(const QJsonDocument &document) +{ + QJsonObject object = document.object(); + CompilerMacros macros; + macros.reserve(object.size()); + + for (auto current = object.constBegin(); current != object.constEnd(); ++current) + macros.emplace_back(current.key(), current.value().toString()); + + std::sort(macros.begin(), macros.end()); + + return macros; +} + +CompilerMacros ProjectPartArtefact::toCompilerMacros(Utils::SmallStringView jsonText) +{ + if (jsonText.isEmpty()) + return {}; + + QJsonDocument document = createJsonDocument(jsonText, "Compiler macros parsing error"); + + return createCompilerMacrosFromDocument(document); +} + +QJsonDocument ProjectPartArtefact::createJsonDocument(Utils::SmallStringView jsonText, + const char *whatError) +{ + QJsonParseError error; + QJsonDocument document = QJsonDocument::fromJson(QByteArray::fromRawData(jsonText.data(), + jsonText.size()), + &error); + checkError(whatError, error); + + return document; +} + +void ProjectPartArtefact::checkError(const char *whatError, const QJsonParseError &error) +{ + if (error.error != QJsonParseError::NoError) { + throw ProjectPartArtefactParseError(whatError, + error.errorString()); + } +} + +bool operator==(const ProjectPartArtefact &first, const ProjectPartArtefact &second) +{ + return first.compilerArguments == second.compilerArguments + && first.compilerMacros == second.compilerMacros; +} + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/projectpartartefacts.h b/src/tools/clangrefactoringbackend/source/projectpartartefact.h similarity index 57% rename from src/tools/clangrefactoringbackend/source/projectpartartefacts.h rename to src/tools/clangrefactoringbackend/source/projectpartartefact.h index 646a87e7906..364ffbd42bf 100644 --- a/src/tools/clangrefactoringbackend/source/projectpartartefacts.h +++ b/src/tools/clangrefactoringbackend/source/projectpartartefact.h @@ -25,14 +25,14 @@ #pragma once -#include +#include "projectpartartefactexception.h" + #include #include -#include -#include -#include +QT_FORWARD_DECLARE_CLASS(QJsonDocument) +QT_FORWARD_DECLARE_STRUCT(QJsonParseError) namespace ClangBackEnd { @@ -41,45 +41,21 @@ class ProjectPartArtefact public: ProjectPartArtefact(Utils::SmallStringView compilerArgumentsText, Utils::SmallStringView compilerMacrosText, - int projectPartId) - : compilerArguments(toStringVector(compilerArgumentsText)), - compilerMacros(toCompilerMacros(compilerMacrosText)), - projectPartId(projectPartId) - { - } + int projectPartId); static - Utils::SmallStringVector toStringVector(Utils::SmallStringView jsonText) - { - QJsonDocument document = QJsonDocument::fromJson(QByteArray::fromRawData(jsonText.data(), - jsonText.size())); - - return Utils::transform(document.array(), [] (const QJsonValue &value) { - return Utils::SmallString{value.toString()}; - }); - } - + Utils::SmallStringVector toStringVector(Utils::SmallStringView jsonText); static - CompilerMacros toCompilerMacros(Utils::SmallStringView jsonText) - { - QJsonDocument document = QJsonDocument::fromJson(QByteArray::fromRawData(jsonText.data(), - jsonText.size())); - QJsonObject object = document.object(); - CompilerMacros macros; - macros.reserve(object.size()); - - for (auto current = object.constBegin(); current != object.constEnd(); ++current) - macros.emplace_back(current.key(), current.value().toString()); - - return macros; - } - + CompilerMacros createCompilerMacrosFromDocument(const QJsonDocument &document); + static + CompilerMacros toCompilerMacros(Utils::SmallStringView jsonText); + static + QJsonDocument createJsonDocument(Utils::SmallStringView jsonText, + const char *whatError); + static + void checkError(const char *whatError, const QJsonParseError &error); friend - bool operator==(const ProjectPartArtefact &first, const ProjectPartArtefact &second) - { - return first.compilerArguments == second.compilerArguments - && first.compilerMacros == second.compilerMacros; - } + bool operator==(const ProjectPartArtefact &first, const ProjectPartArtefact &second); public: Utils::SmallStringVector compilerArguments; @@ -88,4 +64,4 @@ public: }; using ProjectPartArtefacts = std::vector; -} +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/projectpartartefactexception.h b/src/tools/clangrefactoringbackend/source/projectpartartefactexception.h new file mode 100644 index 00000000000..22f1b3ed945 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/projectpartartefactexception.h @@ -0,0 +1,40 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 + +namespace ClangBackEnd { + +class ProjectPartArtefactParseError : public Sqlite::Exception +{ +public: + ProjectPartArtefactParseError(const char *whatErrorHasHappen, + Utils::SmallString &&errorMessage) + : Exception(whatErrorHasHappen, std::move(errorMessage)) + { + } +}; + +} diff --git a/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h index cd77704328e..a68c91e56df 100644 --- a/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h +++ b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h @@ -27,7 +27,7 @@ #include "filestatus.h" #include "projectpartentry.h" -#include "projectpartartefacts.h" +#include "projectpartartefact.h" #include "sourcelocationentry.h" #include "sourcedependency.h" #include "symbolentry.h" diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp index 2403175bfd1..bacc0be5587 100644 --- a/tests/unit/unittest/gtest-creator-printing.cpp +++ b/tests/unit/unittest/gtest-creator-printing.cpp @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/tests/unit/unittest/mocksqlitereadstatement.h b/tests/unit/unittest/mocksqlitereadstatement.h index c0773a512fc..d0566b9c917 100644 --- a/tests/unit/unittest/mocksqlitereadstatement.h +++ b/tests/unit/unittest/mocksqlitereadstatement.h @@ -31,7 +31,7 @@ #include #include -#include +#include #include diff --git a/tests/unit/unittest/projectpartartefact-test.cpp b/tests/unit/unittest/projectpartartefact-test.cpp index a7328125438..03dcf9c0d76 100644 --- a/tests/unit/unittest/projectpartartefact-test.cpp +++ b/tests/unit/unittest/projectpartartefact-test.cpp @@ -25,7 +25,7 @@ #include "googletest.h" -#include +#include namespace { @@ -38,6 +38,19 @@ TEST(ProjectPartArtefact, CompilerArguments) ASSERT_THAT(artefact.compilerArguments, ElementsAre(Eq("-DFoo"), Eq("-DBar"))); } +TEST(ProjectPartArtefact, EmptyCompilerArguments) +{ + ClangBackEnd::ProjectPartArtefact artefact{"", "", 1}; + + ASSERT_THAT(artefact.compilerArguments, IsEmpty()); +} + +TEST(ProjectPartArtefact, CompilerArgumentsParseError) +{ + ASSERT_THROW(ClangBackEnd::ProjectPartArtefact("\"-DFoo\",\"-DBar\"]", "", 1), + ClangBackEnd::ProjectPartArtefactParseError); +} + TEST(ProjectPartArtefact, CompilerMacros) { ClangBackEnd::ProjectPartArtefact artefact{"", "{\"Foo\":\"1\",\"Bar\":\"42\"}", 1}; @@ -45,4 +58,18 @@ TEST(ProjectPartArtefact, CompilerMacros) ASSERT_THAT(artefact.compilerMacros, UnorderedElementsAre(Eq(CompilerMacro{"Foo", "1"}), Eq(CompilerMacro{"Bar", "42"}))); } + +TEST(ProjectPartArtefact, EmptyCompilerMacros) +{ + ClangBackEnd::ProjectPartArtefact artefact{"", "", 1}; + + ASSERT_THAT(artefact.compilerMacros, IsEmpty()); +} + +TEST(ProjectPartArtefact, CompilerMacrosParseError) +{ + ASSERT_THROW(ClangBackEnd::ProjectPartArtefact("", "\"Foo\":\"1\",\"Bar\":\"42\"}", 1), + ClangBackEnd::ProjectPartArtefactParseError); +} + } diff --git a/tests/unit/unittest/symbolindexer-test.cpp b/tests/unit/unittest/symbolindexer-test.cpp index fe509beda1f..8336345e6df 100644 --- a/tests/unit/unittest/symbolindexer-test.cpp +++ b/tests/unit/unittest/symbolindexer-test.cpp @@ -82,12 +82,12 @@ protected: ClangBackEnd::FilePathId generatedFilePathId{1, 21}; ProjectPartContainer projectPart1{"project1", {"-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header"}, - {{"DEFINE", "1"}}, + {{"BAR", "1"}, {"FOO", "1"}}, {header1PathId}, {main1PathId}}; ProjectPartContainer projectPart2{"project2", {"-I", TESTDATA_DIR, "-x", "c++-header", "-Wno-pragma-once-outside-header"}, - {{"DEFINE", "1"}}, + {{"BAR", "1"}, {"FOO", "0"}}, {header2PathId}, {main2PathId}}; FileContainers unsaved{{{TESTDATA_DIR, "query_simplefunction.h"}, @@ -99,7 +99,7 @@ protected: UsedMacros usedMacros{{"Foo", {1, 1}}}; FileStatuses fileStatus{{{1, 2}, 3, 4}}; SourceDependencies sourceDependencies{{{1, 1}, {1, 2}}, {{1, 1}, {1, 3}}}; - ClangBackEnd::ProjectPartArtefact artefact{"[-DFOO]", "{\"FOO\":\"1\"}", 74}; + ClangBackEnd::ProjectPartArtefact artefact{"[\"-DFOO\"]", "{\"FOO\":\"1\",\"BAR\":\"1\"}", 74}; NiceMock mockSqliteTransactionBackend; NiceMock mockCollector; NiceMock mockStorage; @@ -178,10 +178,10 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsUpdateProjectPartsInStorage) { EXPECT_CALL(mockStorage, insertOrUpdateProjectPart(Eq("project1"), ElementsAre("-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header"), - ElementsAre(CompilerMacro{"DEFINE", "1"}))); + ElementsAre(CompilerMacro{"BAR", "1"}, CompilerMacro{"FOO", "1"}))); EXPECT_CALL(mockStorage, insertOrUpdateProjectPart(Eq("project2"), ElementsAre("-I", TESTDATA_DIR, "-x", "c++-header", "-Wno-pragma-once-outside-header"), - ElementsAre(CompilerMacro{"DEFINE", "1"}))); + ElementsAre(CompilerMacro{"BAR", "1"}, CompilerMacro{"FOO", "0"}))); indexer.updateProjectParts({projectPart1, projectPart2}, Utils::clone(unsaved)); } diff --git a/tests/unit/unittest/symbolstorage-test.cpp b/tests/unit/unittest/symbolstorage-test.cpp index f0e1e3f2473..536cbbe4ffa 100644 --- a/tests/unit/unittest/symbolstorage-test.cpp +++ b/tests/unit/unittest/symbolstorage-test.cpp @@ -90,7 +90,7 @@ protected: {2, {"function2USR", "function2"}}}; SourceLocationEntries sourceLocations{{1, {1, 3}, {42, 23}, SymbolType::Declaration}, {2, {1, 4}, {7, 11}, SymbolType::Declaration}}; - ClangBackEnd::ProjectPartArtefact artefact{"-DFOO", "{\"FOO\":\"1\"}", 74}; + ClangBackEnd::ProjectPartArtefact artefact{"[\"-DFOO\"]", "{\"FOO\":\"1\"}", 74}; Storage storage{statementFactory, filePathCache}; }; diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index c40571bd0a2..81efab24636 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -92,6 +92,7 @@ SOURCES += \ nativefilepathview-test.cpp \ mocktimer.cpp \ tokenprocessor-test.cpp \ + projectpartartefact-test.cpp \ highlightingresultreporter-test.cpp !isEmpty(LIBCLANG_LIBS) {