From c88d18c310637a138b9f01b54151b1d7c8e3eb16 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Mon, 16 Nov 2015 16:47:46 +0100 Subject: [PATCH 01/15] Clang: Print command line arguments quoted Change-Id: I82d664f259040b0024d9e1d4df4235442bc6ac73 Reviewed-by: Marco Bubke --- .../ipcsource/commandlinearguments.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/tools/clangbackend/ipcsource/commandlinearguments.cpp b/src/tools/clangbackend/ipcsource/commandlinearguments.cpp index 41c80430be9..5a0aa0e8e92 100644 --- a/src/tools/clangbackend/ipcsource/commandlinearguments.cpp +++ b/src/tools/clangbackend/ipcsource/commandlinearguments.cpp @@ -30,6 +30,8 @@ #include "commandlinearguments.h" +#include + #include namespace ClangBackEnd { @@ -67,13 +69,23 @@ const char *CommandLineArguments::at(int position) const return m_arguments.at(uint(position)); } +static Utf8String maybeQuoted(const char *argumentAsCString) +{ + const auto quotationMark = Utf8StringLiteral("\""); + const auto argument = Utf8String::fromUtf8(argumentAsCString); + + if (argument.contains(quotationMark)) + return argument; + + return quotationMark + argument + quotationMark; +} + void CommandLineArguments::print() const { using namespace std; - cerr << "Arguments to libclang:"; for (const auto &argument : m_arguments) - cerr << ' ' << argument; + cerr << ' ' << maybeQuoted(argument).constData(); cerr << endl; } From 6deaf6b23d76e0dded86a86f15940debc7598444 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Tue, 17 Nov 2015 16:21:13 +0100 Subject: [PATCH 02/15] CppTools: Guard against doubled header paths Change-Id: If183b6d2210028f74dae839db782114ce79911c4 Reviewed-by: Tobias Hunger Reviewed-by: Marco Bubke --- src/plugins/cpptools/cppprojects.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/plugins/cpptools/cppprojects.cpp b/src/plugins/cpptools/cppprojects.cpp index d1ab05fb686..ba2b14ba0f5 100644 --- a/src/plugins/cpptools/cppprojects.cpp +++ b/src/plugins/cpptools/cppprojects.cpp @@ -59,6 +59,16 @@ ProjectPart::ProjectPart() { } +static ProjectPart::HeaderPath toProjectPartHeaderPath(const ProjectExplorer::HeaderPath &headerPath) +{ + const ProjectPart::HeaderPath::Type headerPathType = + headerPath.kind() == ProjectExplorer::HeaderPath::FrameworkHeaderPath + ? ProjectPart::HeaderPath::FrameworkPath + : ProjectPart::HeaderPath::IncludePath; + + return ProjectPart::HeaderPath(headerPath.path(), headerPathType); +} + /*! \brief Retrieves info from concrete compiler using it's flags. @@ -106,10 +116,9 @@ void ProjectPart::evaluateToolchain(const ToolChain *tc, const QList headers = tc->systemHeaderPaths(commandLineFlags, sysRoot); foreach (const ProjectExplorer::HeaderPath &header, headers) { - headerPaths << ProjectPart::HeaderPath(header.path(), - header.kind() == ProjectExplorer::HeaderPath::FrameworkHeaderPath - ? ProjectPart::HeaderPath::FrameworkPath - : ProjectPart::HeaderPath::IncludePath); + const HeaderPath headerPath = toProjectPartHeaderPath(header); + if (!headerPaths.contains(headerPath)) + headerPaths << headerPath; } toolchainDefines = tc->predefinedMacros(commandLineFlags); From 609bc2a38916931514241f5fbba9b4ad3c6ea0fd Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Mon, 23 Nov 2015 13:31:46 +0100 Subject: [PATCH 03/15] Clang: Avoid needless reparse after first parse Change-Id: Ie97818f29d1df61380cd1c22ef2598091050b10d Reviewed-by: Marco Bubke --- .../ipcsource/translationunit.cpp | 4 +- .../ipcsource/translationunits.cpp | 4 +- tests/unit/unittest/clangipcservertest.cpp | 41 +++++++++++++++---- tests/unit/unittest/translationunittest.cpp | 33 +++++++++++++++ 4 files changed, 69 insertions(+), 13 deletions(-) diff --git a/src/tools/clangbackend/ipcsource/translationunit.cpp b/src/tools/clangbackend/ipcsource/translationunit.cpp index 8769f7caef3..052761d3639 100644 --- a/src/tools/clangbackend/ipcsource/translationunit.cpp +++ b/src/tools/clangbackend/ipcsource/translationunit.cpp @@ -83,8 +83,8 @@ public: CXTranslationUnit translationUnit = nullptr; CXIndex index = nullptr; uint documentRevision = 0; - bool needsToBeReparsed = false; - bool hasNewDiagnostics = false; + bool needsToBeReparsed = false; + bool hasNewDiagnostics = true; }; TranslationUnitData::TranslationUnitData(const Utf8String &filePath, diff --git a/src/tools/clangbackend/ipcsource/translationunits.cpp b/src/tools/clangbackend/ipcsource/translationunits.cpp index 8fd3b14b7c6..a14f15a55f9 100644 --- a/src/tools/clangbackend/ipcsource/translationunits.cpp +++ b/src/tools/clangbackend/ipcsource/translationunits.cpp @@ -62,10 +62,8 @@ void TranslationUnits::create(const QVector &fileContainers) { checkIfTranslationUnitsDoesNotExists(fileContainers); - for (const FileContainer &fileContainer : fileContainers) { + for (const FileContainer &fileContainer : fileContainers) createTranslationUnit(fileContainer); - updateTranslationUnitsWithChangedDependency(fileContainer.filePath()); - } } void TranslationUnits::update(const QVector &fileContainers) diff --git a/tests/unit/unittest/clangipcservertest.cpp b/tests/unit/unittest/clangipcservertest.cpp index 175e19e5213..be19eab6eed 100644 --- a/tests/unit/unittest/clangipcservertest.cpp +++ b/tests/unit/unittest/clangipcservertest.cpp @@ -77,11 +77,18 @@ using ClangBackEnd::TranslationUnitDoesNotExistMessage; using ClangBackEnd::ProjectPartsDoNotExistMessage; using ClangBackEnd::UpdateTranslationUnitsForEditorMessage; -MATCHER_P3(HasDirtyTranslationUnit, filePath, projectPartId, documentRevision, +MATCHER_P5(HasDirtyTranslationUnit, + filePath, + projectPartId, + documentRevision, + isNeedingReparse, + hasNewDiagnostics, std::string(negation ? "isn't" : "is") + " translation unit with file path "+ PrintToString(filePath) + " and project " + PrintToString(projectPartId) + " and document revision " + PrintToString(documentRevision) + + " and isNeedingReparse = " + PrintToString(isNeedingReparse) + + " and hasNewDiagnostics = " + PrintToString(hasNewDiagnostics) ) { auto &&translationUnits = arg.translationUnitsForTestOnly(); @@ -89,16 +96,24 @@ MATCHER_P3(HasDirtyTranslationUnit, filePath, projectPartId, documentRevision, auto translationUnit = translationUnits.translationUnit(filePath, projectPartId); if (translationUnit.documentRevision() == documentRevision) { - if (translationUnit.hasNewDiagnostics()) { - if (translationUnit.isNeedingReparse()) - return true; + if (translationUnit.hasNewDiagnostics() && !hasNewDiagnostics) { + *result_listener << "hasNewDiagnostics is true"; + return false; + } else if (!translationUnit.hasNewDiagnostics() && hasNewDiagnostics) { + *result_listener << "hasNewDiagnostics is false"; + return false; + } + + if (translationUnit.isNeedingReparse() && !isNeedingReparse) { + *result_listener << "isNeedingReparse is true"; + return false; + } else if (!translationUnit.isNeedingReparse() && isNeedingReparse) { *result_listener << "isNeedingReparse is false"; return false; } - *result_listener << "hasNewDiagnostics is false"; - return false; + return true; } *result_listener << "revision number is " << PrintToString(translationUnit.documentRevision()); @@ -406,8 +421,18 @@ TEST_F(ClangIpcServer, TicketNumberIsForwarded) clangServer.completeCode(completeCodeMessage); } -TEST_F(ClangIpcServer, TranslationUnitIsDirtyAfterCreation) +TEST_F(ClangIpcServer, TranslationUnitAfterCreationNeedsNoReparseAndHasNewDiagnostics) { - ASSERT_THAT(clangServer, HasDirtyTranslationUnit(functionTestFilePath, projectPartId, 0)); + ASSERT_THAT(clangServer, HasDirtyTranslationUnit(functionTestFilePath, projectPartId, 0U, false, true)); } + +TEST_F(ClangIpcServer, TranslationUnitAfterUpdateNeedsReparseAndHasNewDiagnostics) +{ + const auto fileContainer = FileContainer(functionTestFilePath, projectPartId,unsavedContent(unsavedTestFilePath), true, 1); + + clangServer.updateTranslationUnitsForEditor({{fileContainer}}); + + ASSERT_THAT(clangServer, HasDirtyTranslationUnit(functionTestFilePath, projectPartId, 1U, true, true)); +} + } diff --git a/tests/unit/unittest/translationunittest.cpp b/tests/unit/unittest/translationunittest.cpp index 452aa171aec..4bc2d110611 100644 --- a/tests/unit/unittest/translationunittest.cpp +++ b/tests/unit/unittest/translationunittest.cpp @@ -194,6 +194,38 @@ TEST_F(TranslationUnit, DependedFilePaths) Contains(Utf8StringLiteral(TESTDATA_DIR"/translationunits.h")))); } +TEST_F(TranslationUnit, NeedsNoReparseAfterCreation) +{ + translationUnit.cxTranslationUnit(); + + ASSERT_FALSE(translationUnit.isNeedingReparse()); +} + +TEST_F(TranslationUnit, HasNewDiagnosticsAfterCreation) +{ + translationUnit.cxTranslationUnit(); + + ASSERT_TRUE(translationUnit.hasNewDiagnostics()); +} + +TEST_F(TranslationUnit, NeedsReparseAfterChangeOfMainFile) +{ + translationUnit.cxTranslationUnit(); + + translationUnit.setDirtyIfDependencyIsMet(translationUnitFilePath); + + ASSERT_TRUE(translationUnit.isNeedingReparse()); +} + +TEST_F(TranslationUnit, HasNewDiagnosticsAfterChangeOfMainFile) +{ + translationUnit.cxTranslationUnit(); + + translationUnit.setDirtyIfDependencyIsMet(translationUnitFilePath); + + ASSERT_TRUE(translationUnit.hasNewDiagnostics()); +} + TEST_F(TranslationUnit, NoNeedForReparsingForIndependendFile) { translationUnit.cxTranslationUnit(); @@ -234,6 +266,7 @@ TEST_F(TranslationUnit, NeedsNoReparsingAfterReparsing) TEST_F(TranslationUnit, HasNoNewDiagnosticsForIndependendFile) { translationUnit.cxTranslationUnit(); + translationUnit.diagnostics(); // Reset hasNewDiagnostics translationUnit.setDirtyIfDependencyIsMet(Utf8StringLiteral(TESTDATA_DIR"/otherfiles.h")); From 79c27ec6f1c337916ee196908050896f21704905 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 23 Nov 2015 15:34:09 +0100 Subject: [PATCH 04/15] Avoid running qmake by using unsortedVersions Use unsortedVersions() instead of versions() where possible, since versions() sorts by version numbers, and therefore needs "qmake -query" to have run. Change-Id: I76a05f1647d2baacbd33829c6b3bf719a1c8dcbb Reviewed-by: Tobias Hunger --- src/plugins/android/androidsettingswidget.cpp | 2 +- src/plugins/ios/iosconfigurations.cpp | 2 +- src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp | 2 +- src/plugins/qtsupport/qtversionmanager.cpp | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index 0d90bb65da0..7e395c4e37a 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -298,7 +298,7 @@ void AndroidSettingsWidget::check(AndroidSettingsWidget::Mode mode) toolchainsForAbi.insert(ati.abi); QSet qtVersionsForAbi; - foreach (QtSupport::BaseQtVersion *qtVersion, QtSupport::QtVersionManager::versions()) { + foreach (QtSupport::BaseQtVersion *qtVersion, QtSupport::QtVersionManager::unsortedVersions()) { if (qtVersion->type() != QLatin1String(Constants::ANDROIDQT) || qtVersion->qtAbis().isEmpty()) continue; qtVersionsForAbi.insert(qtVersion->qtAbis().first()); diff --git a/src/plugins/ios/iosconfigurations.cpp b/src/plugins/ios/iosconfigurations.cpp index 9bf56c2a6ee..31da93fd426 100644 --- a/src/plugins/ios/iosconfigurations.cpp +++ b/src/plugins/ios/iosconfigurations.cpp @@ -144,7 +144,7 @@ static QHash findToolChains(const QList &p static QHash> iosQtVersions() { QHash> versions; - foreach (BaseQtVersion *qtVersion, QtVersionManager::versions()) { + foreach (BaseQtVersion *qtVersion, QtVersionManager::unsortedVersions()) { if (!qtVersion->isValid() || qtVersion->type() != QLatin1String(Constants::IOSQT)) continue; foreach (const Abi &abi, qtVersion->qtAbis()) diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp index 017c2e444d9..c4d2aaebe3f 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp @@ -108,7 +108,7 @@ QList QmakeProjectImporter::import(const FileName &importPath, bool qCDebug(logs) << " QMake:" << canonicalQmakeBinary; BaseQtVersion *version - = Utils::findOrDefault(QtVersionManager::versions(), + = Utils::findOrDefault(QtVersionManager::unsortedVersions(), [&canonicalQmakeBinary](BaseQtVersion *v) -> bool { QFileInfo vfi = v->qmakeCommand().toFileInfo(); FileName current = FileName::fromString(vfi.canonicalFilePath()); diff --git a/src/plugins/qtsupport/qtversionmanager.cpp b/src/plugins/qtsupport/qtversionmanager.cpp index 3a44f6861db..2be77a98a68 100644 --- a/src/plugins/qtsupport/qtversionmanager.cpp +++ b/src/plugins/qtsupport/qtversionmanager.cpp @@ -503,7 +503,7 @@ static void updateDocumentation() void QtVersionManager::updateDumpFor(const FileName &qmakeCommand) { - foreach (BaseQtVersion *v, versions()) { + foreach (BaseQtVersion *v, unsortedVersions()) { if (v->qmakeCommand() == qmakeCommand) v->recheckDumper(); } @@ -631,7 +631,7 @@ void QtVersionManager::setNewQtVersions(QList newVersions) BaseQtVersion *QtVersionManager::qtVersionForQMakeBinary(const FileName &qmakePath) { - return Utils::findOrDefault(versions(), Utils::equal(&BaseQtVersion::qmakeCommand, qmakePath)); + return Utils::findOrDefault(unsortedVersions(), Utils::equal(&BaseQtVersion::qmakeCommand, qmakePath)); } } // namespace QtVersion From 983473163f0de7aea54d6d3e86d58ba8149a69dc Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 23 Nov 2015 17:31:35 +0100 Subject: [PATCH 05/15] iostool: Allow sequential client connections The QML debug server allows this and QtCreator uses it, so iostool should support it, too. Change-Id: I71d4143457d427795e5abcbef0ad5d26378d5e9d Task-number: QTCREATORBUG-15383 Reviewed-by: Jake Petroules Reviewed-by: Eike Ziller Reviewed-by: Tobias Hunger --- src/tools/iostool/main.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/tools/iostool/main.cpp b/src/tools/iostool/main.cpp index f902f761cd5..fc2bab4c84b 100644 --- a/src/tools/iostool/main.cpp +++ b/src/tools/iostool/main.cpp @@ -114,6 +114,7 @@ public: IosTool *iosTool(); public slots: void handleNewRelayConnection(); + void removeRelayConnection(Relayer *relayer); protected: virtual void newRelayConnection() = 0; @@ -231,9 +232,12 @@ void Relayer::setClientSocket(QTcpSocket *clientSocket) { QTC_CHECK(!m_clientSocket); m_clientSocket = clientSocket; - if (m_clientSocket) + if (m_clientSocket) { connect(m_clientSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(handleClientHasError(QAbstractSocket::SocketError))); + connect(m_clientSocket, &QAbstractSocket::disconnected, + this, [this](){server()->removeRelayConnection(this);}); + } } bool Relayer::startRelay(int serverFileDescriptor) @@ -354,7 +358,7 @@ void Relayer::handleClientHasData() void Relayer::handleClientHasError(QAbstractSocket::SocketError error) { iosTool()->errorMsg(tr("iOS Debugging connection to creator failed with error %1").arg(error)); - iosTool()->stopRelayServers(); + server()->removeRelayConnection(this); } IosTool *Relayer::iosTool() @@ -446,6 +450,12 @@ void RelayServer::handleNewRelayConnection() newRelayConnection(); } +void RelayServer::removeRelayConnection(Relayer *relayer) +{ + m_connections.removeAll(relayer); + relayer->deleteLater(); +} + SingleRelayServer::SingleRelayServer(IosTool *parent, int serverFileDescriptor) : RelayServer(parent) @@ -458,9 +468,7 @@ SingleRelayServer::SingleRelayServer(IosTool *parent, void SingleRelayServer::newRelayConnection() { if (m_connections.size() > 0) { - m_server.close(); - QTcpSocket *s = m_server.nextPendingConnection(); - delete s; + delete m_server.nextPendingConnection(); return; } QTcpSocket *clientSocket = m_server.nextPendingConnection(); @@ -469,7 +477,6 @@ void SingleRelayServer::newRelayConnection() m_connections.append(newConnection); newConnection->startRelay(m_serverFileDescriptor); } - m_server.close(); } GenericRelayServer::GenericRelayServer(IosTool *parent, int remotePort, From bdf66b0a3fa549302b8a7a6586e907b323f81b22 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 20 Nov 2015 15:35:40 +0100 Subject: [PATCH 06/15] QmlDesigner: Adding specifics for GridLayout Task-number: QTCREATORBUG-14821 Change-Id: Ifa037975c99762fb8866ffffa118332044842dff Reviewed-by: Eike Ziller Reviewed-by: Tim Jenssen --- .../QtQuick/Layouts/GridLayoutSpecifics.qml | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Layouts/GridLayoutSpecifics.qml diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Layouts/GridLayoutSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Layouts/GridLayoutSpecifics.qml new file mode 100644 index 00000000000..f16981eb125 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Layouts/GridLayoutSpecifics.qml @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://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.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +****************************************************************************/ + +import QtQuick 2.1 +import HelperWidgets 2.0 +import QtQuick.Layouts 1.0 + +Column { + anchors.left: parent.left + anchors.right: parent.right + + Section { + anchors.left: parent.left + anchors.right: parent.right + caption: qsTr("GridLayout") + + + SectionLayout { + + Label { + text: qsTr("Columns") + } + + SecondColumnLayout { + SpinBox { + backendValue: backendValues.columns + minimumValue: 0 + maximumValue: 2000 + decimals: 0 + } + + ExpandingSpacer { + } + } + + Label { + text: qsTr("Rows") + } + + SecondColumnLayout { + SpinBox { + backendValue: backendValues.rows + minimumValue: 0 + maximumValue: 2000 + decimals: 0 + } + + ExpandingSpacer { + } + } + + Label { + text: qsTr("Flow") + } + + SecondColumnLayout { + ComboBox { + model: ["LeftToRight", "TopToBottom"] + backendValue: backendValues.flow + Layout.fillWidth: true + scope: "GridLayout" + } + } + + Label { + text: qsTr("Layout Direction") + } + + SecondColumnLayout { + ComboBox { + model: ["LeftToRight", "RightToLeft"] + backendValue: backendValues.layoutDirection + Layout.fillWidth: true + scope: "Qt" + } + + } + + + Label { + text: qsTr("Row Spacing") + } + + SecondColumnLayout { + SpinBox { + backendValue: backendValues.rowSpacing + minimumValue: -4000 + maximumValue: 4000 + decimals: 0 + } + + ExpandingSpacer { + } + } + + Label { + text: qsTr("Column Spacing") + } + + SecondColumnLayout { + SpinBox { + backendValue: backendValues.columnSpacing + minimumValue: -4000 + maximumValue: 4000 + decimals: 0 + } + + ExpandingSpacer { + } + } + } + } +} From 8345ba2d2d450b2143a51e0afafdc46782b1825e Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Fri, 20 Nov 2015 14:11:26 +0100 Subject: [PATCH 07/15] Android: Set JDK path for builds Without it the build may fail. Task-number: QTCREATORBUG-15382 Change-Id: Ie7f823746516d17e8e32a367953cf491378f00c1 Reviewed-by: BogDan Vatra Reviewed-by: Eike Ziller --- src/plugins/android/androidtoolchain.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/plugins/android/androidtoolchain.cpp b/src/plugins/android/androidtoolchain.cpp index 1b4177a0b60..5f3b0f0a8c4 100644 --- a/src/plugins/android/androidtoolchain.cpp +++ b/src/plugins/android/androidtoolchain.cpp @@ -106,7 +106,6 @@ bool AndroidToolChain::isValid() const void AndroidToolChain::addToEnvironment(Environment &env) const { - // TODO this vars should be configurable in projects -> build tab // TODO invalidate all .pro files !!! @@ -114,9 +113,15 @@ void AndroidToolChain::addToEnvironment(Environment &env) const env.set(QLatin1String("ANDROID_NDK_TOOLCHAIN_PREFIX"), AndroidConfig::toolchainPrefix(targetAbi())); env.set(QLatin1String("ANDROID_NDK_TOOLS_PREFIX"), AndroidConfig::toolsPrefix(targetAbi())); env.set(QLatin1String("ANDROID_NDK_TOOLCHAIN_VERSION"), m_ndkToolChainVersion); - QString javaHome = AndroidConfigurations::currentConfig().openJDKLocation().toString(); - if (!javaHome.isEmpty() && QFileInfo::exists(javaHome)) - env.set(QLatin1String("JAVA_HOME"), javaHome); + const Utils::FileName javaHome = AndroidConfigurations::currentConfig().openJDKLocation(); + if (!javaHome.isEmpty() && javaHome.toFileInfo().exists()) { + env.set(QLatin1String("JAVA_HOME"), javaHome.toString()); + Utils::FileName javaBin = javaHome; + javaBin.appendPath(QLatin1String("bin")); + const QString jb = javaBin.toUserOutput(); + if (!Utils::contains(env.path(), [&jb](const QString &p) { return p == jb; })) + env.prependOrSetPath(jb); + } env.set(QLatin1String("ANDROID_HOME"), AndroidConfigurations::currentConfig().sdkLocation().toString()); env.set(QLatin1String("ANDROID_SDK_ROOT"), AndroidConfigurations::currentConfig().sdkLocation().toString()); } From bd10e9b0202da72ea4a61532406ed5e1765f70dd Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 25 Nov 2015 15:11:23 +0100 Subject: [PATCH 08/15] Clang: Only apply fixits to the corresponding revision Change-Id: I4f4136369e1b261338d444670c212565e0c6b824 Reviewed-by: Nikolai Kosjar --- src/plugins/clangcodemodel/clangdiagnosticmanager.cpp | 5 +++++ src/plugins/clangcodemodel/clangdiagnosticmanager.h | 2 ++ .../clangcodemodel/clangeditordocumentprocessor.cpp | 5 +++++ .../clangcodemodel/clangeditordocumentprocessor.h | 2 ++ .../clangcodemodel/clangmodelmanagersupport.cpp | 11 +++++++++++ 5 files changed, 25 insertions(+) diff --git a/src/plugins/clangcodemodel/clangdiagnosticmanager.cpp b/src/plugins/clangcodemodel/clangdiagnosticmanager.cpp index 6c46c05b76e..13544424bd8 100644 --- a/src/plugins/clangcodemodel/clangdiagnosticmanager.cpp +++ b/src/plugins/clangcodemodel/clangdiagnosticmanager.cpp @@ -189,6 +189,11 @@ QList ClangDiagnosticManager::takeExtraSelections() return extraSelections; } +void ClangDiagnosticManager::clearDiagnosticsWithFixIts() +{ + m_fixItdiagnostics.clear(); +} + void ClangDiagnosticManager::generateEditorSelections() { m_extraSelections.clear(); diff --git a/src/plugins/clangcodemodel/clangdiagnosticmanager.h b/src/plugins/clangcodemodel/clangdiagnosticmanager.h index 85ba1dde499..8007fc47fe8 100644 --- a/src/plugins/clangcodemodel/clangdiagnosticmanager.h +++ b/src/plugins/clangcodemodel/clangdiagnosticmanager.h @@ -56,6 +56,8 @@ public: const QVector &diagnosticsWithFixIts() const; QList takeExtraSelections(); + void clearDiagnosticsWithFixIts(); + private: QString filePath() const; void filterDiagnostics(const QVector &diagnostics); diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp index 341f541255c..5739960751c 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp @@ -224,6 +224,11 @@ ClangBackEnd::FileContainer ClangEditorDocumentProcessor::fileContainer() const return fileContainer(m_projectPart.data()); } +void ClangEditorDocumentProcessor::clearDiagnosticsWithFixIts() +{ + m_diagnosticManager.clearDiagnosticsWithFixIts(); +} + ClangEditorDocumentProcessor *ClangEditorDocumentProcessor::get(const QString &filePath) { return qobject_cast(BaseEditorDocumentProcessor::get(filePath)); diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.h b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h index 575725e8738..ded0258210f 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.h +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h @@ -81,6 +81,8 @@ public: ClangBackEnd::FileContainer fileContainer() const; + void clearDiagnosticsWithFixIts(); + public: static ClangEditorDocumentProcessor *get(const QString &filePath); diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 06cda925ee1..26780648305 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -197,6 +197,15 @@ void ModelManagerSupportClang::onCppDocumentReloadFinishedOnTranslationUnit(bool } } +namespace { +void clearDiagnosticFixIts(const QString &filePath) +{ + auto processor = ClangEditorDocumentProcessor::get(filePath); + if (processor) + processor->clearDiagnosticsWithFixIts(); +} +} + void ModelManagerSupportClang::onCppDocumentContentsChangedOnTranslationUnit(int position, int /*charsRemoved*/, int /*charsAdded*/) @@ -206,6 +215,8 @@ void ModelManagerSupportClang::onCppDocumentContentsChangedOnTranslationUnit(int m_ipcCommunicator.updateChangeContentStartPosition(document->filePath().toString(), position); m_ipcCommunicator.updateTranslationUnitIfNotCurrentDocument(document); + + clearDiagnosticFixIts(document->filePath().toString()); } void ModelManagerSupportClang::onCppDocumentAboutToReloadOnUnsavedFile() From 2e499b73d602ab619109ca31d00962906090a446 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 18 Nov 2015 19:09:38 +0100 Subject: [PATCH 09/15] Clang: Filter scope operators Scope operators are not really user defined. Change-Id: I1ab08dc3db7c39b98da02b6ef10bf78b75a6856d Reviewed-by: Nikolai Kosjar --- .../ipcsource/highlightinginformation.cpp | 14 +++++++++++++- .../unittest/data/highlightinginformations.cpp | 16 ++++++++++++++++ .../unittest/highlightinginformationstest.cpp | 14 ++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/tools/clangbackend/ipcsource/highlightinginformation.cpp b/src/tools/clangbackend/ipcsource/highlightinginformation.cpp index 808a0407d14..d91ddf26b9d 100644 --- a/src/tools/clangbackend/ipcsource/highlightinginformation.cpp +++ b/src/tools/clangbackend/ipcsource/highlightinginformation.cpp @@ -241,11 +241,23 @@ HighlightingType literalKind(const Cursor &cursor) Q_UNREACHABLE(); } +bool hasOperatorName(const char *operatorString) +{ + return std::strncmp(operatorString, "operator", 8) == 0; +} + +HighlightingType operatorKind(const Cursor &cursor) +{ + if (hasOperatorName(cursor.spelling().cString())) + return HighlightingType::Operator; + else + return HighlightingType::Invalid; +} HighlightingType punctationKind(const Cursor &cursor) { switch (cursor.kind()) { - case CXCursor_DeclRefExpr: return HighlightingType::Operator; + case CXCursor_DeclRefExpr: return operatorKind(cursor); default: return HighlightingType::Invalid; } } diff --git a/tests/unit/unittest/data/highlightinginformations.cpp b/tests/unit/unittest/data/highlightinginformations.cpp index d651fd65e1c..db5f8afde72 100644 --- a/tests/unit/unittest/data/highlightinginformations.cpp +++ b/tests/unit/unittest/data/highlightinginformations.cpp @@ -383,3 +383,19 @@ void f17() { TemplatedType TemplatedTypeDeclaration; } + +void f18() +{ + auto value = 1 + 2; +} + +class ScopeClass +{ +public: + static void ScopeOperator(); +}; + +void f19() +{ + ScopeClass::ScopeOperator(); +} diff --git a/tests/unit/unittest/highlightinginformationstest.cpp b/tests/unit/unittest/highlightinginformationstest.cpp index c09f12cc170..8e5ee4f0ee0 100644 --- a/tests/unit/unittest/highlightinginformationstest.cpp +++ b/tests/unit/unittest/highlightinginformationstest.cpp @@ -881,6 +881,20 @@ TEST_F(HighlightingInformations, TemplatedTypeDeclaration) ASSERT_THAT(infos[0], HasType(HighlightingType::Type)); } +TEST_F(HighlightingInformations, NoOperator) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(389, 24)); + + ASSERT_THAT(infos[2], HasType(HighlightingType::Invalid)); +} + +TEST_F(HighlightingInformations, ScopeOperator) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(400, 33)); + + ASSERT_THAT(infos[1], HasType(HighlightingType::Invalid)); +} + Data *HighlightingInformations::d; void HighlightingInformations::SetUpTestCase() From 9310c02bc8e79753d6dfb014ac35a39da6607fd4 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 25 Nov 2015 15:21:24 +0100 Subject: [PATCH 10/15] Clang: Add better diagnostic sending We send first the current editor, next the visible editors and the end everything else. Change-Id: I4a7b5924ffe563d6a74251739ddedcd005ce046c Reviewed-by: Nikolai Kosjar --- .../ipcsource/translationunit.cpp | 22 ++ .../clangbackend/ipcsource/translationunit.h | 6 + .../ipcsource/translationunits.cpp | 67 +++++- .../clangbackend/ipcsource/translationunits.h | 13 +- .../unittest/mocksenddiagnosticscallback.h | 53 +++++ tests/unit/unittest/translationunitstest.cpp | 207 +++++++++++++++++- tests/unit/unittest/unittest.pro | 3 +- 7 files changed, 355 insertions(+), 16 deletions(-) create mode 100644 tests/unit/unittest/mocksenddiagnosticscallback.h diff --git a/src/tools/clangbackend/ipcsource/translationunit.cpp b/src/tools/clangbackend/ipcsource/translationunit.cpp index 052761d3639..cd880f0567d 100644 --- a/src/tools/clangbackend/ipcsource/translationunit.cpp +++ b/src/tools/clangbackend/ipcsource/translationunit.cpp @@ -85,6 +85,8 @@ public: uint documentRevision = 0; bool needsToBeReparsed = false; bool hasNewDiagnostics = true; + bool isUsedByCurrentEditor = false; + bool isVisibleInEditor = false; }; TranslationUnitData::TranslationUnitData(const Utf8String &filePath, @@ -125,6 +127,26 @@ bool TranslationUnit::isNull() const return !d; } +void TranslationUnit::setIsUsedByCurrentEditor(bool isUsedByCurrentEditor) +{ + d->isUsedByCurrentEditor = isUsedByCurrentEditor; +} + +bool TranslationUnit::isUsedByCurrentEditor() const +{ + return d->isUsedByCurrentEditor; +} + +void TranslationUnit::setIsVisibleInEditor(bool isVisibleInEditor) +{ + d->isVisibleInEditor = isVisibleInEditor; +} + +bool TranslationUnit::isVisibleInEditor() const +{ + return d->isVisibleInEditor; +} + void TranslationUnit::reset() { d.reset(); diff --git a/src/tools/clangbackend/ipcsource/translationunit.h b/src/tools/clangbackend/ipcsource/translationunit.h index fd3831cb3e0..37c47413611 100644 --- a/src/tools/clangbackend/ipcsource/translationunit.h +++ b/src/tools/clangbackend/ipcsource/translationunit.h @@ -86,6 +86,12 @@ public: bool isNull() const; + void setIsUsedByCurrentEditor(bool isUsedByCurrentEditor); + bool isUsedByCurrentEditor() const; + + void setIsVisibleInEditor(bool isVisibleInEditor); + bool isVisibleInEditor() const; + void reset(); void reparse() const; diff --git a/src/tools/clangbackend/ipcsource/translationunits.cpp b/src/tools/clangbackend/ipcsource/translationunits.cpp index a14f15a55f9..07975bf693d 100644 --- a/src/tools/clangbackend/ipcsource/translationunits.cpp +++ b/src/tools/clangbackend/ipcsource/translationunits.cpp @@ -39,6 +39,8 @@ #include +#include + namespace ClangBackEnd { bool operator==(const FileContainer &fileContainer, const TranslationUnit &translationUnit) @@ -95,6 +97,18 @@ void TranslationUnits::remove(const QVector &fileContainers) updateTranslationUnitsWithChangedDependencies(fileContainers); } +void TranslationUnits::setCurrentEditor(const Utf8String &filePath) +{ + for (TranslationUnit &translationUnit : translationUnits_) + translationUnit.setIsUsedByCurrentEditor(translationUnit.filePath() == filePath); +} + +void TranslationUnits::setVisibleEditors(const Utf8StringVector &filePaths) +{ + for (TranslationUnit &translationUnit : translationUnits_) + translationUnit.setIsVisibleInEditor(filePaths.contains(translationUnit.filePath())); +} + const TranslationUnit &TranslationUnits::translationUnit(const Utf8String &filePath, const Utf8String &projectPartId) const { checkIfProjectPartExists(projectPartId); @@ -151,14 +165,55 @@ void TranslationUnits::updateTranslationUnitsWithChangedDependencies(const QVect DiagnosticSendState TranslationUnits::sendChangedDiagnostics() { - for (const auto &translationUnit : translationUnits_) { - if (translationUnit.hasNewDiagnostics()) { - sendDiagnosticChangedMessage(translationUnit); - return DiagnosticSendState::MaybeThereAreMoreDiagnostics; - } + auto diagnosticSendState = sendChangedDiagnosticsForCurrentEditor(); + if (diagnosticSendState == DiagnosticSendState::NoDiagnosticSend) + diagnosticSendState = sendChangedDiagnosticsForVisibleEditors(); + if (diagnosticSendState == DiagnosticSendState::NoDiagnosticSend) + diagnosticSendState = sendChangedDiagnosticsForAll(); + + return diagnosticSendState; +} + +template +DiagnosticSendState TranslationUnits::sendChangedDiagnostics(Predicate predicate) +{ + auto foundTranslationUnit = std::find_if(translationUnits_.begin(), + translationUnits_.end(), + predicate); + + if (foundTranslationUnit != translationUnits().end()) { + sendDiagnosticChangedMessage(*foundTranslationUnit); + return DiagnosticSendState::MaybeThereAreMoreDiagnostics; } - return DiagnosticSendState::AllDiagnosticSend; + return DiagnosticSendState::NoDiagnosticSend; +} + +DiagnosticSendState TranslationUnits::sendChangedDiagnosticsForCurrentEditor() +{ + auto hasDiagnosticsForCurrentEditor = [] (const TranslationUnit &translationUnit) { + return translationUnit.isUsedByCurrentEditor() && translationUnit.hasNewDiagnostics(); + }; + + return sendChangedDiagnostics(hasDiagnosticsForCurrentEditor); +} + +DiagnosticSendState TranslationUnits::sendChangedDiagnosticsForVisibleEditors() +{ + auto hasDiagnosticsForVisibleEditor = [] (const TranslationUnit &translationUnit) { + return translationUnit.isVisibleInEditor() && translationUnit.hasNewDiagnostics(); + }; + + return sendChangedDiagnostics(hasDiagnosticsForVisibleEditor); +} + +DiagnosticSendState TranslationUnits::sendChangedDiagnosticsForAll() +{ + auto hasDiagnostics = [] (const TranslationUnit &translationUnit) { + return translationUnit.hasNewDiagnostics(); + }; + + return sendChangedDiagnostics(hasDiagnostics); } void TranslationUnits::setSendChangeDiagnosticsCallback(std::function &&callback) diff --git a/src/tools/clangbackend/ipcsource/translationunits.h b/src/tools/clangbackend/ipcsource/translationunits.h index 58433b85666..a08d642d48b 100644 --- a/src/tools/clangbackend/ipcsource/translationunits.h +++ b/src/tools/clangbackend/ipcsource/translationunits.h @@ -49,8 +49,8 @@ class DiagnosticsChangedMessage; enum class DiagnosticSendState { - AllDiagnosticSend, - MaybeThereAreMoreDiagnostics + NoDiagnosticSend, + MaybeThereAreMoreDiagnostics, }; class TranslationUnits @@ -62,6 +62,9 @@ public: void update(const QVector &fileContainers); void remove(const QVector &fileContainers); + void setCurrentEditor(const Utf8String &filePath); + void setVisibleEditors(const Utf8StringVector &filePaths); + const TranslationUnit &translationUnit(const Utf8String &filePath, const Utf8String &projectPartId) const; const TranslationUnit &translationUnit(const FileContainer &fileContainer) const; bool hasTranslationUnit(const Utf8String &filePath) const; @@ -76,6 +79,9 @@ public: void updateTranslationUnitsWithChangedDependencies(const QVector &fileContainers); DiagnosticSendState sendChangedDiagnostics(); + DiagnosticSendState sendChangedDiagnosticsForCurrentEditor(); + DiagnosticSendState sendChangedDiagnosticsForVisibleEditors(); + DiagnosticSendState sendChangedDiagnosticsForAll(); void setSendChangeDiagnosticsCallback(std::function &&callback); @@ -99,6 +105,9 @@ private: void sendDiagnosticChangedMessage(const TranslationUnit &translationUnit); void removeTranslationUnits(const QVector &fileContainers); + template + DiagnosticSendState sendChangedDiagnostics(Predicate predicate); + private: ClangFileSystemWatcher fileSystemWatcher; std::function sendDiagnosticsChangedCallback; diff --git a/tests/unit/unittest/mocksenddiagnosticscallback.h b/tests/unit/unittest/mocksenddiagnosticscallback.h new file mode 100644 index 00000000000..ecb24fcbc99 --- /dev/null +++ b/tests/unit/unittest/mocksenddiagnosticscallback.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ +#ifndef MOCKSENDDIAGNOSTICSCALLBACK_H +#define MOCKSENDDIAGNOSTICSCALLBACK_H + +#include +#include +#include +#include "gtest-qt-printing.h" + +class SendDiagnosticCallback +{ +public: + virtual ~SendDiagnosticCallback() = default; + + virtual void sendDiagnostic() = 0; +}; + +class MockSendDiagnosticCallback : public SendDiagnosticCallback +{ +public: + MOCK_METHOD0(sendDiagnostic, + void()); +}; + +#endif // MOCKSENDDIAGNOSTICSCALLBACK_H diff --git a/tests/unit/unittest/translationunitstest.cpp b/tests/unit/unittest/translationunitstest.cpp index ec2dfb9951d..0b19ecdf62d 100644 --- a/tests/unit/unittest/translationunitstest.cpp +++ b/tests/unit/unittest/translationunitstest.cpp @@ -43,9 +43,10 @@ #include #include - #include +#include "mocksenddiagnosticscallback.h" + #include #include #include @@ -54,6 +55,8 @@ using ClangBackEnd::TranslationUnit; using ClangBackEnd::UnsavedFiles; using ClangBackEnd::ProjectPart; +using ClangBackEnd::DiagnosticsChangedMessage; +using ClangBackEnd::DiagnosticSendState; using testing::IsNull; using testing::NotNull; @@ -81,23 +84,24 @@ class TranslationUnits : public ::testing::Test { protected: void SetUp() override; + void sendAllDiagnostics(); + void sendAllCurrentEditorDiagnostics(); + void sendAllVisibleEditorsDiagnostics(); +protected: ClangBackEnd::ProjectParts projects; ClangBackEnd::UnsavedFiles unsavedFiles; ClangBackEnd::TranslationUnits translationUnits{projects, unsavedFiles}; + MockSendDiagnosticCallback mockSendDiagnosticCallback; const Utf8String filePath = Utf8StringLiteral(TESTDATA_DIR"/translationunits.cpp"); const Utf8String headerPath = Utf8StringLiteral(TESTDATA_DIR"/translationunits.h"); const Utf8String nonExistingFilePath = Utf8StringLiteral("foo.cpp"); const Utf8String projectPartId = Utf8StringLiteral("projectPartId"); const Utf8String nonExistingProjectPartId = Utf8StringLiteral("nonExistingProjectPartId"); + const ClangBackEnd::FileContainer fileContainer{filePath, projectPartId}; + const ClangBackEnd::FileContainer headerContainer{headerPath, projectPartId}; }; -void TranslationUnits::SetUp() -{ - projects.createOrUpdate({ClangBackEnd::ProjectPartContainer(projectPartId)}); -} - - TEST_F(TranslationUnits, ThrowForGettingWithWrongFilePath) { ASSERT_THROW(translationUnits.translationUnit(nonExistingFilePath, projectPartId), @@ -279,4 +283,193 @@ TEST_F(TranslationUnits, HasNotTranslationUnit) ASSERT_FALSE(translationUnits.hasTranslationUnit(filePath)); } +TEST_F(TranslationUnits, isUsedByCurrentEditor) +{ + translationUnits.create({fileContainer}); + auto translationUnit = translationUnits.translationUnit(fileContainer); + + translationUnits.setCurrentEditor(filePath); + + ASSERT_TRUE(translationUnit.isUsedByCurrentEditor()); +} + +TEST_F(TranslationUnits, IsNotCurrentEditor) +{ + translationUnits.create({fileContainer}); + auto translationUnit = translationUnits.translationUnit(fileContainer); + + translationUnits.setCurrentEditor(headerPath); + + ASSERT_FALSE(translationUnit.isUsedByCurrentEditor()); +} + +TEST_F(TranslationUnits, IsNotCurrentEditorAfterBeingCurrent) +{ + translationUnits.create({fileContainer}); + auto translationUnit = translationUnits.translationUnit(fileContainer); + translationUnits.setCurrentEditor(filePath); + + translationUnits.setCurrentEditor(headerPath); + + ASSERT_FALSE(translationUnit.isUsedByCurrentEditor()); +} + +TEST_F(TranslationUnits, IsVisibleEditor) +{ + translationUnits.create({fileContainer}); + auto translationUnit = translationUnits.translationUnit(fileContainer); + + translationUnits.setVisibleEditors({filePath}); + + ASSERT_TRUE(translationUnit.isVisibleInEditor()); +} + +TEST_F(TranslationUnits, IsNotVisibleEditor) +{ + translationUnits.create({fileContainer}); + auto translationUnit = translationUnits.translationUnit(fileContainer); + + translationUnits.setVisibleEditors({headerPath}); + + ASSERT_FALSE(translationUnit.isVisibleInEditor()); +} + +TEST_F(TranslationUnits, IsNotVisibleEditorAfterBeingVisible) +{ + translationUnits.create({fileContainer}); + auto translationUnit = translationUnits.translationUnit(fileContainer); + translationUnits.setVisibleEditors({filePath}); + + translationUnits.setVisibleEditors({headerPath}); + + ASSERT_FALSE(translationUnit.isVisibleInEditor()); +} + +TEST_F(TranslationUnits, DoNotSendDiagnosticsIfThereIsNothingToSend) +{ + EXPECT_CALL(mockSendDiagnosticCallback, sendDiagnostic()).Times(0); + + sendAllDiagnostics(); +} + +TEST_F(TranslationUnits, SendDiagnosticsAfterTranslationUnitCreation) +{ + translationUnits.create({fileContainer, headerContainer}); + + EXPECT_CALL(mockSendDiagnosticCallback, sendDiagnostic()).Times(2); + + sendAllDiagnostics(); +} + +TEST_F(TranslationUnits, DoNotSendDiagnosticsAfterGettingDiagnostics) +{ + translationUnits.create({fileContainer, headerContainer}); + auto translationUnit = translationUnits.translationUnit(fileContainer); + translationUnit.diagnostics(); + + EXPECT_CALL(mockSendDiagnosticCallback, sendDiagnostic()).Times(1); + + sendAllDiagnostics(); +} + +TEST_F(TranslationUnits, SendDiagnosticsForCurrentEditor) +{ + translationUnits.create({fileContainer, headerContainer}); + auto translationUnit = translationUnits.translationUnit(fileContainer); + translationUnit.setIsUsedByCurrentEditor(true); + + EXPECT_CALL(mockSendDiagnosticCallback, sendDiagnostic()).Times(1); + + sendAllCurrentEditorDiagnostics(); +} + +TEST_F(TranslationUnits, DoNotSendDiagnosticsForCurrentEditorIfThereIsNoCurrentEditor) +{ + translationUnits.create({fileContainer, headerContainer}); + + EXPECT_CALL(mockSendDiagnosticCallback, sendDiagnostic()).Times(0); + + sendAllCurrentEditorDiagnostics(); +} + +TEST_F(TranslationUnits, DoNotSendDiagnosticsForCurrentEditorAfterGettingDiagnostics) +{ + translationUnits.create({fileContainer, headerContainer}); + auto translationUnit = translationUnits.translationUnit(fileContainer); + translationUnit.setIsUsedByCurrentEditor(true); + translationUnit.diagnostics(); + + EXPECT_CALL(mockSendDiagnosticCallback, sendDiagnostic()).Times(0); + + sendAllCurrentEditorDiagnostics(); +} + +TEST_F(TranslationUnits, DoNotSendDiagnosticsForVisibleEditorIfThereAreNoVisibleEditors) +{ + translationUnits.create({fileContainer, headerContainer}); + + EXPECT_CALL(mockSendDiagnosticCallback, sendDiagnostic()).Times(0); + + translationUnits.sendChangedDiagnosticsForVisibleEditors(); +} + +TEST_F(TranslationUnits, SendDiagnosticsForVisibleEditors) +{ + translationUnits.create({fileContainer, headerContainer}); + auto fileTranslationUnit = translationUnits.translationUnit(fileContainer); + fileTranslationUnit.setIsVisibleInEditor(true); + auto headerTranslationUnit = translationUnits.translationUnit(headerContainer); + headerTranslationUnit.setIsVisibleInEditor(true); + + EXPECT_CALL(mockSendDiagnosticCallback, sendDiagnostic()).Times(2); + + sendAllVisibleEditorsDiagnostics(); +} + +TEST_F(TranslationUnits, SendOnlyOneDiagnosticsForVisibleEditor) +{ + translationUnits.create({fileContainer, headerContainer}); + auto fileTranslationUnit = translationUnits.translationUnit(fileContainer); + fileTranslationUnit.setIsVisibleInEditor(true); + auto headerTranslationUnit = translationUnits.translationUnit(headerContainer); + headerTranslationUnit.setIsVisibleInEditor(true); + headerTranslationUnit.diagnostics(); + + EXPECT_CALL(mockSendDiagnosticCallback, sendDiagnostic()).Times(1); + + sendAllVisibleEditorsDiagnostics(); +} + +void TranslationUnits::SetUp() +{ + projects.createOrUpdate({ClangBackEnd::ProjectPartContainer(projectPartId)}); + + auto callback = [&] (const DiagnosticsChangedMessage &) { mockSendDiagnosticCallback.sendDiagnostic(); }; + translationUnits.setSendChangeDiagnosticsCallback(callback); +} + +void TranslationUnits::sendAllDiagnostics() +{ + auto diagnosticSendState = DiagnosticSendState::MaybeThereAreMoreDiagnostics; + + while (diagnosticSendState == DiagnosticSendState::MaybeThereAreMoreDiagnostics) + diagnosticSendState = translationUnits.sendChangedDiagnostics(); +} + +void TranslationUnits::sendAllCurrentEditorDiagnostics() +{ + auto diagnosticSendState = DiagnosticSendState::MaybeThereAreMoreDiagnostics; + + while (diagnosticSendState == DiagnosticSendState::MaybeThereAreMoreDiagnostics) + diagnosticSendState = translationUnits.sendChangedDiagnosticsForCurrentEditor(); +} + +void TranslationUnits::sendAllVisibleEditorsDiagnostics() +{ + auto diagnosticSendState = DiagnosticSendState::MaybeThereAreMoreDiagnostics; + + while (diagnosticSendState == DiagnosticSendState::MaybeThereAreMoreDiagnostics) + diagnosticSendState = translationUnits.sendChangedDiagnosticsForVisibleEditors(); +} + } diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 6fe2d25f2e2..b2d209d4dca 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -63,6 +63,7 @@ HEADERS += \ mockipclient.h \ mockipcserver.h \ spydummy.h \ - matcher-diagnosticcontainer.h + matcher-diagnosticcontainer.h \ + mocksenddiagnosticscallback.h OTHER_FILES += $$files(data/*) From 8c3959534d556d7102953df89a4d08f2eb80709b Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 25 Nov 2015 15:29:28 +0100 Subject: [PATCH 11/15] Clang: Add current and visible editor message Change-Id: Ifd88bc032388ae7a8d3dbc0f1f5746665074cc18 Reviewed-by: Nikolai Kosjar --- .../clangbackendipc/clangbackendipc-lib.pri | 6 +- src/libs/clangbackendipc/cmbmessages.cpp | 3 + src/libs/clangbackendipc/ipcclientinterface.h | 1 + .../clangbackendipc/ipcserverinterface.cpp | 5 + src/libs/clangbackendipc/ipcserverinterface.h | 1 + src/libs/clangbackendipc/ipcserverproxy.cpp | 6 + src/libs/clangbackendipc/ipcserverproxy.h | 2 +- .../updatevisibletranslationunitsmessage.cpp | 116 ++++++++++++++++ .../updatevisibletranslationunitsmessage.h | 72 ++++++++++ src/libs/sqlite/utf8string.cpp | 8 ++ src/libs/sqlite/utf8string.h | 3 + .../clangbackend/ipcsource/clangipcserver.cpp | 13 ++ .../clangbackend/ipcsource/clangipcserver.h | 1 + tests/unit/echoserver/echoipcserver.cpp | 6 + tests/unit/echoserver/echoipcserver.h | 1 + tests/unit/unittest/clangipcservertest.cpp | 131 +++++++++++------- .../unittest/clientserverinprocesstest.cpp | 14 ++ tests/unit/unittest/mockipcserver.h | 2 + 18 files changed, 341 insertions(+), 50 deletions(-) create mode 100644 src/libs/clangbackendipc/updatevisibletranslationunitsmessage.cpp create mode 100644 src/libs/clangbackendipc/updatevisibletranslationunitsmessage.h diff --git a/src/libs/clangbackendipc/clangbackendipc-lib.pri b/src/libs/clangbackendipc/clangbackendipc-lib.pri index cc11840a043..3084a13761b 100644 --- a/src/libs/clangbackendipc/clangbackendipc-lib.pri +++ b/src/libs/clangbackendipc/clangbackendipc-lib.pri @@ -46,7 +46,8 @@ SOURCES += $$PWD/ipcserverinterface.cpp \ $$PWD/requestdiagnosticsmessage.cpp \ $$PWD/registerunsavedfilesforeditormessage.cpp \ $$PWD/unregisterunsavedfilesforeditormessage.cpp \ - $$PWD/updatetranslationunitsforeditormessage.cpp + $$PWD/updatetranslationunitsforeditormessage.cpp \ + $$PWD/updatevisibletranslationunitsmessage.cpp HEADERS += \ $$PWD/ipcserverinterface.h \ @@ -87,6 +88,7 @@ HEADERS += \ $$PWD/requestdiagnosticsmessage.h \ $$PWD/registerunsavedfilesforeditormessage.h \ $$PWD/unregisterunsavedfilesforeditormessage.h \ - $$PWD/updatetranslationunitsforeditormessage.h + $$PWD/updatetranslationunitsforeditormessage.h \ + $$PWD/updatevisibletranslationunitsmessage.h contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols diff --git a/src/libs/clangbackendipc/cmbmessages.cpp b/src/libs/clangbackendipc/cmbmessages.cpp index 04af03c5e7d..d275de5353d 100644 --- a/src/libs/clangbackendipc/cmbmessages.cpp +++ b/src/libs/clangbackendipc/cmbmessages.cpp @@ -49,6 +49,7 @@ #include "translationunitdoesnotexistmessage.h" #include "unregisterunsavedfilesforeditormessage.h" #include "updatetranslationunitsforeditormessage.h" +#include "updatevisibletranslationunitsmessage.h" #include @@ -82,6 +83,8 @@ void Messages::registerMessages() registerMetaType(); registerMetaType(); + registerMetaType(); + registerMetaType(); registerMetaType(); registerMetaType(); diff --git a/src/libs/clangbackendipc/ipcclientinterface.h b/src/libs/clangbackendipc/ipcclientinterface.h index 32d17e4c60d..5600e130763 100644 --- a/src/libs/clangbackendipc/ipcclientinterface.h +++ b/src/libs/clangbackendipc/ipcclientinterface.h @@ -50,6 +50,7 @@ class DiagnosticsChangedMessage; class RequestDiagnosticsMessage; class RegisterUnsavedFilesForEditorMessage; class UnregisterUnsavedFilesForEditorMessage; +class UpdateVisibleTranslationUnitsMessage; class CMBIPC_EXPORT IpcClientInterface : public IpcInterface { diff --git a/src/libs/clangbackendipc/ipcserverinterface.cpp b/src/libs/clangbackendipc/ipcserverinterface.cpp index 92ba85a6de7..93717dfa33a 100644 --- a/src/libs/clangbackendipc/ipcserverinterface.cpp +++ b/src/libs/clangbackendipc/ipcserverinterface.cpp @@ -39,6 +39,7 @@ #include "requestdiagnosticsmessage.h" #include "unregisterunsavedfilesforeditormessage.h" #include "updatetranslationunitsforeditormessage.h" +#include "updatevisibletranslationunitsmessage.h" #include #include @@ -57,6 +58,8 @@ void IpcServerInterface::dispatch(const QVariant &message) static const int unregisterUnsavedFilesForEditorMessageType = QMetaType::type("ClangBackEnd::UnregisterUnsavedFilesForEditorMessage"); static const int completeCodeMessageType = QMetaType::type("ClangBackEnd::CompleteCodeMessage"); static const int requestDiagnosticsMessageType = QMetaType::type("ClangBackEnd::RequestDiagnosticsMessage"); + static const int updateVisibleTranslationUnitsMessageType = QMetaType::type("ClangBackEnd::UpdateVisibleTranslationUnitsMessage"); + int type = message.userType(); @@ -80,6 +83,8 @@ void IpcServerInterface::dispatch(const QVariant &message) completeCode(message.value()); else if (type == requestDiagnosticsMessageType) requestDiagnostics(message.value()); + else if (type == updateVisibleTranslationUnitsMessageType) + updateVisibleTranslationUnits(message.value()); else qWarning() << "Unknown IpcServerMessage"; } diff --git a/src/libs/clangbackendipc/ipcserverinterface.h b/src/libs/clangbackendipc/ipcserverinterface.h index 0682970412c..98d1441c0d5 100644 --- a/src/libs/clangbackendipc/ipcserverinterface.h +++ b/src/libs/clangbackendipc/ipcserverinterface.h @@ -54,6 +54,7 @@ public: virtual void unregisterUnsavedFilesForEditor(const UnregisterUnsavedFilesForEditorMessage &message) = 0; virtual void completeCode(const CompleteCodeMessage &message) = 0; virtual void requestDiagnostics(const RequestDiagnosticsMessage &message) = 0; + virtual void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) = 0; void addClient(IpcClientInterface *client); void removeClient(IpcClientInterface *client); diff --git a/src/libs/clangbackendipc/ipcserverproxy.cpp b/src/libs/clangbackendipc/ipcserverproxy.cpp index a1d9d978be5..fa5777267c8 100644 --- a/src/libs/clangbackendipc/ipcserverproxy.cpp +++ b/src/libs/clangbackendipc/ipcserverproxy.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -119,5 +120,10 @@ void IpcServerProxy::requestDiagnostics(const ClangBackEnd::RequestDiagnosticsMe writeMessageBlock.write(QVariant::fromValue(message)); } +void IpcServerProxy::updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) +{ + writeMessageBlock.write(QVariant::fromValue(message)); +} + } // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/ipcserverproxy.h b/src/libs/clangbackendipc/ipcserverproxy.h index a3f52ff128c..d4c42887f4f 100644 --- a/src/libs/clangbackendipc/ipcserverproxy.h +++ b/src/libs/clangbackendipc/ipcserverproxy.h @@ -65,7 +65,7 @@ public: void unregisterUnsavedFilesForEditor(const UnregisterUnsavedFilesForEditorMessage &message) override; void completeCode(const CompleteCodeMessage &message) override; void requestDiagnostics(const RequestDiagnosticsMessage &message) override; - + void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) override; void readMessages(); void resetCounter(); diff --git a/src/libs/clangbackendipc/updatevisibletranslationunitsmessage.cpp b/src/libs/clangbackendipc/updatevisibletranslationunitsmessage.cpp new file mode 100644 index 00000000000..8e383fa86c1 --- /dev/null +++ b/src/libs/clangbackendipc/updatevisibletranslationunitsmessage.cpp @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ +#include "updatevisibletranslationunitsmessage.h" + +#include "container_common.h" + +#include +#include + +#include +#include +#include + +namespace ClangBackEnd { + +UpdateVisibleTranslationUnitsMessage::UpdateVisibleTranslationUnitsMessage( + const Utf8String ¤tEditorFilePath, + const Utf8StringVector &visibleEditorFilePaths) + : currentEditorFilePath_(currentEditorFilePath), + visibleEditorFilePaths_(visibleEditorFilePaths) +{ +} + +const Utf8String &UpdateVisibleTranslationUnitsMessage::currentEditorFilePath() const +{ + return currentEditorFilePath_; +} + +const Utf8StringVector &UpdateVisibleTranslationUnitsMessage::visibleEditorFilePaths() const +{ + return visibleEditorFilePaths_; +} + +QDataStream &operator<<(QDataStream &out, const UpdateVisibleTranslationUnitsMessage &message) +{ + out << message.currentEditorFilePath_; + out << message.visibleEditorFilePaths_; + + return out; +} + +QDataStream &operator>>(QDataStream &in, UpdateVisibleTranslationUnitsMessage &message) +{ + in >> message.currentEditorFilePath_; + in >> message.visibleEditorFilePaths_; + + return in; +} + +bool operator==(const UpdateVisibleTranslationUnitsMessage &first, const UpdateVisibleTranslationUnitsMessage &second) +{ + return first.currentEditorFilePath_ == second.currentEditorFilePath_ + && first.visibleEditorFilePaths_ == second.visibleEditorFilePaths_; +} + +bool operator<(const UpdateVisibleTranslationUnitsMessage &first, const UpdateVisibleTranslationUnitsMessage &second) +{ + return first.currentEditorFilePath_ < second.currentEditorFilePath_ + && compareContainer(first.visibleEditorFilePaths_, second.visibleEditorFilePaths_); +} + +QDebug operator<<(QDebug debug, const UpdateVisibleTranslationUnitsMessage &message) +{ + debug.nospace() << "UpdateVisibleTranslationUnitsMessage("; + + debug.nospace() << message.currentEditorFilePath() << ", "; + + for (const Utf8String &visibleEditorFilePath : message.visibleEditorFilePaths()) + debug.nospace() << visibleEditorFilePath << ", "; + + debug.nospace() << ")"; + + return debug; +} + +void PrintTo(const UpdateVisibleTranslationUnitsMessage &message, ::std::ostream* os) +{ + *os << "UpdateVisibleTranslationUnitsMessage("; + + *os << message.currentEditorFilePath().constData() << ", "; + + auto visiblePaths = message.visibleEditorFilePaths(); + + std::copy(visiblePaths.cbegin(), visiblePaths.cend(), std::ostream_iterator(*os, ", ")); + + *os << ")"; +} + +} // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/updatevisibletranslationunitsmessage.h b/src/libs/clangbackendipc/updatevisibletranslationunitsmessage.h new file mode 100644 index 00000000000..3383ccc616f --- /dev/null +++ b/src/libs/clangbackendipc/updatevisibletranslationunitsmessage.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ +#ifndef CLANGBACKEND_UPDATEVISIBLETRANSLATIONUNITSMESSAGE_H +#define CLANGBACKEND_UPDATEVISIBLETRANSLATIONUNITSMESSAGE_H + +#include + +#include + +#include + +namespace ClangBackEnd { + +class CMBIPC_EXPORT UpdateVisibleTranslationUnitsMessage +{ + friend CMBIPC_EXPORT QDataStream &operator<<(QDataStream &out, const UpdateVisibleTranslationUnitsMessage &message); + friend CMBIPC_EXPORT QDataStream &operator>>(QDataStream &in, UpdateVisibleTranslationUnitsMessage &message); + friend CMBIPC_EXPORT bool operator==(const UpdateVisibleTranslationUnitsMessage &first, const UpdateVisibleTranslationUnitsMessage &second); + friend CMBIPC_EXPORT bool operator<(const UpdateVisibleTranslationUnitsMessage &first, const UpdateVisibleTranslationUnitsMessage &second); + +public: + UpdateVisibleTranslationUnitsMessage() = default; + UpdateVisibleTranslationUnitsMessage(const Utf8String ¤tEditorFilePath, + const Utf8StringVector &visibleEditorFilePaths); + + const Utf8String ¤tEditorFilePath() const; + const Utf8StringVector &visibleEditorFilePaths() const; + +private: + Utf8String currentEditorFilePath_; + Utf8StringVector visibleEditorFilePaths_; +}; + +CMBIPC_EXPORT QDataStream &operator<<(QDataStream &out, const UpdateVisibleTranslationUnitsMessage &message); +CMBIPC_EXPORT QDataStream &operator>>(QDataStream &in, UpdateVisibleTranslationUnitsMessage &message); +CMBIPC_EXPORT bool operator==(const UpdateVisibleTranslationUnitsMessage &first, const UpdateVisibleTranslationUnitsMessage &second); +CMBIPC_EXPORT bool operator<(const UpdateVisibleTranslationUnitsMessage &first, const UpdateVisibleTranslationUnitsMessage &second); + +CMBIPC_EXPORT QDebug operator<<(QDebug debug, const UpdateVisibleTranslationUnitsMessage &message); +void PrintTo(const UpdateVisibleTranslationUnitsMessage &message, ::std::ostream* os); +} // namespace ClangBackEnd + +Q_DECLARE_METATYPE(ClangBackEnd::UpdateVisibleTranslationUnitsMessage) + +#endif // CLANGBACKEND_UPDATEVISIBLETRANSLATIONUNITSMESSAGE_H diff --git a/src/libs/sqlite/utf8string.cpp b/src/libs/sqlite/utf8string.cpp index c8cbaea2230..9fb92b5d39d 100644 --- a/src/libs/sqlite/utf8string.cpp +++ b/src/libs/sqlite/utf8string.cpp @@ -269,6 +269,14 @@ void PrintTo(const Utf8String &text, ::std::ostream* os) *os << "\"" << text.toByteArray().data() << "\""; } +std::ostream& operator<<(std::ostream &os, const Utf8String &utf8String) +{ + using std::ostream; + os << utf8String.constData(); + + return os; +} + uint qHash(const Utf8String &utf8String) { return qHash(utf8String.byteArray); diff --git a/src/libs/sqlite/utf8string.h b/src/libs/sqlite/utf8string.h index c6adfc93716..6158f8b690d 100644 --- a/src/libs/sqlite/utf8string.h +++ b/src/libs/sqlite/utf8string.h @@ -36,6 +36,8 @@ #include #include +#include + class Utf8StringVector; class Utf8String; @@ -120,6 +122,7 @@ SQLITE_EXPORT QDataStream &operator<<(QDataStream &datastream, const Utf8String SQLITE_EXPORT QDataStream &operator>>(QDataStream &datastream, Utf8String &text); SQLITE_EXPORT QDebug operator<<(QDebug debug, const Utf8String &text); SQLITE_EXPORT void PrintTo(const Utf8String &text, ::std::ostream* os); +SQLITE_EXPORT std::ostream& operator<<(std::ostream &os, const Utf8String &utf8String); SQLITE_EXPORT uint qHash(const Utf8String &utf8String); diff --git a/src/tools/clangbackend/ipcsource/clangipcserver.cpp b/src/tools/clangbackend/ipcsource/clangipcserver.cpp index 320c982c88e..31c3ae481f3 100644 --- a/src/tools/clangbackend/ipcsource/clangipcserver.cpp +++ b/src/tools/clangbackend/ipcsource/clangipcserver.cpp @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -243,6 +244,18 @@ void ClangIpcServer::requestDiagnostics(const RequestDiagnosticsMessage &message } } +void ClangIpcServer::updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) +{ + TIME_SCOPE_DURATION("ClangIpcServer::updateVisibleTranslationUnits"); + + try { + translationUnits.setCurrentEditor(message.currentEditorFilePath()); + translationUnits.setVisibleEditors(message.visibleEditorFilePaths()); + } catch (const std::exception &exception) { + qWarning() << "Error in ClangIpcServer::updateVisibleTranslationUnits:" << exception.what(); + } +} + const TranslationUnits &ClangIpcServer::translationUnitsForTestOnly() const { return translationUnits; diff --git a/src/tools/clangbackend/ipcsource/clangipcserver.h b/src/tools/clangbackend/ipcsource/clangipcserver.h index d4e5c6442ac..bfb1313e64f 100644 --- a/src/tools/clangbackend/ipcsource/clangipcserver.h +++ b/src/tools/clangbackend/ipcsource/clangipcserver.h @@ -61,6 +61,7 @@ public: void unregisterUnsavedFilesForEditor(const UnregisterUnsavedFilesForEditorMessage &message) override; void completeCode(const CompleteCodeMessage &message) override; void requestDiagnostics(const RequestDiagnosticsMessage &message) override; + void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) override; const TranslationUnits &translationUnitsForTestOnly() const; diff --git a/tests/unit/echoserver/echoipcserver.cpp b/tests/unit/echoserver/echoipcserver.cpp index c9dbfb42e88..fe1e79180f3 100644 --- a/tests/unit/echoserver/echoipcserver.cpp +++ b/tests/unit/echoserver/echoipcserver.cpp @@ -43,6 +43,7 @@ #include "requestdiagnosticsmessage.h" #include "unregisterunsavedfilesforeditormessage.h" #include "updatetranslationunitsforeditormessage.h" +#include "updatevisibletranslationunitsmessage.h" #include #include @@ -106,6 +107,11 @@ void EchoIpcServer::requestDiagnostics(const RequestDiagnosticsMessage &message) echoMessage(QVariant::fromValue(message)); } +void EchoIpcServer::updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) +{ + echoMessage(QVariant::fromValue(message)); +} + void EchoIpcServer::echoMessage(const QVariant &message) { client()->echo(EchoMessage(message)); diff --git a/tests/unit/echoserver/echoipcserver.h b/tests/unit/echoserver/echoipcserver.h index cb3c55d2bb4..f7710f6f3dc 100644 --- a/tests/unit/echoserver/echoipcserver.h +++ b/tests/unit/echoserver/echoipcserver.h @@ -49,6 +49,7 @@ public: void unregisterUnsavedFilesForEditor(const UnregisterUnsavedFilesForEditorMessage &message) override; void completeCode(const CompleteCodeMessage &message) override; void requestDiagnostics(const RequestDiagnosticsMessage &message) override; + void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) override; private: void echoMessage(const QVariant &message); diff --git a/tests/unit/unittest/clangipcservertest.cpp b/tests/unit/unittest/clangipcservertest.cpp index be19eab6eed..2f0711832b0 100644 --- a/tests/unit/unittest/clangipcservertest.cpp +++ b/tests/unit/unittest/clangipcservertest.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -76,6 +77,7 @@ using ClangBackEnd::ProjectPartContainer; using ClangBackEnd::TranslationUnitDoesNotExistMessage; using ClangBackEnd::ProjectPartsDoNotExistMessage; using ClangBackEnd::UpdateTranslationUnitsForEditorMessage; +using ClangBackEnd::UpdateVisibleTranslationUnitsMessage; MATCHER_P5(HasDirtyTranslationUnit, filePath, @@ -135,11 +137,13 @@ protected: void registerProjectPart(); void changeProjectPartArguments(); void changeProjectPartArgumentsToWrongValues(); + void updateVisibilty(const Utf8String ¤tEditor, const Utf8String &additionalVisibleEditor); static const Utf8String unsavedContent(const QString &unsavedFilePath); protected: MockIpcClient mockIpcClient; ClangBackEnd::ClangIpcServer clangServer; + const ClangBackEnd::TranslationUnits &translationUnits = clangServer.translationUnitsForTestOnly(); const Utf8String projectPartId = Utf8StringLiteral("pathToProjectPart.pro"); const Utf8String functionTestFilePath = Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_function.cpp"); const Utf8String variableTestFilePath = Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_variable.cpp"); @@ -148,53 +152,6 @@ protected: const Utf8String parseErrorTestFilePath = Utf8StringLiteral(TESTDATA_DIR"/complete_translationunit_parse_error.cpp"); }; - -void ClangIpcServer::SetUp() -{ - clangServer.addClient(&mockIpcClient); - registerProjectPart(); - registerFiles(); -} - -void ClangIpcServer::registerFiles() -{ - RegisterTranslationUnitForEditorMessage message({FileContainer(functionTestFilePath, projectPartId, unsavedContent(unsavedTestFilePath), true), - FileContainer(variableTestFilePath, projectPartId)}); - - clangServer.registerTranslationUnitsForEditor(message); -} - -void ClangIpcServer::registerProjectPart() -{ - RegisterProjectPartsForEditorMessage message({ProjectPartContainer(projectPartId)}); - - clangServer.registerProjectPartsForEditor(message); -} - -void ClangIpcServer::changeProjectPartArguments() -{ - RegisterProjectPartsForEditorMessage message({ProjectPartContainer(projectPartId, {Utf8StringLiteral("-DArgumentDefinition")})}); - - clangServer.registerProjectPartsForEditor(message); -} - -void ClangIpcServer::changeProjectPartArgumentsToWrongValues() -{ - RegisterProjectPartsForEditorMessage message({ProjectPartContainer(projectPartId, {Utf8StringLiteral("-blah")})}); - - clangServer.registerProjectPartsForEditor(message); -} - -const Utf8String ClangIpcServer::unsavedContent(const QString &unsavedFilePath) -{ - QFile unsavedFileContentFile(unsavedFilePath); - bool isOpen = unsavedFileContentFile.open(QIODevice::ReadOnly | QIODevice::Text); - if (!isOpen) - ADD_FAILURE() << "File with the unsaved content cannot be opened!"; - - return Utf8String::fromByteArray(unsavedFileContentFile.readAll()); -} - TEST_F(ClangIpcServer, GetCodeCompletion) { CompleteCodeMessage completeCodeMessage(functionTestFilePath, @@ -426,6 +383,86 @@ TEST_F(ClangIpcServer, TranslationUnitAfterCreationNeedsNoReparseAndHasNewDiagno ASSERT_THAT(clangServer, HasDirtyTranslationUnit(functionTestFilePath, projectPartId, 0U, false, true)); } +TEST_F(ClangIpcServer, SetCurrentAndVisibleEditor) +{ + auto functionTranslationUnit = translationUnits.translationUnit(functionTestFilePath, projectPartId); + auto variableTranslationUnit = translationUnits.translationUnit(variableTestFilePath, projectPartId); + + updateVisibilty(functionTestFilePath, variableTestFilePath); + + ASSERT_TRUE(functionTranslationUnit.isUsedByCurrentEditor()); + ASSERT_TRUE(functionTranslationUnit.isVisibleInEditor()); + ASSERT_TRUE(variableTranslationUnit.isVisibleInEditor()); +} + +TEST_F(ClangIpcServer, IsNotCurrentCurrentAndVisibleEditorAnymore) +{ + auto functionTranslationUnit = translationUnits.translationUnit(functionTestFilePath, projectPartId); + auto variableTranslationUnit = translationUnits.translationUnit(variableTestFilePath, projectPartId); + updateVisibilty(functionTestFilePath, variableTestFilePath); + + updateVisibilty(variableTestFilePath, Utf8String()); + + ASSERT_FALSE(functionTranslationUnit.isUsedByCurrentEditor()); + ASSERT_FALSE(functionTranslationUnit.isVisibleInEditor()); + ASSERT_TRUE(variableTranslationUnit.isUsedByCurrentEditor()); + ASSERT_TRUE(variableTranslationUnit.isVisibleInEditor()); +} + +void ClangIpcServer::SetUp() +{ + clangServer.addClient(&mockIpcClient); + registerProjectPart(); + registerFiles(); +} + +void ClangIpcServer::registerFiles() +{ + RegisterTranslationUnitForEditorMessage message({FileContainer(functionTestFilePath, projectPartId, unsavedContent(unsavedTestFilePath), true), + FileContainer(variableTestFilePath, projectPartId)}); + + clangServer.registerTranslationUnitsForEditor(message); +} + +void ClangIpcServer::registerProjectPart() +{ + RegisterProjectPartsForEditorMessage message({ProjectPartContainer(projectPartId)}); + + clangServer.registerProjectPartsForEditor(message); +} + +void ClangIpcServer::changeProjectPartArguments() +{ + RegisterProjectPartsForEditorMessage message({ProjectPartContainer(projectPartId, {Utf8StringLiteral("-DArgumentDefinition")})}); + + clangServer.registerProjectPartsForEditor(message); +} + +void ClangIpcServer::changeProjectPartArgumentsToWrongValues() +{ + RegisterProjectPartsForEditorMessage message({ProjectPartContainer(projectPartId, {Utf8StringLiteral("-blah")})}); + + clangServer.registerProjectPartsForEditor(message); +} + +void ClangIpcServer::updateVisibilty(const Utf8String ¤tEditor, const Utf8String &additionalVisibleEditor) +{ + UpdateVisibleTranslationUnitsMessage message(currentEditor, + {currentEditor, additionalVisibleEditor}); + + clangServer.updateVisibleTranslationUnits(message); +} + +const Utf8String ClangIpcServer::unsavedContent(const QString &unsavedFilePath) +{ + QFile unsavedFileContentFile(unsavedFilePath); + bool isOpen = unsavedFileContentFile.open(QIODevice::ReadOnly | QIODevice::Text); + if (!isOpen) + ADD_FAILURE() << "File with the unsaved content cannot be opened!"; + + return Utf8String::fromByteArray(unsavedFileContentFile.readAll()); +} + TEST_F(ClangIpcServer, TranslationUnitAfterUpdateNeedsReparseAndHasNewDiagnostics) { const auto fileContainer = FileContainer(functionTestFilePath, projectPartId,unsavedContent(unsavedTestFilePath), true, 1); diff --git a/tests/unit/unittest/clientserverinprocesstest.cpp b/tests/unit/unittest/clientserverinprocesstest.cpp index 87632e2c069..0b5bb27d114 100644 --- a/tests/unit/unittest/clientserverinprocesstest.cpp +++ b/tests/unit/unittest/clientserverinprocesstest.cpp @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -232,6 +233,19 @@ TEST_F(ClientServerInProcess, SendUnregisterProjectPartsForEditorMessage) scheduleServerMessages(); } +TEST_F(ClientServerInProcess, UpdateVisibleTranslationUnitsMessage) +{ + ClangBackEnd::UpdateVisibleTranslationUnitsMessage message(Utf8StringLiteral(TESTDATA_DIR"/fileone.cpp"), + {Utf8StringLiteral(TESTDATA_DIR"/fileone.cpp"), + Utf8StringLiteral(TESTDATA_DIR"/filetwo.cpp")}); + + EXPECT_CALL(mockIpcServer, updateVisibleTranslationUnits(message)) + .Times(1); + + serverProxy.updateVisibleTranslationUnits(message); + scheduleServerMessages(); +} + TEST_F(ClientServerInProcess, SendTranslationUnitDoesNotExistMessage) { ClangBackEnd::TranslationUnitDoesNotExistMessage message(fileContainer); diff --git a/tests/unit/unittest/mockipcserver.h b/tests/unit/unittest/mockipcserver.h index 31591c28c0d..83f9870b4d6 100644 --- a/tests/unit/unittest/mockipcserver.h +++ b/tests/unit/unittest/mockipcserver.h @@ -60,6 +60,8 @@ public: void(const ClangBackEnd::CompleteCodeMessage &message)); MOCK_METHOD1(requestDiagnostics, void(const ClangBackEnd::RequestDiagnosticsMessage &message)); + MOCK_METHOD1(updateVisibleTranslationUnits, + void(const ClangBackEnd::UpdateVisibleTranslationUnitsMessage &message)); }; #endif // MOCKIPCSERVER_H From 1f4af6a77880b996307b17cab05004830a11c12c Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Tue, 24 Nov 2015 12:18:35 +0100 Subject: [PATCH 12/15] Utils: Specify LIBS in utils-lib.pri ...so that unittest.pro compiles on MSVC2013 without duplicating the LIBS line. Change-Id: I2a4f9cab65620ea28692d17352e92ababc47e4fd Reviewed-by: Eike Ziller --- src/libs/utils/utils-lib.pri | 4 ++++ src/libs/utils/utils.pro | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri index 9c5be39c030..cf45860794f 100644 --- a/src/libs/utils/utils-lib.pri +++ b/src/libs/utils/utils-lib.pri @@ -8,6 +8,10 @@ QT += gui network qml CONFIG += exceptions # used by portlist.cpp, textfileformat.cpp, and ssh/* +win32: LIBS += -luser32 -lshell32 +# PortsGatherer +win32: LIBS += -liphlpapi -lws2_32 + SOURCES += $$PWD/environment.cpp \ $$PWD/environmentmodel.cpp \ $$PWD/qtcprocess.cpp \ diff --git a/src/libs/utils/utils.pro b/src/libs/utils/utils.pro index 83d61eac6df..b3f2f208928 100644 --- a/src/libs/utils/utils.pro +++ b/src/libs/utils/utils.pro @@ -1,8 +1,4 @@ include(../../qtcreatorlibrary.pri) include(utils-lib.pri) -win32: LIBS += -luser32 -lshell32 -# PortsGatherer -win32: LIBS += -liphlpapi -lws2_32 - DEFINES += QTC_REL_TOOLS_PATH=$$shell_quote(\"$$relative_path($$IDE_LIBEXEC_PATH, $$IDE_BIN_PATH)\") From f710ec8ce2f37a20db77aa40da1121b7a504254a Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 26 Nov 2015 09:37:39 +0100 Subject: [PATCH 13/15] More change log Change-Id: Ie8ee846e038ff926c4a0ff27dc4e7be61a05b2d6 Reviewed-by: Leena Miettinen --- dist/changes-3.6.0.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dist/changes-3.6.0.md b/dist/changes-3.6.0.md index 98dfebadf27..5644a917117 100644 --- a/dist/changes-3.6.0.md +++ b/dist/changes-3.6.0.md @@ -21,6 +21,10 @@ Editing * Fixed that Qt Creator tried to write auto-save files in read-only directories * Fixed possible crash with code completion (QTCREATORBUG-14875) +* Fixed that closing session was leaving invalid editor windows open + (QTCREATORBUG-15193) +* Fixed that editors were closing even when closing Qt Creator was cancelled + (QTCREATORBUG-14401) Project Management @@ -29,6 +33,10 @@ Project Management (QTCREATORBUG-14606) * Added option to synchronize kits between all projects in a session (QTCREATORBUG-5823) +* Fixed that `%{CurrentBuild:Type}` was not expanded correctly + (QTCREATORBUG-15178) +* Fixed that `Stop applications before building` also stopped applications + when deploying (QTCREATORBUG-15281) QMake Projects @@ -39,6 +47,8 @@ QMake Projects * Fixed that `QMAKE_EXT_H` was ignored for UI code model (QTCREATORBUG-14910) * Fixed that `make` build step was not updated on environment changes (QTCREATORBUG-14831) +* Fixed adding files to `.qrc` files through the project tree + (QTCREATORBUG-15277) CMake Projects @@ -50,9 +60,13 @@ CMake Projects C++ Support * Added support for `noexcept` +* Fixed crash with function arguments hint (QTCREATORBUG-15275) +* Fixed that object instantiation was sometimes highlighted as function call + (QTCREATORBUG-15212) * Clang code model * Added more diagnostic messages to editors * Added Clang's Fix-its to refactoring actions (QTCREATORBUG-14868) + * Added option for additional command line arguments Debugging @@ -73,6 +87,7 @@ Analyzer QML Profiler * Improved performance of timeline view (QTCREATORBUG-14983) +* Fixed offset when dragging timeline categories (QTCREATORBUG-15333) Qt Quick Designer @@ -114,6 +129,7 @@ Android (QTCREATORBUG-14832) * Fixed deployment on devices without `readlink` (QTCREATORBUG-15006) * Fixed debugging of signed applications (requires Qt 5.6) (QTCREATORBUG-13035) +* Fixed that building failed if Java is not in `PATH` (QTCREATORBUG-15382) iOS @@ -124,6 +140,7 @@ Remote Linux * Added support for ECDSA public keys with 384 and 521 bits, ECDSA user keys, and ECDSA key creation * Fixed environment and working directory for Valgrind analyzer +* Fixed attaching to remote debugging server (QTCREATORBUG-15210) Credits for these changes go to: Aleix Pol From e3c16259ed5297a3ee707d0aeade985ae103992e Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 20 Nov 2015 15:56:26 +0100 Subject: [PATCH 14/15] QmlProfiler: When showing connection error, cancel any connects The device can exist without being open, which makes the disconnect() when the message box finishes ineffective. Also, disconnect() merely trashes the signals and slots, but doesn't remove the device. Task-number: QTCREATORBUG-15383 Change-Id: I8eb8ca3db496c9841156c0949c3e3bfd92329056 Reviewed-by: Christian Stenger --- src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp b/src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp index 04f2ac0eb62..a355955f5bd 100644 --- a/src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp @@ -245,6 +245,8 @@ void QmlProfilerClientManager::tryToConnect() } else if (d->connectionAttempts == 50) { d->connectionTimer.stop(); d->connectionAttempts = 0; + delete d->connection; // delete directly. + d->connection = 0; QMessageBox *infoBox = QmlProfilerTool::requestMessageBox(); infoBox->setIcon(QMessageBox::Critical); @@ -300,14 +302,11 @@ void QmlProfilerClientManager::logState(const QString &msg) void QmlProfilerClientManager::retryMessageBoxFinished(int result) { - if (d->connection) { - QTC_ASSERT(!d->connection->isOpen(), return); - if (d->connection->isConnecting()) - d->connection->disconnect(); - } + QTC_ASSERT(!d->connection, disconnectClient()); switch (result) { case QMessageBox::Retry: { + connectClient(d->tcpPort); d->connectionAttempts = 0; d->connectionTimer.start(); break; From 35ed93fe2d8fbc2d5b2531edb4f3b32be55457ce Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 23 Nov 2015 10:16:47 +0100 Subject: [PATCH 15/15] QmlProfiler: replace TCP connections after 200ms of failing to connect Sometimes it takes very long to establish a TCP connection to the debug server. If the connection hasn't been established after 200ms we probably don't want to wait for it any longer. If, however, the TCP connection is there and the "hello" hasn't arrived yet, we keep the connection in order not to trigger an unexpected state in the application. Change-Id: I1a64493fefc759f526cdebff434a2557077f9246 Task-number: QTCREATORBUG-15383 Reviewed-by: Christian Stenger --- src/libs/qmldebug/qmldebugclient.cpp | 9 +++++++++ src/libs/qmldebug/qmldebugclient.h | 1 + src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp | 11 +++++++++++ 3 files changed, 21 insertions(+) diff --git a/src/libs/qmldebug/qmldebugclient.cpp b/src/libs/qmldebug/qmldebugclient.cpp index 2f5b7976cd7..126830ba13f 100644 --- a/src/libs/qmldebug/qmldebugclient.cpp +++ b/src/libs/qmldebug/qmldebugclient.cpp @@ -334,6 +334,15 @@ void QmlDebugConnection::connectToHost(const QString &hostName, quint16 port) socket->connectToHost(hostName, port); } +QAbstractSocket::SocketState QmlDebugConnection::socketState() const +{ + // TODO: when merging into master, add clause for local socket + if (QAbstractSocket *socket = qobject_cast(d->device)) + return socket->state(); + else + return QAbstractSocket::UnconnectedState; +} + // QmlDebugClientPrivate::QmlDebugClientPrivate() diff --git a/src/libs/qmldebug/qmldebugclient.h b/src/libs/qmldebug/qmldebugclient.h index 01c871ba09c..fdee2f290e9 100644 --- a/src/libs/qmldebug/qmldebugclient.h +++ b/src/libs/qmldebug/qmldebugclient.h @@ -55,6 +55,7 @@ public: ~QmlDebugConnection(); void connectToHost(const QString &hostName, quint16 port); + QAbstractSocket::SocketState socketState() const; bool isOpen() const; bool isConnecting() const; diff --git a/src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp b/src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp index a355955f5bd..753a389d33c 100644 --- a/src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp @@ -242,6 +242,17 @@ void QmlProfilerClientManager::tryToConnect() if (d->connection && d->connection->isOpen()) { d->connectionTimer.stop(); d->connectionAttempts = 0; + } else if (d->connection && + d->connection->socketState() != QAbstractSocket::ConnectedState) { + // Replace the connection after trying for some time. On some operating systems (OSX) the + // very first connection to a TCP server takes a very long time to get established. + + // delete directly here, so that any pending events aren't delivered. We don't want the + // connection first to be established and then torn down again. + delete d->connection; + d->connection = 0; + connectClient(d->tcpPort); + connectToClient(); } else if (d->connectionAttempts == 50) { d->connectionTimer.stop(); d->connectionAttempts = 0;