From fef76f0284c0455ec9cc43e148a68ccf2cc46357 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 25 Aug 2016 13:42:55 +0200 Subject: [PATCH 01/21] Fix that opening advanced search could make output pane smaller Height is set to 0 when the pane is hidden, so we have to check the nonMaximizedSize instead (and only if the pane is not maximized already. Task-number: QTCREATORBUG-15986 Change-Id: Ic2a08c300a7e311b59c4597d8043041f68a4c1ff Reviewed-by: Tobias Hunger --- src/plugins/coreplugin/outputpane.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/outputpane.cpp b/src/plugins/coreplugin/outputpane.cpp index eef0312aeae..b0f5c195bce 100644 --- a/src/plugins/coreplugin/outputpane.cpp +++ b/src/plugins/coreplugin/outputpane.cpp @@ -177,7 +177,7 @@ void OutputPanePlaceHolder::ensureSizeHintAsMinimum() Internal::OutputPaneManager *om = Internal::OutputPaneManager::instance(); int minimum = (d->m_splitter->orientation() == Qt::Vertical ? om->sizeHint().height() : om->sizeHint().width()); - if (height() < minimum) + if (nonMaximizedSize() < minimum && !d->m_isMaximized) setHeight(minimum); } From 15ecdd1e238d7932a83333c369f2ad61148f2f5f Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 25 Aug 2016 09:17:05 +0200 Subject: [PATCH 02/21] Editor: Close proposal widget when text is pasted Already worked with the shortcut defined in the settings, but not with the standard shortcuts defined by QKeySequence. Task-number: QTCREATORBUG-16586 Change-Id: I4dc02e29ee5d273c3bfc9de28f52e90cffc2397c Reviewed-by: Eike Ziller --- src/plugins/texteditor/codeassist/genericproposalwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/texteditor/codeassist/genericproposalwidget.cpp b/src/plugins/texteditor/codeassist/genericproposalwidget.cpp index 4a1e1eff671..5e3a466aaf5 100644 --- a/src/plugins/texteditor/codeassist/genericproposalwidget.cpp +++ b/src/plugins/texteditor/codeassist/genericproposalwidget.cpp @@ -621,7 +621,7 @@ bool GenericProposalWidget::eventFilter(QObject *o, QEvent *e) default: // Only forward keys that insert text and refine the completion. - if (ke->text().isEmpty()) + if (ke->text().isEmpty() && !(ke == QKeySequence::Paste)) return true; break; } From 149f084b1184a780e781864a423d4b72e144436d Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 25 Aug 2016 09:40:55 +0200 Subject: [PATCH 03/21] Editor: Use correct pointer in guard Task-number: QTCREATORBUG-16253 Change-Id: Ie046af69c37784c1a42cc693971b42baaef2f6ff Reviewed-by: Eike Ziller --- src/plugins/texteditor/textmark.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/texteditor/textmark.cpp b/src/plugins/texteditor/textmark.cpp index 26f16b1b390..fa0b1f0cb5c 100644 --- a/src/plugins/texteditor/textmark.cpp +++ b/src/plugins/texteditor/textmark.cpp @@ -275,7 +275,7 @@ void TextMarkRegistry::documentRenamed(IDocument *document, const QString &oldName, const QString &newName) { TextDocument *baseTextDocument = qobject_cast(document); - if (!document) + if (!baseTextDocument) return; FileName oldFileName = FileName::fromString(oldName); FileName newFileName = FileName::fromString(newName); From 07706a9a8e375432c650ba04c3ad64b052470cfb Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 19 Aug 2016 08:28:24 +0200 Subject: [PATCH 04/21] BinEditor: Do not call openImpl without a file name Task-number: QTCREATORBUG-16751 Change-Id: I64133932b405707f4d7e1e2213e1ddf73cbcc387 Reviewed-by: hjk --- src/plugins/bineditor/bineditorplugin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/bineditor/bineditorplugin.cpp b/src/plugins/bineditor/bineditorplugin.cpp index 6f5f75dfc25..980e781a510 100644 --- a/src/plugins/bineditor/bineditorplugin.cpp +++ b/src/plugins/bineditor/bineditorplugin.cpp @@ -340,7 +340,8 @@ public: void provideNewRange(quint64 offset) { - openImpl(0, filePath().toString(), offset); + if (filePath().exists()) + openImpl(0, filePath().toString(), offset); } public: From 481f0830694b5a8f797fbbcfbdf466a85e86e1ab Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 18 Aug 2016 15:40:52 +0200 Subject: [PATCH 05/21] Dumper: Fix value of not callable pseudo member Task-number: QTCREATORBUG-8124 Change-Id: I86ab891f18d9a0cc58217711637c8587cd42bb07 Reviewed-by: hjk --- share/qtcreator/debugger/qttypes.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/debugger/qttypes.py b/share/qtcreator/debugger/qttypes.py index f0bc8ccc37d..300fda0245a 100644 --- a/share/qtcreator/debugger/qttypes.py +++ b/share/qtcreator/debugger/qttypes.py @@ -508,9 +508,16 @@ def qdump__QFileInfo(d, value): d.putCallItem("ownerid", value, "ownerId") #QFile::Permissions permissions () const - perms = d.call(value, "permissions") + try: + perms = d.call(value, "permissions") + except: + perms = None + if perms is None: - d.putValue("") + with SubItem(d, "permissions"): + d.putSpecialValue("notcallable") + d.putType(ns + "QFile::Permissions") + d.putNumChild(0) else: with SubItem(d, "permissions"): d.putEmptyValue() From a8039d9ce2fcb59c42eeb4a676faf0263a8ccbe2 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Fri, 8 Jul 2016 12:07:53 +0200 Subject: [PATCH 06/21] ClangStaticAnalyzer: Simplify testing various kits The already available ClangStaticAnalyzerUnitTests uses the automatically set up "Desktop" kit to run the analyzer. This is fine for tests that are run in the build environment of Qt Creator. However, testing different kits on the same machine means to build Qt Creator itself with those kits, which is not practical. The new ClangStaticAnalyzerSessionTests will open the predefined session "ClangStaticAnalyzerPreconfiguredSession" and for each project and each target it will run the analyzer. If there is no such session, the test will be skipped. To manually preconfigure the desired session: 1. ./qtcreator -settingspath /custom/path 2. Set up the desired kits. 3. Create a session with the name ClangStaticAnalyzerPreconfiguredSession and load the desired test projects. To run the test: ./qtcreator -settingspath /custom/path -test ClangStaticAnalyzer,testPreconfiguredSession Change-Id: I0f027353854088d3acf8acecc16c74e9f0516e7d Reviewed-by: Christian Kandeler --- .../clangstaticanalyzer.pro | 10 +- .../clangstaticanalyzer.qbs | 2 + .../clangstaticanalyzerplugin.cpp | 2 + ...taticanalyzerpreconfiguredsessiontests.cpp | 214 ++++++++++++++++++ ...gstaticanalyzerpreconfiguredsessiontests.h | 64 ++++++ 5 files changed, 290 insertions(+), 2 deletions(-) create mode 100644 src/plugins/clangstaticanalyzer/clangstaticanalyzerpreconfiguredsessiontests.cpp create mode 100644 src/plugins/clangstaticanalyzer/clangstaticanalyzerpreconfiguredsessiontests.h diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzer.pro b/src/plugins/clangstaticanalyzer/clangstaticanalyzer.pro index 0f8016f437d..4450072a70d 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzer.pro +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzer.pro @@ -41,8 +41,14 @@ FORMS += \ clangstaticanalyzerprojectsettingswidget.ui equals(TEST, 1) { - HEADERS += clangstaticanalyzerunittests.h - SOURCES += clangstaticanalyzerunittests.cpp + HEADERS += \ + clangstaticanalyzerpreconfiguredsessiontests.h \ + clangstaticanalyzerunittests.h + + SOURCES += \ + clangstaticanalyzerpreconfiguredsessiontests.cpp \ + clangstaticanalyzerunittests.cpp + RESOURCES += clangstaticanalyzerunittests.qrc } diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs b/src/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs index b4a9258e72d..34d1fd2f773 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs @@ -59,6 +59,8 @@ QtcPlugin { name: "Unit tests" condition: qtc.testsEnabled files: [ + "clangstaticanalyzerpreconfiguredsessiontests.cpp", + "clangstaticanalyzerpreconfiguredsessiontests.h", "clangstaticanalyzerunittests.cpp", "clangstaticanalyzerunittests.h", "clangstaticanalyzerunittests.qrc", diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp index 7c40c91a0aa..17faed3682a 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp @@ -32,6 +32,7 @@ #include "clangstaticanalyzertool.h" #ifdef WITH_TESTS +#include "clangstaticanalyzerpreconfiguredsessiontests.h" #include "clangstaticanalyzerunittests.h" #endif @@ -148,6 +149,7 @@ QList ClangStaticAnalyzerPlugin::createTestObjects() const { QList tests; #ifdef WITH_TESTS + tests << new ClangStaticAnalyzerPreconfiguredSessionTests(m_analyzerTool); tests << new ClangStaticAnalyzerUnitTests(m_analyzerTool); #endif return tests; diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerpreconfiguredsessiontests.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerpreconfiguredsessiontests.cpp new file mode 100644 index 00000000000..202e33b1d0d --- /dev/null +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerpreconfiguredsessiontests.cpp @@ -0,0 +1,214 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "clangstaticanalyzerpreconfiguredsessiontests.h" + +#include "clangstaticanalyzerdiagnostic.h" +#include "clangstaticanalyzertool.h" +#include "clangstaticanalyzerutils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +using namespace CppTools; +using namespace ProjectExplorer; + +static bool processEventsUntil(const std::function condition, int timeOutInMs = 30000) +{ + QTime t; + t.start(); + + forever { + if (t.elapsed() > timeOutInMs) + return false; + + if (condition()) + return true; + + QCoreApplication::processEvents(); + } +} + +namespace ClangStaticAnalyzer { +namespace Internal { + +ClangStaticAnalyzerPreconfiguredSessionTests::ClangStaticAnalyzerPreconfiguredSessionTests( + ClangStaticAnalyzerTool *analyzerTool, + QObject *parent) + : QObject(parent) + , m_sessionManager(*ProjectExplorer::SessionManager::instance()) + , m_analyzerTool(*analyzerTool) +{ +} + +void ClangStaticAnalyzerPreconfiguredSessionTests::initTestCase() +{ + const QString preconfiguredSessionName = QLatin1String("ClangStaticAnalyzerPreconfiguredSession"); + if (!m_sessionManager.sessions().contains(preconfiguredSessionName)) + QSKIP("Manually preconfigured session 'ClangStaticAnalyzerPreconfiguredSession' needed."); + + // Load session + if (m_sessionManager.activeSession() != preconfiguredSessionName) + QVERIFY(m_sessionManager.loadSession(preconfiguredSessionName)); + + // Wait until all projects are loaded. + const int sessionManagerProjects = m_sessionManager.projects().size(); + const auto allProjectsLoaded = [sessionManagerProjects]() { + return CppModelManager::instance()->projectInfos().size() == sessionManagerProjects; + }; + QVERIFY(processEventsUntil(allProjectsLoaded)); +} + +void ClangStaticAnalyzerPreconfiguredSessionTests::testPreconfiguredSession() +{ + QFETCH(Project *, project); + QFETCH(Target *, target); + + QVERIFY(switchToProjectAndTarget(project, target)); + + m_analyzerTool.startTool(); + QSignalSpy waitUntilAnalyzerFinished(&m_analyzerTool, SIGNAL(finished(bool))); + QVERIFY(waitUntilAnalyzerFinished.wait(30000)); + const QList arguments = waitUntilAnalyzerFinished.takeFirst(); + QVERIFY(arguments.first().toBool()); + QCOMPARE(m_analyzerTool.diagnostics().count(), 0); +} + +static QList validProjects(const QList projectsOfSession) +{ + QList sortedProjects = projectsOfSession; + Utils::sort(sortedProjects, [](Project *lhs, Project *rhs){ + return lhs->displayName() < rhs->displayName(); + }); + + const auto isValidProject = [](Project *project) { + const QList targets = project->targets(); + if (targets.isEmpty()) { + qWarning("Skipping project \"%s\" since it has no targets.", + qPrintable(project->projectFilePath().fileName())); + } + return !targets.isEmpty(); + }; + + return Utils::filtered(sortedProjects, isValidProject); +} + +static QList validTargets(Project *project) +{ + QList sortedTargets = project->targets(); + Utils::sort(sortedTargets, [](Target *lhs, Target *rhs){ + return lhs->displayName() < rhs->displayName(); + }); + + const QString projectFileName = project->projectFilePath().fileName(); + const auto isValidTarget = [projectFileName](Target *target) { + Kit *kit = target->kit(); + if (!kit || !kit->isValid()) { + qWarning("Project \"%s\": Skipping target \"%s\" since it has no (valid) kits.", + qPrintable(projectFileName), + qPrintable(target->displayName())); + return false; + } + + const ToolChain * const toolchain = ToolChainKitInformation::toolChain(kit); + QTC_ASSERT(toolchain, return false); + bool hasClangExecutable; + clangExecutableFromSettings(toolchain->typeId(), &hasClangExecutable); + if (!hasClangExecutable) { + qWarning("Project \"%s\": Skipping target \"%s\" since no suitable clang was found for the toolchain.", + qPrintable(projectFileName), + qPrintable(target->displayName())); + return false; + } + + return true; + }; + + return Utils::filtered(sortedTargets, isValidTarget); +} + +static QByteArray dataTagName(Project *project, Target *target) +{ + const QString projectFileName = project->projectFilePath().fileName(); + const QString dataTagAsString = projectFileName + " -- " + target->displayName(); + return dataTagAsString.toUtf8(); +} + +void ClangStaticAnalyzerPreconfiguredSessionTests::testPreconfiguredSession_data() +{ + QTest::addColumn("project"); + QTest::addColumn("target"); + + bool hasAddedTestData = false; + + foreach (Project *project, validProjects(m_sessionManager.projects())) { + foreach (Target *target, validTargets(project)) { + hasAddedTestData = true; + QTest::newRow(dataTagName(project, target)) << project << target; + } + } + + if (!hasAddedTestData) + QSKIP("Session has no valid projects/targets to test."); +} + +bool ClangStaticAnalyzerPreconfiguredSessionTests::switchToProjectAndTarget(Project *project, + Target *target) +{ + Project * const activeProject = m_sessionManager.startupProject(); + if (project == activeProject && target == activeProject->activeTarget()) + return true; // OK, desired project/target already active. + + QSignalSpy waitUntilProjectUpdated(CppModelManager::instance(), + &CppModelManager::projectPartsUpdated); + + m_sessionManager.setActiveTarget(project, target, ProjectExplorer::SetActive::Cascade); + + const bool waitResult = waitUntilProjectUpdated.wait(30000); + if (!waitResult) { + qWarning() << "waitUntilProjectUpdated() failed"; + return false; + } + + return true; +} + +} // namespace Internal +} // namespace ClangStaticAnalyzerPlugin diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerpreconfiguredsessiontests.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerpreconfiguredsessiontests.h new file mode 100644 index 00000000000..786b6dd0d2c --- /dev/null +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerpreconfiguredsessiontests.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include +#include + +namespace ProjectExplorer { +class Project; +class Target; +class SessionManager; +} + +namespace ClangStaticAnalyzer { +namespace Internal { +class ClangStaticAnalyzerTool; + +class ClangStaticAnalyzerPreconfiguredSessionTests: public QObject +{ + Q_OBJECT + +public: + ClangStaticAnalyzerPreconfiguredSessionTests(ClangStaticAnalyzerTool *analyzerTool, + QObject *parent = 0); + +private slots: + void initTestCase(); + + void testPreconfiguredSession(); + void testPreconfiguredSession_data(); + +private: + bool switchToProjectAndTarget(ProjectExplorer::Project *project, + ProjectExplorer::Target *target); + + ProjectExplorer::SessionManager &m_sessionManager; + ClangStaticAnalyzerTool &m_analyzerTool; +}; + +} // namespace Internal +} // namespace ClangStaticAnalyzerPlugin From 19a9eac46ee88c7ea903b545995b73f035f30d9a Mon Sep 17 00:00:00 2001 From: Marco Benelli Date: Wed, 13 Jul 2016 16:38:36 +0200 Subject: [PATCH 07/21] QmlJs: circular dependencies handling Task-number: QTCREATORBUG-16585 Change-Id: Ia1e01f1314cd4022d59dc768752baaa367fe250a Reviewed-by: Robert Loehning Reviewed-by: Erik Verbruggen --- src/libs/qmljs/qmljsplugindumper.cpp | 12 ++++++++++-- src/libs/qmljs/qmljsplugindumper.h | 3 ++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/libs/qmljs/qmljsplugindumper.cpp b/src/libs/qmljs/qmljsplugindumper.cpp index 7d13482272b..8ef89ebb431 100644 --- a/src/libs/qmljs/qmljsplugindumper.cpp +++ b/src/libs/qmljs/qmljsplugindumper.cpp @@ -458,19 +458,27 @@ QString PluginDumper::buildQmltypesPath(const QString &name) const void PluginDumper::loadDependencies(const QStringList &dependencies, QStringList &errors, QStringList &warnings, - QList &objects) const + QList &objects, + QSet *visited) const { + if (dependencies.isEmpty()) + return; + + QScopedPointer> visitedPtr(visited ? visited : new QSet()); + QStringList dependenciesPaths; QString path; for (const QString &name: dependencies) { path = buildQmltypesPath(name); if (!path.isNull()) dependenciesPaths << path; + visitedPtr->insert(name); } QStringList newDependencies; loadQmlTypeDescription(dependenciesPaths, errors, warnings, objects, 0, &newDependencies); + newDependencies = (newDependencies.toSet() - *visitedPtr).toList(); if (!newDependencies.isEmpty()) - loadDependencies(newDependencies, errors, warnings, objects); + loadDependencies(newDependencies, errors, warnings, objects, visitedPtr.take()); } void PluginDumper::loadQmltypesFile(const QStringList &qmltypesFilePaths, diff --git a/src/libs/qmljs/qmljsplugindumper.h b/src/libs/qmljs/qmljsplugindumper.h index 7d29e6ef3db..586275f021a 100644 --- a/src/libs/qmljs/qmljsplugindumper.h +++ b/src/libs/qmljs/qmljsplugindumper.h @@ -83,7 +83,8 @@ private: void loadDependencies(const QStringList &dependencies, QStringList &errors, QStringList &warnings, - QList &objects) const; + QList &objects, + QSet *visited=0) const; void loadQmltypesFile(const QStringList &qmltypesFilePaths, const QString &libraryPath, QmlJS::LibraryInfo libraryInfo); From 00a8573502b46d29a0fd1c3ad3e2ad0d6187bf81 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 22 Aug 2016 13:45:15 +0200 Subject: [PATCH 08/21] Debugger: Fix use of GDB's own pretty printers ... with newer versions of GDB. Looks like their internal behavior changed (again...) Task-number: QTCREATORBUG-16758 Change-Id: Ic3a092091bac73df92a3a9f33ab863e4b6ece9b4 Reviewed-by: David Schulz Reviewed-by: hjk --- share/qtcreator/debugger/gdbbridge.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py index eb8469bf5a9..f7f32809f93 100644 --- a/share/qtcreator/debugger/gdbbridge.py +++ b/share/qtcreator/debugger/gdbbridge.py @@ -168,7 +168,10 @@ class PlainDumper: self.typeCache = {} def __call__(self, d, value): - printer = self.printer.gen_printer(value) + try: + printer = self.printer.gen_printer(value) + except: + printer = self.printer.invoke(value) lister = getattr(printer, "children", None) children = [] if lister is None else list(lister()) d.putType(self.printer.name) From 1ca42e24cba68022bbde5c93da84778dd053cdfa Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Thu, 25 Aug 2016 15:46:50 +0300 Subject: [PATCH 09/21] Android: Make avd name extraction even more robust The console output changed even more and now it add one more "OK", in order to get the right avd name we should stop searching at last "OK". Task-number: QTCREATORBUG-16783 Change-Id: I2b69763bba740b739e3573fdfae6b6ac9ed16e95 Reviewed-by: Tobias Hunger Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/plugins/android/androidconfigurations.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index ea0b88a6271..b7b17fa59d7 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -922,8 +922,10 @@ QString AndroidConfig::getAvdName(const QString &serialnumber) // The input "avd name" might not be echoed as-is, but contain ASCII // control sequences. for (int i = response.size() - 1; i > 1; --i) { - if (response.at(i).startsWith("OK")) + if (response.at(i).startsWith("OK")) { name = response.at(i - 1); + break; + } } return QString::fromLatin1(name).trimmed(); } From 06b2ff604a569e82cc28a46c3748dc73db436055 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 25 Aug 2016 15:47:32 +0200 Subject: [PATCH 10/21] QmlProfiler: Move output parser into LocalQmlProfilerRunner In the general case we don't want the QmlProfilerRunControl to parse the QML debug port from the application output. As for most platforms the ports are mapped via some remote connection mechanism the parsed port is almost certainly wrong. In the case of local connections, however, the port is actually correct, so we keep the output parser in the LocalQmlProfilerRunner. Change-Id: Ifdaae85196d8b034e67bc2ba0b8c05be980b62e5 Reviewed-by: Christian Kandeler Reviewed-by: hjk Reviewed-by: Ulf Hermann --- .../debugger/analyzer/analyzerruncontrol.h | 1 + .../qmlprofiler/localqmlprofilerrunner.cpp | 29 ++++++++++++++++++ .../qmlprofiler/localqmlprofilerrunner.h | 2 ++ .../qmlprofiler/qmlprofilerruncontrol.cpp | 30 +++---------------- .../qmlprofiler/qmlprofilerruncontrol.h | 4 +-- 5 files changed, 37 insertions(+), 29 deletions(-) diff --git a/src/plugins/debugger/analyzer/analyzerruncontrol.h b/src/plugins/debugger/analyzer/analyzerruncontrol.h index 97ce85e69a9..2fc47727dbd 100644 --- a/src/plugins/debugger/analyzer/analyzerruncontrol.h +++ b/src/plugins/debugger/analyzer/analyzerruncontrol.h @@ -47,6 +47,7 @@ public: AnalyzerRunControl(ProjectExplorer::RunConfiguration *runConfiguration, Core::Id runMode); virtual void notifyRemoteSetupDone(Utils::Port) {} + virtual void notifyRemoteSetupFailed(const QString &) {} virtual void notifyRemoteFinished() {} signals: diff --git a/src/plugins/qmlprofiler/localqmlprofilerrunner.cpp b/src/plugins/qmlprofiler/localqmlprofilerrunner.cpp index 3be605542ef..bffe0d23c80 100644 --- a/src/plugins/qmlprofiler/localqmlprofilerrunner.cpp +++ b/src/plugins/qmlprofiler/localqmlprofilerrunner.cpp @@ -79,6 +79,35 @@ LocalQmlProfilerRunner::LocalQmlProfilerRunner(const Configuration &configuratio this, &LocalQmlProfilerRunner::start); connect(runControl, &RunControl::finished, this, &LocalQmlProfilerRunner::stop); + + m_outputParser.setNoOutputText(ApplicationLauncher::msgWinCannotRetrieveDebuggingOutput()); + + connect(runControl, &Debugger::AnalyzerRunControl::appendMessageRequested, + this, [this](RunControl *runControl, const QString &msg, Utils::OutputFormat format) { + Q_UNUSED(runControl); + Q_UNUSED(format); + m_outputParser.processOutput(msg); + }); + + connect(&m_outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort, + runControl, [this, runControl](Utils::Port port) { + runControl->notifyRemoteSetupDone(port); + }); + + connect(&m_outputParser, &QmlDebug::QmlOutputParser::noOutputMessage, + runControl, [this, runControl]() { + runControl->notifyRemoteSetupDone(Utils::Port()); + }); + + connect(&m_outputParser, &QmlDebug::QmlOutputParser::connectingToSocketMessage, + runControl, [this, runControl]() { + runControl->notifyRemoteSetupDone(Utils::Port()); + }); + + connect(&m_outputParser, &QmlDebug::QmlOutputParser::errorMessage, + runControl, [this, runControl](const QString &message) { + runControl->notifyRemoteSetupFailed(message); + }); } void LocalQmlProfilerRunner::start() diff --git a/src/plugins/qmlprofiler/localqmlprofilerrunner.h b/src/plugins/qmlprofiler/localqmlprofilerrunner.h index 0122771b57b..bcbd996af89 100644 --- a/src/plugins/qmlprofiler/localqmlprofilerrunner.h +++ b/src/plugins/qmlprofiler/localqmlprofilerrunner.h @@ -30,6 +30,7 @@ #include #include #include +#include namespace Debugger { class AnalyzerRunControl; @@ -66,6 +67,7 @@ private: Configuration m_configuration; ProjectExplorer::ApplicationLauncher m_launcher; + QmlDebug::QmlOutputParser m_outputParser; }; } // namespace QmlProfiler diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp index 55a47e3f59d..224e5652cf7 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp @@ -70,7 +70,6 @@ public: Internal::QmlProfilerTool *m_tool = 0; QmlProfilerStateManager *m_profilerState = 0; QTimer m_noDebugOutputTimer; - QmlDebug::QmlOutputParser m_outputParser; bool m_running = false; }; @@ -90,18 +89,9 @@ QmlProfilerRunControl::QmlProfilerRunControl(RunConfiguration *runConfiguration, // (application output might be redirected / blocked) d->m_noDebugOutputTimer.setSingleShot(true); d->m_noDebugOutputTimer.setInterval(4000); - connect(&d->m_noDebugOutputTimer, &QTimer::timeout, - this, [this](){processIsRunning(Utils::Port());}); - - d->m_outputParser.setNoOutputText(ApplicationLauncher::msgWinCannotRetrieveDebuggingOutput()); - connect(&d->m_outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort, - this, &QmlProfilerRunControl::processIsRunning); - connect(&d->m_outputParser, &QmlDebug::QmlOutputParser::noOutputMessage, - this, [this](){processIsRunning(Utils::Port());}); - connect(&d->m_outputParser, &QmlDebug::QmlOutputParser::connectingToSocketMessage, - this, [this](){processIsRunning(Utils::Port());}); - connect(&d->m_outputParser, &QmlDebug::QmlOutputParser::errorMessage, - this, &QmlProfilerRunControl::wrongSetupMessageBox); + connect(&d->m_noDebugOutputTimer, &QTimer::timeout, this, [this]() { + notifyRemoteSetupDone(Utils::Port()); + }); } QmlProfilerRunControl::~QmlProfilerRunControl() @@ -203,13 +193,7 @@ void QmlProfilerRunControl::cancelProcess() emit finished(); } -void QmlProfilerRunControl::appendMessage(const QString &msg, Utils::OutputFormat format) -{ - AnalyzerRunControl::appendMessage(msg, format); - d->m_outputParser.processOutput(msg); -} - -void QmlProfilerRunControl::wrongSetupMessageBox(const QString &errorMessage) +void QmlProfilerRunControl::notifyRemoteSetupFailed(const QString &errorMessage) { QMessageBox *infoBox = new QMessageBox(ICore::mainWindow()); infoBox->setIcon(QMessageBox::Critical); @@ -242,12 +226,6 @@ void QmlProfilerRunControl::wrongSetupMessageBoxFinished(int button) } void QmlProfilerRunControl::notifyRemoteSetupDone(Utils::Port port) -{ - d->m_noDebugOutputTimer.stop(); - emit processRunning(port); -} - -void QmlProfilerRunControl::processIsRunning(Utils::Port port) { d->m_noDebugOutputTimer.stop(); diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.h b/src/plugins/qmlprofiler/qmlprofilerruncontrol.h index b1a1f121fea..49716c05a44 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.h +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.h @@ -46,21 +46,19 @@ public: void registerProfilerStateManager( QmlProfilerStateManager *profilerState ); void notifyRemoteSetupDone(Utils::Port port) override; + void notifyRemoteSetupFailed(const QString &errorMessage) override; void start() override; StopResult stop() override; bool isRunning() const override; void cancelProcess(); void notifyRemoteFinished() override; - void appendMessage(const QString &msg, Utils::OutputFormat format) override; bool supportsReRunning() const override { return false; } signals: void processRunning(Utils::Port port); private: - void wrongSetupMessageBox(const QString &errorMessage); void wrongSetupMessageBoxFinished(int); - void processIsRunning(Utils::Port port); void profilerStateChanged(); class QmlProfilerRunControlPrivate; From 3dc0598d836026dfffc0203b6e44d680b3df31e0 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 29 Aug 2016 11:15:44 +0200 Subject: [PATCH 11/21] Version bump Change-Id: I8fb6aa026c8f27908b789dbf909af223e8a66316 Reviewed-by: Eike Ziller --- qbs/modules/qtc/qtc.qbs | 2 +- qtcreator.pri | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/qbs/modules/qtc/qtc.qbs b/qbs/modules/qtc/qtc.qbs index 4910f75740e..f32de9d3802 100644 --- a/qbs/modules/qtc/qtc.qbs +++ b/qbs/modules/qtc/qtc.qbs @@ -5,7 +5,7 @@ import "qtc.js" as HelperFunctions Module { property string ide_version_major: '4' property string ide_version_minor: '1' - property string ide_version_release: '0' + property string ide_version_release: '1' property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.' + ide_version_release diff --git a/qtcreator.pri b/qtcreator.pri index 1a29b85aa56..10775a13fa9 100644 --- a/qtcreator.pri +++ b/qtcreator.pri @@ -1,7 +1,7 @@ !isEmpty(QTCREATOR_PRI_INCLUDED):error("qtcreator.pri already included") QTCREATOR_PRI_INCLUDED = 1 -QTCREATOR_VERSION = 4.1.0 +QTCREATOR_VERSION = 4.1.1 QTCREATOR_COMPAT_VERSION = 4.1.0 VERSION = $$QTCREATOR_VERSION BINARY_ARTIFACTS_BRANCH = 4.1 From d2a7fa00ebbb68f69b2e334a10aafca1c0cacfc3 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Mon, 29 Aug 2016 11:44:44 +0200 Subject: [PATCH 12/21] Qmake: Make makesteps work in DeployConfiguration again Task-number: QTCREATORBUG-16795 Change-Id: I0772114a82dfd7d41002dc91e3ae5702434b952d Reviewed-by: Eike Ziller --- src/plugins/qmakeprojectmanager/makestep.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/qmakeprojectmanager/makestep.cpp b/src/plugins/qmakeprojectmanager/makestep.cpp index 4a1e77e91ac..79f283cf6bd 100644 --- a/src/plugins/qmakeprojectmanager/makestep.cpp +++ b/src/plugins/qmakeprojectmanager/makestep.cpp @@ -113,6 +113,8 @@ QString MakeStep::effectiveMakeCommand() const QString makeCmd = m_makeCmd; if (makeCmd.isEmpty()) { QmakeBuildConfiguration *bc = qmakeBuildConfiguration(); + if (!bc) + bc = qobject_cast(target()->activeBuildConfiguration()); ToolChain *tc = ToolChainKitInformation::toolChain(target()->kit()); if (bc && tc) From 54b25996325e0eecf9368b2970e5e15788512931 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 29 Aug 2016 17:33:01 +0200 Subject: [PATCH 13/21] Update qbs submodule To HEAD of 1.6 branch Change-Id: I05311515c7ecd0e626bd525e170d34d4d0f2b43c Reviewed-by: Jake Petroules --- src/shared/qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/qbs b/src/shared/qbs index 60b28789ebb..f4b920daae0 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit 60b28789ebbab72ed9232643a8216264f7924ddf +Subproject commit f4b920daae0da57b0ef6df72738fdabbb8a88002 From 3b35d399105cb091084fb780872d91edfe1a564b Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Tue, 2 Aug 2016 14:50:54 +0200 Subject: [PATCH 14/21] Fix debugger to correctly interpret stdout availability behavior Previously if program execution was paused, and a c++ command was executed via executeDebuggerCommand method, which in turn printed to stdout, Qt Creator would assume that program execution has been resumed. But in reality the execution was still paused. Make sure not to report the program execution as being resumed, in case if something is printed to stdout as a result of a debugger command. Change-Id: I8752be00b1bf5bd4767debc2eb26b9a433f251bb Reviewed-by: hjk --- share/qtcreator/debugger/lldbbridge.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index afbff9099f8..7a20042c40b 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -231,6 +231,7 @@ class Dumper(DumperBase): self.report('lldbversion=\"%s\"' % lldb.SBDebugger.GetVersionString()) self.reportState("enginesetupok") + self.debuggerCommandInProgress = False def enterSubItem(self, item): if isinstance(item.name, lldb.SBValue): @@ -1335,10 +1336,12 @@ class Dumper(DumperBase): flavor = event.GetDataFlavor() state = lldb.SBProcess.GetStateFromEvent(event) bp = lldb.SBBreakpoint.GetBreakpointFromEvent(event) + skipEventReporting = self.debuggerCommandInProgress and (eventType == lldb.SBProcess.eBroadcastBitSTDOUT or eventType == lldb.SBProcess.eBroadcastBitSTDERR) self.report('event={type="%s",data="%s",msg="%s",flavor="%s",state="%s",bp="%s"}' % (eventType, out.GetData(), msg, flavor, self.stateName(state), bp)) if state != self.eventState: - self.eventState = state + if not skipEventReporting: + self.eventState = state if state == lldb.eStateExited: if self.isShuttingDown_: self.reportState("inferiorshutdownok") @@ -1381,7 +1384,8 @@ class Dumper(DumperBase): else: self.reportState("stopped") else: - self.reportState(self.stateName(state)) + if not skipEventReporting: + self.reportState(self.stateName(state)) if eventType == lldb.SBProcess.eBroadcastBitStateChanged: # 1 state = self.process.GetState() if state == lldb.eStateStopped: @@ -1683,6 +1687,7 @@ class Dumper(DumperBase): self.reportResult(self.hexencode(result.GetOutput()), {}) def executeDebuggerCommand(self, args): + self.debuggerCommandInProgress = True self.reportToken(args) result = lldb.SBCommandReturnObject() command = args['command'] @@ -1691,6 +1696,7 @@ class Dumper(DumperBase): output = result.GetOutput() error = str(result.GetError()) self.report('success="%d",output="%s",error="%s"' % (success, output, error)) + self.debuggerCommandInProgress = False def fetchDisassembler(self, args): functionName = args.get('function', '') From 365c1b7889e32685d5438d5102482b85323f20c6 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 29 Aug 2016 10:32:18 +0200 Subject: [PATCH 15/21] Fix empty locator results for search index Make sure that we do not cache incomplete result lists when the search is canceled (e.g. because the user typed another character). Task-number: QTCREATORBUG-16753 Change-Id: I5a8f7ab54bed236ccd318841d95a3a4aa4106df0 Reviewed-by: David Schulz --- src/plugins/help/helpindexfilter.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp index 8dcc4296598..a21dfb8caa8 100644 --- a/src/plugins/help/helpindexfilter.cpp +++ b/src/plugins/help/helpindexfilter.cpp @@ -87,6 +87,8 @@ QList HelpIndexFilter::matchesFor(QFutureInterface results; foreach (const QString &filePath, m_helpDatabases) { + if (future.isCanceled()) + return QList(); QSet result; QMetaObject::invokeMethod(this, "searchMatches", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QSet, result), @@ -111,7 +113,7 @@ QList HelpIndexFilter::matchesFor(QFutureInterface allresults; foreach (const QString &keyword, m_keywordCache) { if (future.isCanceled()) - break; + return QList(); if (keyword.startsWith(entry, cs)) { keywords.append(keyword); allresults.insert(keyword); From 1074b081764cd2b55182322914c3489cf385667d Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Mon, 29 Aug 2016 17:07:21 +0200 Subject: [PATCH 16/21] ModelEditor: Fix translations in templates Change-Id: I176bcc60d70609c9623000aaa9cceb33454ad2c5 Reviewed-by: Oswald Buddenhagen Reviewed-by: Jochen Becher Reviewed-by: Eike Ziller --- .../modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp index 387d4124a48..35e1c93a9b0 100644 --- a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp +++ b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp @@ -65,6 +65,7 @@ #include "qmt/style/style.h" #include "qmt/style/objectvisuals.h" +#include #include #include #include @@ -1364,7 +1365,7 @@ void PropertiesView::MView::setTitle(const QList &elements, else m_propertiesTitle = pluralTitle; } else { - m_propertiesTitle = tr("Multi-Selection"); + m_propertiesTitle = QCoreApplication::translate("qmt::PropertiesView::MView", "Multi-Selection"); } } @@ -1389,7 +1390,7 @@ void PropertiesView::MView::setTitle(const MItem *item, const QList &elemen m_propertiesTitle = pluralTitle; } } else { - m_propertiesTitle = tr("Multi-Selection"); + m_propertiesTitle = QCoreApplication::translate("qmt::PropertiesView::MView", "Multi-Selection"); } } } From 96a9b2bb5b6ecb66eade04115f58b0ee55921523 Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Mon, 22 Aug 2016 18:21:05 +0200 Subject: [PATCH 17/21] Squish: Strip final newline from expected text Change-Id: Icc10f3f0efad5a5d803f556037ecbc08fb6503f1 Reviewed-by: Christian Stenger --- tests/system/suite_tools/tst_codepasting/test.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/system/suite_tools/tst_codepasting/test.py b/tests/system/suite_tools/tst_codepasting/test.py index e05ebe2603a..5a5c16dfa53 100644 --- a/tests/system/suite_tools/tst_codepasting/test.py +++ b/tests/system/suite_tools/tst_codepasting/test.py @@ -58,7 +58,7 @@ def main(): description = "Description %s" % datetime.utcnow() type(waitForObject(":uiDescription_QLineEdit"), description) typeLines(pasteEditor, "// tst_codepasting %s" % datetime.utcnow()) - pastedText = pasteEditor.plainText + pastedText = str(pasteEditor.plainText) expiry = waitForObject(":Send to Codepaster.qt_spinbox_lineedit_QLineEdit") expiryDays = random.randint(1, 10) replaceEditorContent(expiry, "%d" % expiryDays) @@ -134,6 +134,8 @@ def main(): waitFor("not filenameCombo.currentText.isEmpty()", 20000) editor = waitForObject(":Qt Creator_CppEditor::Internal::CPPEditorWidget") test.compare(filenameCombo.currentText, "%s: %s" % (protocol, pasteId), "Verify title of editor") + if protocol == "Pastebin.Com" and pastedText.endswith("\n"): + pastedText = pastedText[:-1] test.compare(editor.plainText, pastedText, "Verify that pasted and fetched texts are the same") invokeMenuItem("File", "Close All") invokeMenuItem("File", "Open File or Project...") From 06ac9f00c0c31ede921276a2d1c2e98e87e4da62 Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Thu, 25 Aug 2016 12:29:02 +0200 Subject: [PATCH 18/21] Squish: Improve probabilty of dirseparator in generateRandomFilePath With up to 43 characters it's more probable to not have a dirseparator in the generated string. Change-Id: Ib59fc55eb0b78c9796e19006c057571d7d494e40 Reviewed-by: Christian Stenger --- tests/system/suite_general/tst_tasks_handling/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/suite_general/tst_tasks_handling/test.py b/tests/system/suite_general/tst_tasks_handling/test.py index e4e6d4e516b..69e7a6719cb 100644 --- a/tests/system/suite_general/tst_tasks_handling/test.py +++ b/tests/system/suite_general/tst_tasks_handling/test.py @@ -33,7 +33,7 @@ toolButton = ("{toolTip='%s' type='QToolButton' unnamed='1' visible='1' " def generateRandomFilePath(isWin, isHeader): # generate random (fake) file path filePath = ''.join(random.choice(string.ascii_letters + string.digits + "/") - for _ in range(random.randint(3, 15))) + for _ in range(random.randint(38, 50))) if not filePath.startswith("/"): filePath = "/" + filePath if isWin: From 9ae90a102b0e46fcae1ff2cf867b8dc9973a7fdb Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 30 Aug 2016 11:52:13 +0200 Subject: [PATCH 19/21] Debugger: Do not use remote working dir for local processes Task-number: QTCREATORBUG-16211 Change-Id: I55866bfb64bffb601afcafceb45934ac50b1c686 Reviewed-by: Christian Stenger --- src/plugins/debugger/gdb/remotegdbserveradapter.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/plugins/debugger/gdb/remotegdbserveradapter.cpp b/src/plugins/debugger/gdb/remotegdbserveradapter.cpp index d9806d19da6..642da9f5b78 100644 --- a/src/plugins/debugger/gdb/remotegdbserveradapter.cpp +++ b/src/plugins/debugger/gdb/remotegdbserveradapter.cpp @@ -86,8 +86,6 @@ void GdbRemoteServerEngine::setupEngine() m_uploadProc.start(arglist); m_uploadProc.waitForStarted(); } - if (!runParameters().inferior.workingDirectory.isEmpty()) - m_gdbProc.setWorkingDirectory(runParameters().inferior.workingDirectory); if (runParameters().remoteSetupNeeded) { notifyEngineRequestRemoteSetup(); From b97bc4016f90435fe9e82c3c2855804a34ca97de Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 30 Aug 2016 10:11:54 +0200 Subject: [PATCH 20/21] qbs build: Fix more warnings on Windows Change-Id: I2104d2889cff0fd6a2473e1e141936bb781041a9 Reviewed-by: Jake Petroules --- .../qmldesigner/componentsplugin/componentsplugin.qbs | 5 ++++- src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qbs | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/componentsplugin/componentsplugin.qbs b/src/plugins/qmldesigner/componentsplugin/componentsplugin.qbs index e8a5cae40bc..51d8ccbd636 100644 --- a/src/plugins/qmldesigner/componentsplugin/componentsplugin.qbs +++ b/src/plugins/qmldesigner/componentsplugin/componentsplugin.qbs @@ -28,7 +28,10 @@ QtcProduct { "../../../../share/qtcreator/qml/qmlpuppet/interfaces", "../../../../share/qtcreator/qml/qmlpuppet/types", ]) - cpp.internalVersion: "" + Properties { + condition: qbs.targetOS.contains("unix") + cpp.internalVersion: "" + } Group { name: "controls" diff --git a/src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qbs b/src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qbs index 56f5a83d87c..b6fdb2e14ba 100644 --- a/src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qbs +++ b/src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qbs @@ -8,7 +8,10 @@ QtcProduct { cpp.defines: base.concat("QTQUICK_LIBRARY") cpp.includePaths: base.concat("../designercore/include") - cpp.internalVersion: "" + Properties { + condition: qbs.targetOS.contains("unix") + cpp.internalVersion: "" + } Group { name: "sources" From 89ff2c1db5ee2068cf763ff1789b17b7f2afa118 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 25 Aug 2016 13:25:45 +0200 Subject: [PATCH 21/21] Editor: Collect indentation for a list of text blocks Allows the indenter to reuse code formatter structures. Task-number: QTCREATORBUG-16420 Change-Id: Ie906d7fdcb50798da02ef5b750fb03ae752aadc1 Reviewed-by: Nikolai Kosjar --- src/plugins/cpptools/cppqtstyleindenter.cpp | 18 +++++++++ src/plugins/cpptools/cppqtstyleindenter.h | 2 + src/plugins/glsleditor/glslindenter.cpp | 19 ++++++++++ src/plugins/glsleditor/glslindenter.h | 2 + src/plugins/qmljstools/qmljsindenter.cpp | 16 ++++++++ src/plugins/qmljstools/qmljsindenter.h | 2 + src/plugins/texteditor/indenter.cpp | 9 +++++ src/plugins/texteditor/indenter.h | 8 ++++ src/plugins/texteditor/textdocument.cpp | 42 ++++++++++++--------- 9 files changed, 100 insertions(+), 18 deletions(-) diff --git a/src/plugins/cpptools/cppqtstyleindenter.cpp b/src/plugins/cpptools/cppqtstyleindenter.cpp index e1596c60c69..8877d5b49c9 100644 --- a/src/plugins/cpptools/cppqtstyleindenter.cpp +++ b/src/plugins/cpptools/cppqtstyleindenter.cpp @@ -186,3 +186,21 @@ CppCodeStyleSettings CppQtStyleIndenter::codeStyleSettings() const return m_cppCodeStylePreferences->currentCodeStyleSettings(); return CppCodeStyleSettings(); } + +TextEditor::IndentationForBlock +CppQtStyleIndenter::indentationForBlocks(const QVector &blocks, + const TextEditor::TabSettings &tabSettings) +{ + QtStyleCodeFormatter codeFormatter(tabSettings, codeStyleSettings()); + + codeFormatter.updateStateUntil(blocks.last()); + + TextEditor::IndentationForBlock ret; + foreach (QTextBlock block, blocks) { + int indent; + int padding; + codeFormatter.indentFor(block, &indent, &padding); + ret.insert(block.blockNumber(), indent); + } + return ret; +} diff --git a/src/plugins/cpptools/cppqtstyleindenter.h b/src/plugins/cpptools/cppqtstyleindenter.h index 35b26d60ac1..c633717618a 100644 --- a/src/plugins/cpptools/cppqtstyleindenter.h +++ b/src/plugins/cpptools/cppqtstyleindenter.h @@ -58,6 +58,8 @@ public: void setCodeStylePreferences(TextEditor::ICodeStylePreferences *preferences) override; void invalidateCache(QTextDocument *doc) override; int indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings) override; + TextEditor::IndentationForBlock indentationForBlocks(const QVector &blocks, + const TextEditor::TabSettings &tabSettings) override; private: CppCodeStyleSettings codeStyleSettings() const; CppCodeStylePreferences *m_cppCodeStylePreferences; diff --git a/src/plugins/glsleditor/glslindenter.cpp b/src/plugins/glsleditor/glslindenter.cpp index 33aa8470649..3b229f0c909 100644 --- a/src/plugins/glsleditor/glslindenter.cpp +++ b/src/plugins/glsleditor/glslindenter.cpp @@ -124,5 +124,24 @@ int GlslIndenter::indentFor(const QTextBlock &block, const TextEditor::TabSettin return indent; } +TextEditor::IndentationForBlock +GlslIndenter::indentationForBlocks(const QVector &blocks, + const TextEditor::TabSettings &tabSettings) +{ + CppTools::QtStyleCodeFormatter codeFormatter(tabSettings, + CppTools::CppToolsSettings::instance()->cppCodeStyle()->codeStyleSettings()); + + codeFormatter.updateStateUntil(blocks.last()); + + TextEditor::IndentationForBlock ret; + foreach (QTextBlock block, blocks) { + int indent; + int padding; + codeFormatter.indentFor(block, &indent, &padding); + ret.insert(block.blockNumber(), indent); + } + return ret; +} + } // namespace Internal } // namespace GlslEditor diff --git a/src/plugins/glsleditor/glslindenter.h b/src/plugins/glsleditor/glslindenter.h index e52a024b102..42696f0d994 100644 --- a/src/plugins/glsleditor/glslindenter.h +++ b/src/plugins/glsleditor/glslindenter.h @@ -48,6 +48,8 @@ public: const TextEditor::TabSettings &tabSettings) override; int indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings) override; + TextEditor::IndentationForBlock indentationForBlocks(const QVector &blocks, + const TextEditor::TabSettings &tabSettings) override; }; } // namespace Internal diff --git a/src/plugins/qmljstools/qmljsindenter.cpp b/src/plugins/qmljstools/qmljsindenter.cpp index 71abf832b96..bcbff019b4d 100644 --- a/src/plugins/qmljstools/qmljsindenter.cpp +++ b/src/plugins/qmljstools/qmljsindenter.cpp @@ -90,3 +90,19 @@ int Indenter::indentFor(const QTextBlock &block, codeFormatter.updateStateUntil(block); return codeFormatter.indentFor(block); } + + +TextEditor::IndentationForBlock +Indenter::indentationForBlocks(const QVector &blocks, + const TextEditor::TabSettings &tabSettings) +{ + QmlJSTools::CreatorCodeFormatter codeFormatter(tabSettings); + + + codeFormatter.updateStateUntil(blocks.last()); + + TextEditor::IndentationForBlock ret; + foreach (QTextBlock block, blocks) + ret.insert(block.blockNumber(), codeFormatter.indentFor(block)); + return ret; +} diff --git a/src/plugins/qmljstools/qmljsindenter.h b/src/plugins/qmljstools/qmljsindenter.h index fb3f30c74f1..1c82a1b18cf 100644 --- a/src/plugins/qmljstools/qmljsindenter.h +++ b/src/plugins/qmljstools/qmljsindenter.h @@ -46,6 +46,8 @@ public: void invalidateCache(QTextDocument *doc) override; int indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings) override; + TextEditor::IndentationForBlock indentationForBlocks(const QVector &blocks, + const TextEditor::TabSettings &tabSettings) override; }; } // Internal diff --git a/src/plugins/texteditor/indenter.cpp b/src/plugins/texteditor/indenter.cpp index 29e9f8e2a2c..4f8b428a080 100644 --- a/src/plugins/texteditor/indenter.cpp +++ b/src/plugins/texteditor/indenter.cpp @@ -118,3 +118,12 @@ int Indenter::indentFor(const QTextBlock &block, const TabSettings &tabSettings) Q_UNUSED(tabSettings) return -1; } + +IndentationForBlock Indenter::indentationForBlocks(const QVector &blocks, + const TabSettings &tabSettings) +{ + IndentationForBlock ret; + foreach (QTextBlock block, blocks) + ret.insert(block.blockNumber(), indentFor(block, tabSettings)); + return ret; +} diff --git a/src/plugins/texteditor/indenter.h b/src/plugins/texteditor/indenter.h index 08286b33f5e..be78ea85413 100644 --- a/src/plugins/texteditor/indenter.h +++ b/src/plugins/texteditor/indenter.h @@ -27,6 +27,8 @@ #include "texteditor_global.h" +#include + QT_BEGIN_NAMESPACE class QTextDocument; class QTextCursor; @@ -39,6 +41,8 @@ namespace TextEditor { class ICodeStylePreferences; class TabSettings; +using IndentationForBlock = QMap; + class TEXTEDITOR_EXPORT Indenter { public: @@ -69,6 +73,10 @@ public: virtual void invalidateCache(QTextDocument *doc); virtual int indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings); + + // Expects a list of blocks in order of occurrence in the document. + virtual IndentationForBlock indentationForBlocks(const QVector &blocks, + const TextEditor::TabSettings &tabSettings); }; } // namespace TextEditor diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index 07dd48ba8eb..e3e73546443 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -764,29 +764,35 @@ void TextDocument::cleanWhitespace(QTextCursor &cursor, bool cleanIndentation, b if (cursor.hasSelection()) end = d->m_document.findBlock(cursor.selectionEnd()-1).next(); + QVector blocks; while (block.isValid() && block != end) { + if (inEntireDocument || block.revision() != documentLayout->lastSaveRevision) + blocks.append(block); + block = block.next(); + } + if (blocks.isEmpty()) + return; - if (inEntireDocument || block.revision() != documentLayout->lastSaveRevision) { + const IndentationForBlock &indentations = + d->m_indenter->indentationForBlocks(blocks, d->m_tabSettings); - QString blockText = block.text(); - d->m_tabSettings.removeTrailingWhitespace(cursor, block); - const int indent = d->m_indenter->indentFor(block, d->m_tabSettings); - if (cleanIndentation && !d->m_tabSettings.isIndentationClean(block, indent)) { - cursor.setPosition(block.position()); - int firstNonSpace = d->m_tabSettings.firstNonSpace(blockText); - if (firstNonSpace == blockText.length()) { - cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); - cursor.removeSelectedText(); - } else { - int column = d->m_tabSettings.columnAt(blockText, firstNonSpace); - cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, firstNonSpace); - QString indentationString = d->m_tabSettings.indentationString(0, column, column - indent, block); - cursor.insertText(indentationString); - } + foreach (block, blocks) { + QString blockText = block.text(); + d->m_tabSettings.removeTrailingWhitespace(cursor, block); + const int indent = indentations[block.blockNumber()]; + if (cleanIndentation && !d->m_tabSettings.isIndentationClean(block, indent)) { + cursor.setPosition(block.position()); + int firstNonSpace = d->m_tabSettings.firstNonSpace(blockText); + if (firstNonSpace == blockText.length()) { + cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); + cursor.removeSelectedText(); + } else { + int column = d->m_tabSettings.columnAt(blockText, firstNonSpace); + cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, firstNonSpace); + QString indentationString = d->m_tabSettings.indentationString(0, column, column - indent, block); + cursor.insertText(indentationString); } } - - block = block.next(); } }