diff options
36 files changed, 489 insertions, 70 deletions
diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py index eb8469bf5a..f7f32809f9 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) diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index afbff9099f..7a20042c40 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', '') diff --git a/share/qtcreator/debugger/qttypes.py b/share/qtcreator/debugger/qttypes.py index f0bc8ccc37..300fda0245 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("<not available>") + with SubItem(d, "permissions"): + d.putSpecialValue("notcallable") + d.putType(ns + "QFile::Permissions") + d.putNumChild(0) else: with SubItem(d, "permissions"): d.putEmptyValue() diff --git a/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp b/src/libs/modelinglib/qmt/model_widgets_ui/propertiesviewmview.cpp index 0b87e6f716..03ff3b65bb 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 <QCoreApplication> #include <QWidget> #include <QFormLayout> #include <QLineEdit> @@ -1364,7 +1365,7 @@ void PropertiesView::MView::setTitle(const QList<V *> &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<V *> &elemen m_propertiesTitle = pluralTitle; } } else { - m_propertiesTitle = tr("Multi-Selection"); + m_propertiesTitle = QCoreApplication::translate("qmt::PropertiesView::MView", "Multi-Selection"); } } } diff --git a/src/libs/qmljs/qmljsplugindumper.cpp b/src/libs/qmljs/qmljsplugindumper.cpp index f50fe9aaea..7556863568 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<FakeMetaObject::ConstPtr> &objects) const + QList<FakeMetaObject::ConstPtr> &objects, + QSet<QString> *visited) const { + if (dependencies.isEmpty()) + return; + + QScopedPointer<QSet<QString>> visitedPtr(visited ? visited : new QSet<QString>()); + 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 7d29e6ef3d..586275f021 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<LanguageUtils::FakeMetaObject::ConstPtr> &objects) const; + QList<LanguageUtils::FakeMetaObject::ConstPtr> &objects, + QSet<QString> *visited=0) const; void loadQmltypesFile(const QStringList &qmltypesFilePaths, const QString &libraryPath, QmlJS::LibraryInfo libraryInfo); diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index dca3d0c977..01c2cc08ea 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(); } diff --git a/src/plugins/bineditor/bineditorplugin.cpp b/src/plugins/bineditor/bineditorplugin.cpp index c1f9906a58..5fcccd7838 100644 --- a/src/plugins/bineditor/bineditorplugin.cpp +++ b/src/plugins/bineditor/bineditorplugin.cpp @@ -315,7 +315,8 @@ public: void provideNewRange(quint64 offset) { - openImpl(0, filePath().toString(), offset); + if (filePath().exists()) + openImpl(0, filePath().toString(), offset); } public: diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzer.pro b/src/plugins/clangstaticanalyzer/clangstaticanalyzer.pro index 0f8016f437..4450072a70 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 b4a9258e72..34d1fd2f77 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 f096336fcf..43691e4875 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 @@ -149,6 +150,7 @@ QList<QObject *> ClangStaticAnalyzerPlugin::createTestObjects() const { QList<QObject *> 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 0000000000..202e33b1d0 --- /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 <cpptools/cppmodelmanager.h> +#include <cpptools/projectinfo.h> +#include <projectexplorer/kitinformation.h> +#include <projectexplorer/kitmanager.h> +#include <projectexplorer/project.h> +#include <projectexplorer/projectexplorer.h> +#include <projectexplorer/session.h> +#include <projectexplorer/target.h> +#include <projectexplorer/toolchain.h> +#include <utils/algorithm.h> +#include <utils/fileutils.h> + +#include <QSignalSpy> +#include <QTimer> +#include <QtTest> + +#include <functional> + +using namespace CppTools; +using namespace ProjectExplorer; + +static bool processEventsUntil(const std::function<bool()> 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<QVariant> arguments = waitUntilAnalyzerFinished.takeFirst(); + QVERIFY(arguments.first().toBool()); + QCOMPARE(m_analyzerTool.diagnostics().count(), 0); +} + +static QList<Project *> validProjects(const QList<Project *> projectsOfSession) +{ + QList<Project *> sortedProjects = projectsOfSession; + Utils::sort(sortedProjects, [](Project *lhs, Project *rhs){ + return lhs->displayName() < rhs->displayName(); + }); + + const auto isValidProject = [](Project *project) { + const QList <Target *> 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<Target *> validTargets(Project *project) +{ + QList<Target *> 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 *>("project"); + QTest::addColumn<Target *>("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 0000000000..786b6dd0d2 --- /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 <QObject> +#include <QString> + +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 diff --git a/src/plugins/coreplugin/outputpane.cpp b/src/plugins/coreplugin/outputpane.cpp index eef0312aea..b0f5c195bc 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); } diff --git a/src/plugins/cpptools/cppqtstyleindenter.cpp b/src/plugins/cpptools/cppqtstyleindenter.cpp index e1596c60c6..8877d5b49c 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<QTextBlock> &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 35b26d60ac..c633717618 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<QTextBlock> &blocks, + const TextEditor::TabSettings &tabSettings) override; private: CppCodeStyleSettings codeStyleSettings() const; CppCodeStylePreferences *m_cppCodeStylePreferences; diff --git a/src/plugins/debugger/analyzer/analyzerruncontrol.h b/src/plugins/debugger/analyzer/analyzerruncontrol.h index 97ce85e69a..2fc47727db 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/glsleditor/glslindenter.cpp b/src/plugins/glsleditor/glslindenter.cpp index 33aa847064..3b229f0c90 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<QTextBlock> &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 e52a024b10..42696f0d99 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<QTextBlock> &blocks, + const TextEditor::TabSettings &tabSettings) override; }; } // namespace Internal diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp index 8dcc429659..a21dfb8caa 100644 --- a/src/plugins/help/helpindexfilter.cpp +++ b/src/plugins/help/helpindexfilter.cpp @@ -87,6 +87,8 @@ QList<LocatorFilterEntry> HelpIndexFilter::matchesFor(QFutureInterface<LocatorFi int limit = entry.size() < 2 ? 200 : INT_MAX; QSet<QString> results; foreach (const QString &filePath, m_helpDatabases) { + if (future.isCanceled()) + return QList<LocatorFilterEntry>(); QSet<QString> result; QMetaObject::invokeMethod(this, "searchMatches", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QSet<QString>, result), @@ -111,7 +113,7 @@ QList<LocatorFilterEntry> HelpIndexFilter::matchesFor(QFutureInterface<LocatorFi QSet<QString> allresults; foreach (const QString &keyword, m_keywordCache) { if (future.isCanceled()) - break; + return QList<LocatorFilterEntry>(); if (keyword.startsWith(entry, cs)) { keywords.append(keyword); allresults.insert(keyword); diff --git a/src/plugins/qmakeprojectmanager/makestep.cpp b/src/plugins/qmakeprojectmanager/makestep.cpp index d69eb56f64..a824ddafac 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<QmakeBuildConfiguration *>(target()->activeBuildConfiguration()); ToolChain *tc = ToolChainKitInformation::toolChain(target()->kit(), ToolChain::Language::Cxx); if (bc && tc) diff --git a/src/plugins/qmldesigner/componentsplugin/componentsplugin.qbs b/src/plugins/qmldesigner/componentsplugin/componentsplugin.qbs index e8a5cae40b..51d8ccbd63 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 56f5a83d87..b6fdb2e14b 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" diff --git a/src/plugins/qmljstools/qmljsindenter.cpp b/src/plugins/qmljstools/qmljsindenter.cpp index 71abf832b9..bcbff019b4 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<QTextBlock> &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 fb3f30c74f..1c82a1b18c 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<QTextBlock> &blocks, + const TextEditor::TabSettings &tabSettings) override; }; } // Internal diff --git a/src/plugins/qmlprofiler/localqmlprofilerrunner.cpp b/src/plugins/qmlprofiler/localqmlprofilerrunner.cpp index 3be605542e..bffe0d23c8 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 0122771b57..bcbd996af8 100644 --- a/src/plugins/qmlprofiler/localqmlprofilerrunner.h +++ b/src/plugins/qmlprofiler/localqmlprofilerrunner.h @@ -30,6 +30,7 @@ #include <utils/port.h> #include <projectexplorer/applicationlauncher.h> #include <projectexplorer/runnables.h> +#include <qmldebug/qmloutputparser.h> 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 55a47e3f59..224e5652cf 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); @@ -244,12 +228,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(); if (!port.isValid()) { QTC_ASSERT(connection().is<AnalyzerConnection>(), return); diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.h b/src/plugins/qmlprofiler/qmlprofilerruncontrol.h index b1a1f121fe..49716c05a4 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; diff --git a/src/plugins/texteditor/codeassist/genericproposalwidget.cpp b/src/plugins/texteditor/codeassist/genericproposalwidget.cpp index 4a1e1eff67..5e3a466aaf 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; } diff --git a/src/plugins/texteditor/indenter.cpp b/src/plugins/texteditor/indenter.cpp index 29e9f8e2a2..4f8b428a08 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<QTextBlock> &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 08286b33f5..be78ea8541 100644 --- a/src/plugins/texteditor/indenter.h +++ b/src/plugins/texteditor/indenter.h @@ -27,6 +27,8 @@ #include "texteditor_global.h" +#include <QMap> + QT_BEGIN_NAMESPACE class QTextDocument; class QTextCursor; @@ -39,6 +41,8 @@ namespace TextEditor { class ICodeStylePreferences; class TabSettings; +using IndentationForBlock = QMap<int, int>; + 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<QTextBlock> &blocks, + const TextEditor::TabSettings &tabSettings); }; } // namespace TextEditor diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index 07dd48ba8e..e3e7354644 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<QTextBlock> blocks; while (block.isValid() && block != end) { + if (inEntireDocument || block.revision() != documentLayout->lastSaveRevision) + blocks.append(block); + block = block.next(); + } + if (blocks.isEmpty()) + return; + + const IndentationForBlock &indentations = + d->m_indenter->indentationForBlocks(blocks, d->m_tabSettings); - if (inEntireDocument || block.revision() != documentLayout->lastSaveRevision) { - - 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(); } } diff --git a/src/plugins/texteditor/textmark.cpp b/src/plugins/texteditor/textmark.cpp index e4f68eee4b..86f4b551b4 100644 --- a/src/plugins/texteditor/textmark.cpp +++ b/src/plugins/texteditor/textmark.cpp @@ -294,7 +294,7 @@ void TextMarkRegistry::documentRenamed(IDocument *document, const QString &oldName, const QString &newName) { TextDocument *baseTextDocument = qobject_cast<TextDocument *>(document); - if (!document) + if (!baseTextDocument) return; FileName oldFileName = FileName::fromString(oldName); FileName newFileName = FileName::fromString(newName); diff --git a/tests/system/suite_general/tst_tasks_handling/test.py b/tests/system/suite_general/tst_tasks_handling/test.py index e4e6d4e516..69e7a6719c 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: diff --git a/tests/system/suite_tools/tst_codepasting/test.py b/tests/system/suite_tools/tst_codepasting/test.py index e05ebe2603..5a5c16dfa5 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...") |