aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Ziller <eike.ziller@qt.io>2017-10-19 13:01:12 +0200
committerEike Ziller <eike.ziller@qt.io>2017-10-19 13:01:12 +0200
commitbb9663529beec0530f227cb196907d8a87593a3d (patch)
treebd772de7f00d73086e1d0c0a051b9fefafdeefb2
parent7208ef1ff51e766ae5af64c95436b74a6535d811 (diff)
parent38d307ffb84e4c945682263e2e006ddf23aed857 (diff)
Merge remote-tracking branch 'origin/4.5'
-rw-r--r--doc/src/qtquick/qtquick-modules-with-plugins.qdoc80
-rw-r--r--qbs/imports/QtcAutotest.qbs6
-rw-r--r--qbs/modules/qtc/qtc.qbs2
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp2
-rw-r--r--src/libs/extensionsystem/pluginerroroverview.ui2
-rw-r--r--src/libs/utils/bracematcher.cpp119
-rw-r--r--src/libs/utils/bracematcher.h66
-rw-r--r--src/libs/utils/utils-lib.pri2
-rw-r--r--src/libs/utils/utils.qbs2
-rw-r--r--src/plugins/autotest/gtest/gtesttreeitem.cpp42
-rw-r--r--src/plugins/autotest/testconfiguration.cpp6
-rw-r--r--src/plugins/autotest/testconfiguration.h1
-rw-r--r--src/plugins/clangcodemodel/clangactivationsequencecontextprocessor.cpp12
-rw-r--r--src/plugins/clangcodemodel/clangactivationsequencecontextprocessor.h4
-rw-r--r--src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp4
-rw-r--r--src/plugins/debugger/debugger.qbs1
-rw-r--r--src/plugins/debugger/debuggerplugin.cpp73
-rw-r--r--src/plugins/debugger/debuggerruncontrol.cpp61
-rw-r--r--src/plugins/debugger/debuggerruncontrol.h11
-rw-r--r--src/plugins/debugger/gdb/gdb.pri6
-rw-r--r--src/plugins/debugger/gdb/gdbengine.cpp97
-rw-r--r--src/plugins/debugger/gdb/startgdbserverdialog.cpp234
-rw-r--r--src/plugins/debugger/gdb/startgdbserverdialog.h65
-rw-r--r--src/plugins/genericprojectmanager/genericbuildconfiguration.cpp10
-rw-r--r--src/plugins/genericprojectmanager/genericbuildconfiguration.h2
-rw-r--r--src/plugins/projectexplorer/buildconfiguration.cpp38
-rw-r--r--src/plugins/projectexplorer/buildconfiguration.h4
-rw-r--r--src/plugins/projectexplorer/gcctoolchain.cpp7
-rw-r--r--src/plugins/projectexplorer/projectexplorer.cpp8
-rw-r--r--src/plugins/projectexplorer/runconfiguration.cpp27
-rw-r--r--src/plugins/projectexplorer/runconfiguration.h4
-rw-r--r--src/plugins/pythoneditor/pythoneditorplugin.cpp37
-rw-r--r--src/plugins/qmakeandroidsupport/androidqmakebuildconfigurationfactory.cpp2
-rw-r--r--src/plugins/qmakeandroidsupport/androidqmakebuildconfigurationfactory.h2
-rw-r--r--src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp8
-rw-r--r--src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h2
-rw-r--r--src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.cpp5
-rw-r--r--src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.h1
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.cpp6
-rw-r--r--src/plugins/qmldesigner/components/integration/designdocument.cpp8
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp3
-rw-r--r--src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.cpp2
-rw-r--r--src/plugins/qmldesigner/components/texteditor/texteditorview.cpp6
-rw-r--r--src/plugins/qmldesigner/designercore/include/qmltimelinekeyframes.h5
-rw-r--r--src/plugins/qmldesigner/designercore/include/qmltimelinemutator.h7
-rw-r--r--src/plugins/qmldesigner/designercore/metainfo/metainfo.cpp2
-rw-r--r--src/plugins/qmldesigner/designercore/model/qmltimelinekeyframes.cpp38
-rw-r--r--src/plugins/qmldesigner/designercore/model/qmltimelinemutator.cpp69
-rw-r--r--src/plugins/qmldesigner/qmldesignerplugin.cpp1
-rw-r--r--src/plugins/qmldesigner/shortcutmanager.cpp5
-rw-r--r--src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp2
-rw-r--r--src/plugins/qtsupport/baseqtversion.cpp1
-rw-r--r--src/tools/qml2puppet/qml2puppet/qml2puppet.pro3
-rw-r--r--tests/system/shared/editor_utils.py11
-rwxr-xr-xtests/system/suite_HELP/tst_HELP05/test.py15
-rw-r--r--tests/system/suite_QMLS/tst_QMLS01/test.py15
-rw-r--r--tests/system/suite_QMLS/tst_QMLS02/test.py8
-rw-r--r--tests/system/suite_QMLS/tst_QMLS04/test.py9
-rw-r--r--tests/system/suite_QMLS/tst_QMLS05/test.py2
-rw-r--r--tests/system/suite_QMLS/tst_QMLS06/test.py7
-rw-r--r--tests/system/suite_editors/tst_qml_indent/test.py34
-rw-r--r--tests/system/suite_general/tst_default_settings/test.py5
-rw-r--r--tests/unit/unittest/activationsequencecontextprocessor-test.cpp4
-rw-r--r--tests/unit/unittest/clangcompletioncontextanalyzer-test.cpp7
64 files changed, 611 insertions, 719 deletions
diff --git a/doc/src/qtquick/qtquick-modules-with-plugins.qdoc b/doc/src/qtquick/qtquick-modules-with-plugins.qdoc
index d03626efca7..816c6c934de 100644
--- a/doc/src/qtquick/qtquick-modules-with-plugins.qdoc
+++ b/doc/src/qtquick/qtquick-modules-with-plugins.qdoc
@@ -42,7 +42,47 @@
the contained components, and therefore, the modules must provide extra type
information for code completion and the semantic checks to work correctly.
- When you write a QML module or use QML from a C++ application you typically
+ To create a QML module and make it appear in the \uicontrol Library in
+ \QMLD:
+
+ \list 1
+
+ \li Create custom QML controls and place all the \c .qml files in a
+ directory dedicated to your module.
+
+ \li Create a \c qmldir file for your module and place it in the module
+ directory. For more information, see
+ \l {Module Definition qmldir Files}.
+
+ \li Create a \c qmltypes file, preferably using \c qmlplugindump.
+ For more information see, \l {Generating qmltypes Files}.
+
+ \li Create a directory named \c designer in your module directory.
+
+ \li Create a \c .metainfo file for your module and place it in the
+ \c designer directory. Meta information is needed to display the
+ components in the \uicontrol {QML Types} tab in the \uicontrol
+ Library. Use a metainfo file delivered with Qt, such as
+ \c qtquickcontrols2.metainfo, as an example.
+
+ \li Import your module into a project using \c QML_IMPORT_PATH in the
+ .pro file: \c {QML_IMPORT_PATH += path/to/module}.
+ For more information, see \l {Importing QML Modules}.
+
+ \li Make sure that the QML emulation layer of \QMLD is built with
+ the same Qt version as your QML modules. For more information, see
+ \l {Running QML Modules in Qt Quick Designer}. You can also try
+ skipping this step and take it later, if necessary.
+
+ \endlist
+
+ Your module should now appear in the \uicontrol Imports tab in the
+ \uicontrol Library in \QMLD. Your components should appear in the
+ \uicontrol {QML Types} tab if a valid \c .metainfo file is in place.
+
+ \section1 Registering QML Types
+
+ When you write a QML module or use QML from a C++ application, you typically
register new types with the qmlRegisterType() function or expose some
class instances with \l{QQmlContext::setContextProperty()}. The \QC C++
code model now scans for these calls and
@@ -55,19 +95,7 @@
Classes registered with \c qmlRegisterType() can be used as backend objects
in the \QMLD. For more information, see \l {Adding Connections}.
- By default, \QC will look in the QML import path of Qt for QML modules.
- If your applications adds additional import paths that \QC should use,
- then you can specify those using \c{QML_IMPORT_PATH} in the \c{.pro} file of your
- application.
-
- If you use CMake, add the following command to the CMakeLists.txt file to
- set the QML import path:
-
- \code
- {set(QML_IMPORT_PATH ${CMAKE_SOURCE_DIR}/qml ${CMAKE_BINARY_DIR}/imports CACHE string "" FORCE)}
- \endcode
-
- The import path affects all the targets built by the CMake project.
+ \section1 Generating qmltypes Files
Ideally, QML modules have a \c{plugins.qmltypes} file in the same directory
as the \c qmldir file. The \c qmltypes file contains a description of the
@@ -79,20 +107,18 @@
addition to \c{plugins.qmltypes}. For more information, see
\l{Writing a qmltypes File}.
- \section1 Generating qmltypes Files
-
You can create and edit \c qmltypes files manually, but you are recommended
to use the \c qmlplugindump tool shipped with Qt 4.8 and later to generate
them automatically.
- Once you have obtained qmlplugindump for the Qt version the QML module's
+ Once you have obtained \c qmlplugindump for the Qt version the QML module's
plugins were compiled with, run the following command to load My.Module
version 1.0 from \c{/import/path/my/module} including all its plugins and
output a description of the plugins' types to
\c{/import/path/my/module/plugins.qmltypes}:
\code
- qmlplugindump My.Module 1.0 /import/path > /import/path/my/module/plugins.qmltypes
+ qmlplugindump -nonrelocatable My.Module 1.0 /import/path > /import/path/my/module/plugins.qmltypes
\endcode
You can safely ignore the debug output.
@@ -101,13 +127,29 @@
the sources in \c{<QtCreator>/share/qtcreator/qml/qmldump} if the Qt version
contains private headers.
- \section1 Dumping Plugins Automatically
+ \section2 Dumping Plugins Automatically
If a module with plugins lacks the \c qmltypes file, \QC tries to generate
a temporary file itself by running the \c qmldump program in the background.
However, this automatic dumping is a fallback mechanism with many points of
failure and you cannot rely upon it.
+ \section1 Importing QML Modules
+
+ By default, \QC will look in the QML import path of Qt for QML modules.
+ If your applications adds additional import paths that \QC should use,
+ then you can specify those using \c{QML_IMPORT_PATH} in the \c{.pro} file of your
+ application.
+
+ If you use CMake, add the following command to the CMakeLists.txt file to
+ set the QML import path:
+
+ \code
+ {set(QML_IMPORT_PATH ${CMAKE_SOURCE_DIR}/qml ${CMAKE_BINARY_DIR}/imports CACHE string "" FORCE)}
+ \endcode
+
+ The import path affects all the targets built by the CMake project.
+
\section1 Running QML Modules in Qt Quick Designer
\QMLD uses a QML emulation layer (also called QML Puppet) to render and
diff --git a/qbs/imports/QtcAutotest.qbs b/qbs/imports/QtcAutotest.qbs
index bbef04d1751..cb914f7ef1c 100644
--- a/qbs/imports/QtcAutotest.qbs
+++ b/qbs/imports/QtcAutotest.qbs
@@ -15,7 +15,11 @@ QtcProduct {
project.buildDirectory + '/' + qtc.ide_library_path,
project.buildDirectory + '/' + qtc.ide_plugin_path
]
- cpp.defines: base.filter(function(d) { return d != "QT_RESTRICTED_CAST_FROM_ASCII"; })
+ cpp.defines: base.filter(function(d) {
+ return d !== "QT_RESTRICTED_CAST_FROM_ASCII"
+ && d !== "QT_USE_FAST_OPERATOR_PLUS"
+ && d !== "QT_USE_FAST_CONCATENATION";
+ })
Group {
fileTagsFilter: product.type
diff --git a/qbs/modules/qtc/qtc.qbs b/qbs/modules/qtc/qtc.qbs
index 4b8058d3a6a..60816c0eb07 100644
--- a/qbs/modules/qtc/qtc.qbs
+++ b/qbs/modules/qtc/qtc.qbs
@@ -76,6 +76,8 @@ Module {
"QT_NO_CAST_TO_ASCII",
"QT_RESTRICTED_CAST_FROM_ASCII",
"QT_DISABLE_DEPRECATED_BEFORE=0x050600",
+ "QT_USE_FAST_OPERATOR_PLUS",
+ "QT_USE_FAST_CONCATENATION",
].concat(testsEnabled ? ["WITH_TESTS"] : [])
Rule {
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp
index 102e3851d04..1dc4716649c 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp
@@ -693,7 +693,7 @@ static inline QString fixComponentPathForIncompatibleQt(const QString &component
//plugin directories might contain the version number
fixedPath.chop(4);
fixedPath += QLatin1Char('/') + QFileInfo(componentPath).fileName();
- if (QFileInfo(fixedPath).exists())
+ if (QFileInfo::exists(fixedPath))
return fixedPath;
}
}
diff --git a/src/libs/extensionsystem/pluginerroroverview.ui b/src/libs/extensionsystem/pluginerroroverview.ui
index e87cb34c639..080a73b233f 100644
--- a/src/libs/extensionsystem/pluginerroroverview.ui
+++ b/src/libs/extensionsystem/pluginerroroverview.ui
@@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
- <string>Plugin loader messages</string>
+ <string>Plugin Loader Messages</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
diff --git a/src/libs/utils/bracematcher.cpp b/src/libs/utils/bracematcher.cpp
deleted file mode 100644
index eb56df561fc..00000000000
--- a/src/libs/utils/bracematcher.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Konstantin Tokarev <annulen@yandex.ru>
-** 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 "bracematcher.h"
-
-#include <QTextDocument>
-#include <QTextCursor>
-
-/*!
- \class Utils::BraceMatcher
- \brief The BraceMatcher class implements a generic autocompleter of braces
- and quotes.
-
- This is a helper class for autocompleter implementations. To use it,
- define \e brace, \e quote, and \e delimiter characters for a given language.
-*/
-
-namespace Utils {
-
-/*!
- * Adds a pair of characters, corresponding to \a opening and \a closing braces.
- */
-void BraceMatcher::addBraceCharPair(const QChar opening, const QChar closing)
-{
- m_braceChars[opening] = closing;
-}
-
-/*!
- * Adds a \a quote character.
- */
-void BraceMatcher::addQuoteChar(const QChar quote)
-{
- m_quoteChars << quote;
-}
-
-/*!
- * Adds a separator character \a sep that should be skipped when overtyping it.
- * For example, it could be ';' or ',' in C-like languages.
- */
-void BraceMatcher::addDelimiterChar(const QChar sep)
-{
- m_delimiterChars << sep;
-}
-
-bool BraceMatcher::shouldInsertMatchingText(const QTextCursor &tc) const
-{
- QTextDocument *doc = tc.document();
- return shouldInsertMatchingText(doc->characterAt(tc.selectionEnd()));
-}
-
-bool BraceMatcher::shouldInsertMatchingText(const QChar lookAhead) const
-{
- return lookAhead.isSpace()
- || isQuote(lookAhead)
- || isDelimiter(lookAhead)
- || isClosingBrace(lookAhead);
-}
-
-QString BraceMatcher::insertMatchingBrace(const QTextCursor &cursor,
- const QString &text,
- const QChar la,
- int *skippedChars) const
-{
- if (text.length() != 1)
- return QString();
-
- if (!shouldInsertMatchingText(cursor))
- return QString();
-
- const QChar ch = text.at(0);
- if (isQuote(ch)) {
- if (la != ch)
- return QString(ch);
- ++*skippedChars;
- return QString();
- }
-
- if (isOpeningBrace(ch))
- return QString(m_braceChars[ch]);
-
- if (isDelimiter(ch) || isClosingBrace(ch)) {
- if (la == ch)
- ++*skippedChars;
- }
-
- return QString();
-}
-
-/*!
- * Returns true if the character \a c was added as one of character types.
- */
-bool BraceMatcher::isKnownChar(const QChar c) const
-{
- return isQuote(c) || isDelimiter(c) || isOpeningBrace(c) || isClosingBrace(c);
-}
-
-} // namespace Utils
diff --git a/src/libs/utils/bracematcher.h b/src/libs/utils/bracematcher.h
deleted file mode 100644
index e2fa0928d3d..00000000000
--- a/src/libs/utils/bracematcher.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Konstantin Tokarev <annulen@yandex.ru>
-** 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 "utils_global.h"
-
-#include <QChar>
-#include <QSet>
-#include <QMap>
-
-QT_BEGIN_NAMESPACE
-class QString;
-class QTextCursor;
-QT_END_NAMESPACE
-
-namespace Utils {
-
-class QTCREATOR_UTILS_EXPORT BraceMatcher
-{
-public:
- void addBraceCharPair(const QChar opening, const QChar closing);
- void addQuoteChar(const QChar quote);
- void addDelimiterChar(const QChar delim);
-
- bool shouldInsertMatchingText(const QTextCursor &tc) const;
- bool shouldInsertMatchingText(const QChar lookAhead) const;
-
- QString insertMatchingBrace(const QTextCursor &tc, const QString &text,
- const QChar la, int *skippedChars) const;
-
- bool isOpeningBrace(const QChar c) const { return m_braceChars.contains(c); }
- bool isClosingBrace(const QChar c) const { return m_braceChars.values().contains(c); }
- bool isQuote(const QChar c) const { return m_quoteChars.contains(c); }
- bool isDelimiter(const QChar c) const { return m_delimiterChars.contains(c); }
- bool isKnownChar(const QChar c) const;
-
-private:
- QMap<QChar, QChar> m_braceChars;
- QSet<QChar> m_quoteChars;
- QSet<QChar> m_delimiterChars;
-};
-
-} // namespace Utils
diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri
index c97245cbf25..84893298ee8 100644
--- a/src/libs/utils/utils-lib.pri
+++ b/src/libs/utils/utils-lib.pri
@@ -89,7 +89,6 @@ SOURCES += \
$$PWD/basetreeview.cpp \
$$PWD/qtcassert.cpp \
$$PWD/elfreader.cpp \
- $$PWD/bracematcher.cpp \
$$PWD/proxyaction.cpp \
$$PWD/elidinglabel.cpp \
$$PWD/hostosinfo.cpp \
@@ -197,7 +196,6 @@ HEADERS += \
$$PWD/appmainwindow.h \
$$PWD/basetreeview.h \
$$PWD/elfreader.h \
- $$PWD/bracematcher.h \
$$PWD/proxyaction.h \
$$PWD/hostosinfo.h \
$$PWD/osspecificaspects.h \
diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs
index b42f4aecc6d..2f33b82931a 100644
--- a/src/libs/utils/utils.qbs
+++ b/src/libs/utils/utils.qbs
@@ -50,8 +50,6 @@ Project {
"basetreeview.h",
"benchmarker.cpp",
"benchmarker.h",
- "bracematcher.cpp",
- "bracematcher.h",
"buildablehelperlibrary.cpp",
"buildablehelperlibrary.h",
"camelhumpmatcher.cpp",
diff --git a/src/plugins/autotest/gtest/gtesttreeitem.cpp b/src/plugins/autotest/gtest/gtesttreeitem.cpp
index b0f11830383..efd336e1efe 100644
--- a/src/plugins/autotest/gtest/gtesttreeitem.cpp
+++ b/src/plugins/autotest/gtest/gtesttreeitem.cpp
@@ -138,19 +138,22 @@ QList<TestConfiguration *> GTestTreeItem::getAllTestConfigurations() const
const TestTreeItem *grandChild = child->childItem(grandChildRow);
const QString &key = grandChild->proFile();
proFilesWithTestSets.insert(key, proFilesWithTestSets[key] + 1);
- proFilesWithInternalTargets.insert(key, grandChild->internalTargets());
+ proFilesWithInternalTargets[key].unite(grandChild->internalTargets());
}
}
QHash<QString, int>::ConstIterator it = proFilesWithTestSets.begin();
QHash<QString, int>::ConstIterator end = proFilesWithTestSets.end();
for ( ; it != end; ++it) {
- GTestConfiguration *tc = new GTestConfiguration;
- tc->setTestCaseCount(it.value());
- tc->setProjectFile(it.key());
- tc->setProject(project);
- tc->setInternalTargets(proFilesWithInternalTargets.value(it.key()));
- result << tc;
+ const QSet<QString> &internalTargets = proFilesWithInternalTargets[it.key()];
+ for (const QString &target : internalTargets) {
+ GTestConfiguration *tc = new GTestConfiguration;
+ tc->setTestCaseCount(it.value());
+ tc->setProjectFile(it.key());
+ tc->setProject(project);
+ tc->setInternalTarget(target);
+ result << tc;
+ }
}
return result;
@@ -184,8 +187,8 @@ QList<TestConfiguration *> GTestTreeItem::getSelectedTestConfigurations() const
auto &testCases = proFilesWithCheckedTestSets[child->childItem(0)->proFile()];
testCases.filters.append(gtestFilter(child->state()).arg(child->name()).arg('*'));
testCases.additionalTestCaseCount += grandChildCount - 1;
- proFilesWithInternalTargets.insert(child->childItem(0)->proFile(),
- child->internalTargets());
+ proFilesWithInternalTargets[child->childItem(0)->proFile()].unite(
+ child->internalTargets());
break;
}
case Qt::PartiallyChecked: {
@@ -194,8 +197,8 @@ QList<TestConfiguration *> GTestTreeItem::getSelectedTestConfigurations() const
if (grandChild->checked() == Qt::Checked) {
proFilesWithCheckedTestSets[grandChild->proFile()].filters.append(
gtestFilter(child->state()).arg(child->name()).arg(grandChild->name()));
- proFilesWithInternalTargets.insert(grandChild->proFile(),
- grandChild->internalTargets());
+ proFilesWithInternalTargets[grandChild->proFile()].unite(
+ grandChild->internalTargets());
}
}
break;
@@ -206,13 +209,16 @@ QList<TestConfiguration *> GTestTreeItem::getSelectedTestConfigurations() const
QHash<QString, TestCases>::ConstIterator it = proFilesWithCheckedTestSets.begin();
QHash<QString, TestCases>::ConstIterator end = proFilesWithCheckedTestSets.end();
for ( ; it != end; ++it) {
- GTestConfiguration *tc = new GTestConfiguration;
- tc->setTestCases(it.value().filters);
- tc->setTestCaseCount(tc->testCaseCount() + it.value().additionalTestCaseCount);
- tc->setProjectFile(it.key());
- tc->setProject(project);
- tc->setInternalTargets(proFilesWithInternalTargets[it.key()]);
- result << tc;
+ const QSet<QString> &internalTargets = proFilesWithInternalTargets[it.key()];
+ for (const QString &target : internalTargets) {
+ GTestConfiguration *tc = new GTestConfiguration;
+ tc->setTestCases(it.value().filters);
+ tc->setTestCaseCount(tc->testCaseCount() + it.value().additionalTestCaseCount);
+ tc->setProjectFile(it.key());
+ tc->setProject(project);
+ tc->setInternalTarget(target);
+ result << tc;
+ }
}
return result;
diff --git a/src/plugins/autotest/testconfiguration.cpp b/src/plugins/autotest/testconfiguration.cpp
index 34c8ef18135..46b38f19922 100644
--- a/src/plugins/autotest/testconfiguration.cpp
+++ b/src/plugins/autotest/testconfiguration.cpp
@@ -320,6 +320,12 @@ void TestConfiguration::setProject(Project *project)
m_project = project;
}
+void TestConfiguration::setInternalTarget(const QString &target)
+{
+ m_buildTargets.clear();
+ m_buildTargets.insert(target);
+}
+
void TestConfiguration::setInternalTargets(const QSet<QString> &targets)
{
m_buildTargets = targets;
diff --git a/src/plugins/autotest/testconfiguration.h b/src/plugins/autotest/testconfiguration.h
index e3a0bcea3f9..224d7b19fe3 100644
--- a/src/plugins/autotest/testconfiguration.h
+++ b/src/plugins/autotest/testconfiguration.h
@@ -67,6 +67,7 @@ public:
void setDisplayName(const QString &displayName);
void setEnvironment(const Utils::Environment &env);
void setProject(ProjectExplorer::Project *project);
+ void setInternalTarget(const QString &target);
void setInternalTargets(const QSet<QString> &targets);
void setOriginalRunConfiguration(ProjectExplorer::RunConfiguration *runConfig);
diff --git a/src/plugins/clangcodemodel/clangactivationsequencecontextprocessor.cpp b/src/plugins/clangcodemodel/clangactivationsequencecontextprocessor.cpp
index 62573c70fde..2b364a1d8c5 100644
--- a/src/plugins/clangcodemodel/clangactivationsequencecontextprocessor.cpp
+++ b/src/plugins/clangcodemodel/clangactivationsequencecontextprocessor.cpp
@@ -243,11 +243,14 @@ static bool isValidIdentifierChar(const QChar &character)
int ActivationSequenceContextProcessor::findStartOfName(
const TextEditor::AssistInterface *assistInterface,
- int startPosition)
+ int startPosition,
+ NameCategory category)
{
int position = startPosition;
QChar character;
- if (position > 2 && assistInterface->characterAt(position - 1) == '>'
+
+ if (category == NameCategory::Function
+ && position > 2 && assistInterface->characterAt(position - 1) == '>'
&& assistInterface->characterAt(position - 2) != '-') {
uint unbalancedLessGreater = 1;
--position;
@@ -267,11 +270,12 @@ int ActivationSequenceContextProcessor::findStartOfName(
} while (isValidIdentifierChar(character));
int prevPosition = skipPrecedingWhitespace(assistInterface, position);
- if (assistInterface->characterAt(prevPosition) == ':'
+ if (category == NameCategory::Function
+ && assistInterface->characterAt(prevPosition) == ':'
&& assistInterface->characterAt(prevPosition - 1) == ':') {
// Handle :: case - go recursive
prevPosition = skipPrecedingWhitespace(assistInterface, prevPosition - 2);
- return findStartOfName(assistInterface, prevPosition + 1);
+ return findStartOfName(assistInterface, prevPosition + 1, category);
}
return position + 1;
diff --git a/src/plugins/clangcodemodel/clangactivationsequencecontextprocessor.h b/src/plugins/clangcodemodel/clangactivationsequencecontextprocessor.h
index 6bb25da086f..bffd8d0d262 100644
--- a/src/plugins/clangcodemodel/clangactivationsequencecontextprocessor.h
+++ b/src/plugins/clangcodemodel/clangactivationsequencecontextprocessor.h
@@ -49,8 +49,10 @@ public:
const QTextCursor &textCursor_forTestOnly() const;
+ enum class NameCategory { Function, NonFunction };
static int findStartOfName(const TextEditor::AssistInterface *assistInterface,
- int startPosition);
+ int startPosition,
+ NameCategory category = NameCategory::NonFunction);
static int skipPrecedingWhitespace(const TextEditor::AssistInterface *assistInterface,
int startPosition);
diff --git a/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp b/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp
index bb8308eada5..1f3f5bfebb1 100644
--- a/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp
+++ b/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp
@@ -101,8 +101,8 @@ int ClangCompletionContextAnalyzer::startOfFunctionCall(int endOfOperator) const
ExpressionUnderCursor euc(m_languageFeatures);
index = euc.startOfFunctionCall(textCursor);
index = ActivationSequenceContextProcessor::skipPrecedingWhitespace(m_interface, index);
- const int functionNameStart = ActivationSequenceContextProcessor::findStartOfName(m_interface,
- index);
+ const int functionNameStart = ActivationSequenceContextProcessor::findStartOfName(
+ m_interface, index, ActivationSequenceContextProcessor::NameCategory::Function);
if (functionNameStart == -1)
return -1;
diff --git a/src/plugins/debugger/debugger.qbs b/src/plugins/debugger/debugger.qbs
index 08faeb3d1e6..9a69fb289af 100644
--- a/src/plugins/debugger/debugger.qbs
+++ b/src/plugins/debugger/debugger.qbs
@@ -110,7 +110,6 @@ Project {
files: [
"gdbengine.cpp", "gdbengine.h",
"gdboptionspage.cpp",
- "startgdbserverdialog.cpp", "startgdbserverdialog.h",
]
}
diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp
index d8ee01a58f6..e5b8d8fdbe6 100644
--- a/src/plugins/debugger/debuggerplugin.cpp
+++ b/src/plugins/debugger/debuggerplugin.cpp
@@ -61,7 +61,6 @@
#include "snapshothandler.h"
#include "threadshandler.h"
#include "commonoptionspage.h"
-#include "gdb/startgdbserverdialog.h"
#include "analyzer/analyzerconstants.h"
#include "analyzer/analyzermanager.h"
@@ -734,7 +733,6 @@ public:
void updateDebugWithoutDeployMenu();
void startRemoteCdbSession();
- void startRemoteServerAndAttachToProcess();
void attachToRunningApplication();
void attachToUnstartedApplicationDialog();
void attachToQmlPort();
@@ -980,7 +978,6 @@ public:
QAction *m_startAction = 0;
QAction *m_debugWithoutDeployAction = 0;
QAction *m_startAndDebugApplicationAction = 0;
- QAction *m_startRemoteServerAction = 0;
QAction *m_attachToRunningApplication = 0;
QAction *m_attachToUnstartedApplication = 0;
QAction *m_attachToQmlPortAction = 0;
@@ -1506,10 +1503,6 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
act->setText(tr("Attach to Running Debug Server..."));
connect(act, &QAction::triggered, this, &StartApplicationDialog::attachToRemoteServer);
- act = m_startRemoteServerAction = new QAction(this);
- act->setText(tr("Start Debug Server Attached to Process..."));
- connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::startRemoteServerAndAttachToProcess);
-
act = m_attachToRunningApplication = new QAction(this);
act->setText(tr("Attach to Running Application..."));
connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToRunningApplication);
@@ -1583,11 +1576,6 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
cmd->setAttribute(Command::CA_Hide);
mstart->addAction(cmd, Constants::G_SPECIAL);
- cmd = ActionManager::registerAction(m_startRemoteServerAction,
- "Debugger.StartRemoteServer");
- cmd->setDescription(tr("Start Gdbserver"));
- mstart->addAction(cmd, Constants::G_SPECIAL);
-
if (m_startRemoteCdbAction) {
cmd = ActionManager::registerAction(m_startRemoteCdbAction,
"Debugger.AttachRemoteCdb");
@@ -1991,30 +1979,48 @@ void DebuggerPluginPrivate::startRemoteCdbSession()
debugger->startRunControl();
}
-void DebuggerPluginPrivate::startRemoteServerAndAttachToProcess()
+class RemoteAttachRunner : public DebuggerRunTool
{
- auto kitChooser = new DebuggerKitChooser(DebuggerKitChooser::AnyDebugging);
- auto dlg = new DeviceProcessesDialog(kitChooser, ICore::dialogParent());
- dlg->addAcceptButton(DeviceProcessesDialog::tr("&Attach to Process"));
- dlg->showAllDevices();
- if (dlg->exec() == QDialog::Rejected) {
- delete dlg;
- return;
+public:
+ RemoteAttachRunner(RunControl *runControl, Kit *kit, int pid)
+ : DebuggerRunTool(runControl, kit)
+ {
+ IDevice::ConstPtr device = DeviceKitInformation::device(kit);
+ setDisplayName("AttachToRunningProcess");
+
+ portsGatherer = new GdbServerPortsGatherer(runControl);
+ portsGatherer->setUseGdbServer(true);
+ portsGatherer->setUseQmlServer(false);
+ portsGatherer->setDevice(device);
+
+ auto gdbServer = new GdbServerRunner(runControl, portsGatherer);
+ gdbServer->setUseMulti(false);
+ gdbServer->addStartDependency(portsGatherer);
+ gdbServer->setDevice(device);
+ gdbServer->setAttachPid(ProcessHandle(pid));
+
+ addStartDependency(gdbServer);
+
+ setStartMode(AttachToRemoteProcess);
+ setCloseMode(DetachAtClose);
+
+ // setInferiorExecutable(localExecutable);
+ setUseContinueInsteadOfRun(true);
+ setContinueAfterAttach(false);
}
- dlg->setAttribute(Qt::WA_DeleteOnClose);
- Kit *kit = kitChooser->currentKit();
- QTC_ASSERT(kit, return);
- IDevice::ConstPtr device = DeviceKitInformation::device(kit);
- QTC_ASSERT(device, return);
+ void start() final
+ {
+ setRemoteChannel(portsGatherer->gdbServerChannel());
+ DebuggerRunTool::start();
+ }
- GdbServerStarter *starter = new GdbServerStarter(dlg, true);
- starter->run();
-}
+ GdbServerPortsGatherer *portsGatherer;
+};
void DebuggerPluginPrivate::attachToRunningApplication()
{
- auto kitChooser = new DebuggerKitChooser(DebuggerKitChooser::LocalDebugging);
+ auto kitChooser = new DebuggerKitChooser(DebuggerKitChooser::AnyDebugging);
auto dlg = new DeviceProcessesDialog(kitChooser, ICore::dialogParent());
dlg->addAcceptButton(DeviceProcessesDialog::tr("&Attach to Process"));
@@ -2030,11 +2036,14 @@ void DebuggerPluginPrivate::attachToRunningApplication()
IDevice::ConstPtr device = DeviceKitInformation::device(kit);
QTC_ASSERT(device, return);
+ DeviceProcessItem process = dlg->currentProcess();
+
if (device->type() == PE::DESKTOP_DEVICE_TYPE) {
- attachToRunningProcess(kit, dlg->currentProcess(), false);
+ attachToRunningProcess(kit, process, false);
} else {
- GdbServerStarter *starter = new GdbServerStarter(dlg, true);
- starter->run();
+ auto runControl = new RunControl(nullptr, ProjectExplorer::Constants::DEBUG_RUN_MODE);
+ auto debugger = new RemoteAttachRunner(runControl, kit, process.pid);
+ debugger->startRunControl();
}
}
diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp
index b16a94b4f1e..4b93b87cf4b 100644
--- a/src/plugins/debugger/debuggerruncontrol.cpp
+++ b/src/plugins/debugger/debuggerruncontrol.cpp
@@ -937,6 +937,8 @@ GdbServerPortsGatherer::GdbServerPortsGatherer(RunControl *runControl)
this, &RunWorker::reportFailure);
connect(&m_portsGatherer, &DeviceUsedPortsGatherer::portListReady,
this, &GdbServerPortsGatherer::handlePortListReady);
+
+ m_device = runControl->device();
}
GdbServerPortsGatherer::~GdbServerPortsGatherer()
@@ -945,26 +947,31 @@ GdbServerPortsGatherer::~GdbServerPortsGatherer()
QString GdbServerPortsGatherer::gdbServerChannel() const
{
- const QString host = device()->sshParameters().host;
+ const QString host = m_device->sshParameters().host;
return QString("%1:%2").arg(host).arg(m_gdbServerPort.number());
}
QUrl GdbServerPortsGatherer::qmlServer() const
{
- QUrl server = device()->toolControlChannel(IDevice::QmlControlChannel);
+ QUrl server = m_device->toolControlChannel(IDevice::QmlControlChannel);
server.setPort(m_qmlServerPort.number());
return server;
}
+void GdbServerPortsGatherer::setDevice(IDevice::ConstPtr device)
+{
+ m_device = device;
+}
+
void GdbServerPortsGatherer::start()
{
appendMessage(tr("Checking available ports..."), NormalMessageFormat);
- m_portsGatherer.start(device());
+ m_portsGatherer.start(m_device);
}
void GdbServerPortsGatherer::handlePortListReady()
{
- Utils::PortList portList = device()->freePorts();
+ Utils::PortList portList = m_device->freePorts();
appendMessage(tr("Found %n free ports.", nullptr, portList.count()), NormalMessageFormat);
if (m_useGdbServer) {
m_gdbServerPort = m_portsGatherer.getNextFreePort(&portList);
@@ -990,19 +997,38 @@ GdbServerRunner::GdbServerRunner(RunControl *runControl, GdbServerPortsGatherer
: SimpleTargetRunner(runControl), m_portsGatherer(portsGatherer)
{
setDisplayName("GdbServerRunner");
+ if (runControl->runnable().is<StandardRunnable>())
+ m_runnable = runControl->runnable().as<StandardRunnable>();
}
GdbServerRunner::~GdbServerRunner()
{
}
+void GdbServerRunner::setRunnable(const StandardRunnable &runnable)
+{
+ m_runnable = runnable;
+}
+
+void GdbServerRunner::setUseMulti(bool on)
+{
+ m_useMulti = on;
+}
+
+void GdbServerRunner::setAttachPid(ProcessHandle pid)
+{
+ m_pid = pid;
+}
+
void GdbServerRunner::start()
{
QTC_ASSERT(m_portsGatherer, reportFailure(); return);
- StandardRunnable r = runnable().as<StandardRunnable>();
- QStringList args = QtcProcess::splitArgs(r.commandLineArguments, OsTypeLinux);
- QString command;
+ StandardRunnable gdbserver;
+ gdbserver.environment = m_runnable.environment;
+ gdbserver.workingDirectory = m_runnable.workingDirectory;
+
+ QStringList args = QtcProcess::splitArgs(m_runnable.commandLineArguments, OsTypeLinux);
const bool isQmlDebugging = m_portsGatherer->useQmlServer();
const bool isCppDebugging = m_portsGatherer->useGdbServer();
@@ -1011,21 +1037,24 @@ void GdbServerRunner::start()
args.prepend(QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlDebuggerServices,
m_portsGatherer->qmlServerPort()));
}
-
if (isQmlDebugging && !isCppDebugging) {
- command = r.executable;
+ gdbserver.executable = m_runnable.executable; // FIXME: Case should not happen?
} else {
- command = device()->debugServerPath();
- if (command.isEmpty())
- command = "gdbserver";
+ gdbserver.executable = device()->debugServerPath();
+ if (gdbserver.executable.isEmpty())
+ gdbserver.executable = "gdbserver";
args.clear();
- args.append(QString("--multi"));
+ if (m_useMulti)
+ args.append("--multi");
+ if (m_pid.isValid())
+ args.append("--attach");
args.append(QString(":%1").arg(m_portsGatherer->gdbServerPort().number()));
+ if (m_pid.isValid())
+ args.append(QString::number(m_pid.pid()));
}
- r.executable = command;
- r.commandLineArguments = QtcProcess::joinArgs(args, OsTypeLinux);
+ gdbserver.commandLineArguments = QtcProcess::joinArgs(args, OsTypeLinux);
- setRunnable(r);
+ SimpleTargetRunner::setRunnable(gdbserver);
appendMessage(tr("Starting gdbserver..."), NormalMessageFormat);
diff --git a/src/plugins/debugger/debuggerruncontrol.h b/src/plugins/debugger/debuggerruncontrol.h
index 4f17a23adad..50d2ed4b986 100644
--- a/src/plugins/debugger/debuggerruncontrol.h
+++ b/src/plugins/debugger/debuggerruncontrol.h
@@ -161,6 +161,8 @@ public:
Utils::Port qmlServerPort() const { return m_qmlServerPort; }
QUrl qmlServer() const;
+ void setDevice(ProjectExplorer::IDevice::ConstPtr device);
+
private:
void start() override;
void handlePortListReady();
@@ -170,6 +172,7 @@ private:
bool m_useQmlServer = false;
Utils::Port m_gdbServerPort;
Utils::Port m_qmlServerPort;
+ ProjectExplorer::IDevice::ConstPtr m_device;
};
class DEBUGGER_EXPORT GdbServerRunner : public ProjectExplorer::SimpleTargetRunner
@@ -179,12 +182,20 @@ class DEBUGGER_EXPORT GdbServerRunner : public ProjectExplorer::SimpleTargetRunn
public:
explicit GdbServerRunner(ProjectExplorer::RunControl *runControl,
GdbServerPortsGatherer *portsGatherer);
+
~GdbServerRunner();
+ void setRunnable(const ProjectExplorer::StandardRunnable &runnable);
+ void setUseMulti(bool on);
+ void setAttachPid(Utils::ProcessHandle pid);
+
private:
void start() override;
GdbServerPortsGatherer *m_portsGatherer;
+ ProjectExplorer::StandardRunnable m_runnable;
+ Utils::ProcessHandle m_pid;
+ bool m_useMulti = true;
};
extern DEBUGGER_EXPORT const char GdbServerRunnerWorkerId[];
diff --git a/src/plugins/debugger/gdb/gdb.pri b/src/plugins/debugger/gdb/gdb.pri
index 4e0883fa034..c6678d127d0 100644
--- a/src/plugins/debugger/gdb/gdb.pri
+++ b/src/plugins/debugger/gdb/gdb.pri
@@ -1,8 +1,6 @@
HEADERS += \
- $$PWD/gdbengine.h \
- $$PWD/startgdbserverdialog.h
+ $$PWD/gdbengine.h
SOURCES += \
$$PWD/gdbengine.cpp \
- $$PWD/gdboptionspage.cpp \
- $$PWD/startgdbserverdialog.cpp
+ $$PWD/gdboptionspage.cpp
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index f4526977e31..ca46e3e2170 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -538,7 +538,7 @@ void GdbEngine::handleAsyncOutput(const QString &asyncClass, const GdbMi &result
// symbols-loaded="0",thread-group="i1"
QString id = result["id"].data();
if (!id.isEmpty())
- showStatusMessage(tr("Library %1 loaded").arg(id), 1000);
+ showStatusMessage(tr("Library %1 loaded.").arg(id), 1000);
progressPing();
Module module;
module.startAddress = 0;
@@ -553,7 +553,7 @@ void GdbEngine::handleAsyncOutput(const QString &asyncClass, const GdbMi &result
// host-name="/usr/lib/libdrm.so.2"
QString id = result["id"].data();
progressPing();
- showStatusMessage(tr("Library %1 unloaded").arg(id), 1000);
+ showStatusMessage(tr("Library %1 unloaded.").arg(id), 1000);
} else if (asyncClass == "thread-group-added") {
// 7.1-symbianelf has "{id="i1"}"
} else if (asyncClass == "thread-group-started") {
@@ -563,13 +563,13 @@ void GdbEngine::handleAsyncOutput(const QString &asyncClass, const GdbMi &result
progressPing();
// 7.1.50 has thread-group-started,id="i1",pid="3529"
QString id = result["id"].data();
- showStatusMessage(tr("Thread group %1 created").arg(id), 1000);
+ showStatusMessage(tr("Thread group %1 created.").arg(id), 1000);
notifyInferiorPid(result["pid"].toProcessHandle());
handleThreadGroupCreated(result);
} else if (asyncClass == "thread-created") {
//"{id="1",group-id="28902"}"
QString id = result["id"].data();
- showStatusMessage(tr("Thread %1 created").arg(id), 1000);
+ showStatusMessage(tr("Thread %1 created.").arg(id), 1000);
ThreadData thread;
thread.id = ThreadId(id.toLong());
thread.groupId = result["group-id"].data();
@@ -577,18 +577,18 @@ void GdbEngine::handleAsyncOutput(const QString &asyncClass, const GdbMi &result
} else if (asyncClass == "thread-group-exited") {
// Archer has "{id="28902"}"
QString id = result["id"].data();
- showStatusMessage(tr("Thread group %1 exited").arg(id), 1000);
+ showStatusMessage(tr("Thread group %1 exited.").arg(id), 1000);
handleThreadGroupExited(result);
} else if (asyncClass == "thread-exited") {
//"{id="1",group-id="28902"}"
QString id = result["id"].data();
QString groupid = result["group-id"].data();
- showStatusMessage(tr("Thread %1 in group %2 exited")
+ showStatusMessage(tr("Thread %1 in group %2 exited.")
.arg(id).arg(groupid), 1000);
threadsHandler()->removeThread(ThreadId(id.toLong()));
} else if (asyncClass == "thread-selected") {
QString id = result["id"].data();
- showStatusMessage(tr("Thread %1 selected").arg(id), 1000);
+ showStatusMessage(tr("Thread %1 selected.").arg(id), 1000);
//"{id="2"}"
} else if (asyncClass == "breakpoint-modified") {
// New in FSF gdb since 2011-04-27.
@@ -813,7 +813,7 @@ void GdbEngine::runCommand(const DebuggerCommand &command)
return;
}
if (state() == InferiorRunOk) {
- showStatusMessage(tr("Stopping temporarily"), 1000);
+ showStatusMessage(tr("Stopping temporarily."), 1000);
m_onStop.append(cmd, wantContinue);
requestInterruptInferior();
return;
@@ -896,15 +896,15 @@ void GdbEngine::commandTimeout()
int timeOut = m_commandTimer.interval();
//m_commandTimer.stop();
const QString msg = tr("The gdb process has not responded "
- "to a command within %n second(s). This could mean it is stuck "
+ "to a command within %n seconds. This could mean it is stuck "
"in an endless loop or taking longer than expected to perform "
"the operation.\nYou can choose between waiting "
"longer or aborting debugging.", 0, timeOut / 1000);
QMessageBox *mb = showMessageBox(QMessageBox::Critical,
- tr("GDB not responding"), msg,
+ tr("GDB Not Responding"), msg,
QMessageBox::Ok | QMessageBox::Cancel);
- mb->button(QMessageBox::Cancel)->setText(tr("Give GDB more time"));
- mb->button(QMessageBox::Ok)->setText(tr("Stop debugging"));
+ mb->button(QMessageBox::Cancel)->setText(tr("Give GDB More Time"));
+ mb->button(QMessageBox::Ok)->setText(tr("Stop Debugging"));
if (mb->exec() == QMessageBox::Ok) {
showMessage("KILLING DEBUGGER AS REQUESTED BY USER");
// This is an undefined state, so we just pull the emergency brake.
@@ -944,8 +944,8 @@ void GdbEngine::handleResultRecord(DebuggerResponse *response)
// with helpers enabled. In this case we get a second response with
// msg="Cannot find new threads: generic error"
showMessage("APPLYING WORKAROUND #1");
- AsynchronousMessageBox::critical(tr("Executable failed"), msg);
- showStatusMessage(tr("Process failed to start"));
+ AsynchronousMessageBox::critical(tr("Executable Failed"), msg);
+ showStatusMessage(tr("Process failed to start."));
//shutdown();
notifyInferiorIll();
} else if (msg == "\"finish\" not meaningful in the outermost frame.") {
@@ -968,7 +968,7 @@ void GdbEngine::handleResultRecord(DebuggerResponse *response)
//notifyInferiorIll();
//showStatusMessage(tr("Executable failed: %1").arg(msg));
//shutdown();
- //AsynchronousMessageBox::critical(tr("Executable failed"), msg);
+ //AsynchronousMessageBox::critical(tr("Executable Failed"), msg);
} else if (msg.contains("Cannot insert breakpoint")) {
// For breakpoints set by address to non-existent addresses we
// might get something like "6^error,msg="Warning:\nCannot insert
@@ -981,7 +981,7 @@ void GdbEngine::handleResultRecord(DebuggerResponse *response)
// long as the breakpoints are enabled.
// FIXME: Should we silently disable the offending breakpoints?
showMessage("APPLYING WORKAROUND #5");
- AsynchronousMessageBox::critical(tr("Setting breakpoints failed"), msg);
+ AsynchronousMessageBox::critical(tr("Setting Breakpoints Failed"), msg);
QTC_CHECK(state() == InferiorRunOk);
notifyInferiorSpontaneousStop();
notifyEngineIll();
@@ -1155,7 +1155,7 @@ void GdbEngine::handleExecuteJumpToLine(const DebuggerResponse &response)
notifyInferiorRunOk(); // Only needed for gdb < 7.0.
} else if (response.resultClass == ResultError) {
// Could be "Unreasonable jump request" or similar.
- QString out = tr("Cannot jump. Stopped");
+ QString out = tr("Cannot jump. Stopped.");
QString msg = response.data["msg"].data();
if (!msg.isEmpty())
out += ". " + msg;
@@ -1163,7 +1163,7 @@ void GdbEngine::handleExecuteJumpToLine(const DebuggerResponse &response)
notifyInferiorRunFailed();
} else if (response.resultClass == ResultDone) {
// This happens on old gdb. Trigger the effect of a '*stopped'.
- showStatusMessage(tr("Jumped. Stopped"));
+ showStatusMessage(tr("Jumped. Stopped."));
notifyInferiorSpontaneousStop();
handleStop2(response.data);
}
@@ -1182,7 +1182,7 @@ void GdbEngine::handleExecuteRunToLine(const DebuggerResponse &response)
//>~"testArray () at ../simple/app.cpp:241\n"
//>~"241\t s[1] = \"b\";\n"
//>122^done
- showStatusMessage(tr("Target line hit. Stopped"));
+ showStatusMessage(tr("Target line hit, and therefore stopped."));
notifyInferiorRunOk();
}
}
@@ -1230,7 +1230,7 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
msg = tr("Application exited after receiving signal %1")
.arg(data["signal-name"].toString());
} else {
- msg = tr("Application exited normally");
+ msg = tr("Application exited normally.");
}
// Only show the message. Ramp-down will be triggered by -thread-group-exited.
showStatusMessage(msg);
@@ -1330,11 +1330,12 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
notifyInferiorStopOk();
} else if (state() == EngineRunRequested) {
// This is gdb 7+'s initial *stopped in response to attach that
- // appears before the ^done is seen.
+ // appears before the ^done is seen for local setups.
notifyEngineRunAndInferiorStopOk();
- if (terminal())
+ if (terminal()) {
continueInferiorInternal();
- return;
+ return;
+ }
} else {
QTC_CHECK(false);
}
@@ -1742,7 +1743,7 @@ void GdbEngine::handleInferiorShutdown(const DebuggerResponse &response)
notifyInferiorShutdownOk();
return;
}
- AsynchronousMessageBox::critical(tr("Failed to shut down application"),
+ AsynchronousMessageBox::critical(tr("Failed to Shut Down Application"),
msgInferiorStopFailed(msg));
notifyInferiorShutdownFailed();
}
@@ -1811,7 +1812,7 @@ void GdbEngine::handleThreadGroupExited(const GdbMi &result)
static QString msgNoGdbBinaryForToolChain(const Abi &tc)
{
- return GdbEngine::tr("There is no GDB binary available for binaries in format \"%1\"")
+ return GdbEngine::tr("There is no GDB binary available for binaries in format \"%1\".")
.arg(tc.toString());
}
@@ -3933,8 +3934,8 @@ void GdbEngine::loadInitScript()
runCommand({"source " + script});
} else {
AsynchronousMessageBox::warning(
- tr("Cannot find debugger initialization script"),
- tr("The debugger settings point to a script file at \"%1\" "
+ tr("Cannot Find Debugger Initialization Script"),
+ tr("The debugger settings point to a script file at \"%1\", "
"which is not accessible. If a script file is not needed, "
"consider clearing that entry to avoid this warning."
).arg(script));
@@ -4030,7 +4031,7 @@ void GdbEngine::handleAdapterStartFailed(const QString &msg, Id settingsIdHint)
CHECK_STATE(EngineSetupOk);
showMessage("ADAPTER START FAILED");
if (!msg.isEmpty() && !Internal::isTestRun()) {
- const QString title = tr("Adapter start failed");
+ const QString title = tr("Adapter Start Failed");
if (!settingsIdHint.isValid()) {
ICore::showWarningWithOptions(title, msg);
} else {
@@ -4125,7 +4126,7 @@ void GdbEngine::notifyInferiorSetupFailedHelper(const QString &msg)
return; // Adapter crashed meanwhile, so this notification is meaningless.
}
showMessage("INFERIOR START FAILED");
- AsynchronousMessageBox::critical(tr("Failed to start application"), msg);
+ AsynchronousMessageBox::critical(tr("Failed to Start Application"), msg);
notifyInferiorSetupFailed();
}
@@ -4196,17 +4197,17 @@ QString GdbEngine::msgInferiorStopFailed(const QString &why)
QString GdbEngine::msgInferiorSetupOk()
{
- return tr("Application started");
+ return tr("Application started.");
}
QString GdbEngine::msgInferiorRunOk()
{
- return tr("Application running");
+ return tr("Application running.");
}
QString GdbEngine::msgAttachedToStoppedInferior()
{
- return tr("Attached to stopped application");
+ return tr("Attached to stopped application.");
}
QString GdbEngine::msgConnectRemoteServerFailed(const QString &why)
@@ -4267,7 +4268,11 @@ void GdbEngine::setupInferior()
const DebuggerRunParameters &rp = runParameters();
- if (isAttachEngine()) {
+ if (rp.startMode == AttachToRemoteProcess) {
+
+ notifyInferiorSetupOk();
+
+ } else if (isAttachEngine()) {
// Task 254674 does not want to remove them
//qq->breakHandler()->removeAllBreakpoints();
handleInferiorPrepared();
@@ -4377,7 +4382,6 @@ void GdbEngine::setupInferior()
} else if (isPlainEngine()) {
setEnvironmentVariables();
- const DebuggerRunParameters &rp = runParameters();
if (!rp.inferior.workingDirectory.isEmpty())
runCommand({"cd " + rp.inferior.workingDirectory});
if (!rp.inferior.commandLineArguments.isEmpty()) {
@@ -4395,9 +4399,18 @@ void GdbEngine::runEngine()
{
CHECK_STATE(EngineRunRequested);
- if (isAttachEngine()) {
+ const DebuggerRunParameters &rp = runParameters();
+
+ if (rp.startMode == AttachToRemoteProcess) {
+
+ notifyEngineRunAndInferiorStopOk();
- const qint64 pid = runParameters().attachPID.pid();
+ QString channel = rp.remoteChannel;
+ runCommand({"target remote " + channel});
+
+ } else if (isAttachEngine()) {
+
+ const qint64 pid = rp.attachPID.pid();
showStatusMessage(tr("Attaching to process %1.").arg(pid));
runCommand({"attach " + QString::number(pid),
[this](const DebuggerResponse &r) { handleAttach(r); }});
@@ -4454,12 +4467,13 @@ void GdbEngine::handleAttach(const DebuggerResponse &response)
// Happens e.g. for "Attach to unstarted application"
// We will get a '*stopped' later that we'll interpret as 'spontaneous'
// So acknowledge the current state and put a delayed 'continue' in the pipe.
- showMessage(tr("Attached to running application"), StatusBar);
+ showMessage(tr("Attached to running application."), StatusBar);
notifyEngineRunAndInferiorRunOk();
} else {
// InferiorStopOk, e.g. for "Attach to running application".
// The *stopped came in between sending the 'attach' and
// receiving its '^done'.
+ notifyEngineRunAndInferiorStopOk();
if (runParameters().continueAfterAttach)
continueInferiorInternal();
}
@@ -4528,7 +4542,7 @@ void GdbEngine::interruptInferior2()
if (!ok) {
// FIXME: Extra state needed?
showMessage("NOTE: INFERIOR STOP NOT POSSIBLE");
- showStatusMessage(tr("Interrupting not possible"));
+ showStatusMessage(tr("Interrupting not possible."));
notifyInferiorRunOk();
}
}
@@ -4595,11 +4609,11 @@ void GdbEngine::handleFileExecAndSymbols(const DebuggerResponse &response)
showMessage(tr("Symbols found."), StatusBar);
handleInferiorPrepared();
} else {
- QString msg = tr("No symbols found in core file <i>%1</i>.").arg(core)
+ QString msg = tr("No symbols found in the core file \"%1\".").arg(core)
+ ' ' + tr("This can be caused by a path length limitation "
"in the core file.")
- + ' ' + tr("Try to specify the binary using the "
- "<i>Debug->Start Debugging->Attach to Core</i> dialog.");
+ + ' ' + tr("Try to specify the binary in "
+ "Debug > Start Debugging > Attach to Core.");
notifyInferiorSetupFailedHelper(msg);
}
@@ -4663,6 +4677,7 @@ void GdbEngine::handleSetTargetAsync(const DebuggerResponse &response)
void GdbEngine::callTargetRemote()
{
+ CHECK_STATE(InferiorSetupRequested);
QString channel = runParameters().remoteChannel;
// Don't touch channels with explicitly set protocols.
diff --git a/src/plugins/debugger/gdb/startgdbserverdialog.cpp b/src/plugins/debugger/gdb/startgdbserverdialog.cpp
deleted file mode 100644
index a9596269ca5..00000000000
--- a/src/plugins/debugger/gdb/startgdbserverdialog.cpp
+++ /dev/null
@@ -1,234 +0,0 @@
-/****************************************************************************
-**
-** 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 "startgdbserverdialog.h"
-
-#include <debugger/debuggerengine.h>
-#include <debugger/debuggermainwindow.h>
-#include <debugger/debuggerplugin.h>
-#include <debugger/debuggerkitinformation.h>
-#include <debugger/debuggerruncontrol.h>
-
-#include <coreplugin/icore.h>
-#include <coreplugin/messagebox.h>
-#include <projectexplorer/kitchooser.h>
-#include <projectexplorer/devicesupport/deviceprocesslist.h>
-#include <projectexplorer/devicesupport/deviceprocessesdialog.h>
-#include <projectexplorer/devicesupport/deviceusedportsgatherer.h>
-#include <ssh/sshremoteprocessrunner.h>
-#include <utils/portlist.h>
-#include <utils/qtcassert.h>
-
-#include <QFileInfo>
-
-using namespace Core;
-using namespace ProjectExplorer;
-using namespace QSsh;
-using namespace Utils;
-
-
-namespace Debugger {
-namespace Internal {
-
-class StartGdbServerDialogPrivate
-{
-public:
- StartGdbServerDialogPrivate() : dialog(0), kit(0) {}
-
- DeviceProcessesDialog *dialog;
- bool attachToServer;
- DeviceProcessItem process;
- Kit *kit;
- IDevice::ConstPtr device;
-
- DeviceUsedPortsGatherer gatherer;
- SshRemoteProcessRunner runner;
-};
-
-GdbServerStarter::GdbServerStarter(DeviceProcessesDialog *dlg, bool attachAfterServerStart)
- : QObject(dlg)
-{
- d = new StartGdbServerDialogPrivate;
- d->dialog = dlg;
- d->kit = dlg->kitChooser()->currentKit();
- d->process = dlg->currentProcess();
- d->device = DeviceKitInformation::device(d->kit);
- d->attachToServer = attachAfterServerStart;
-}
-
-GdbServerStarter::~GdbServerStarter()
-{
- delete d;
-}
-
-void GdbServerStarter::handleRemoteError(const QString &errorMsg)
-{
- AsynchronousMessageBox::critical(tr("Remote Error"), errorMsg);
-}
-
-void GdbServerStarter::portGathererError(const QString &text)
-{
- logMessage(tr("Could not retrieve list of free ports:"));
- logMessage(text);
- logMessage(tr("Process aborted"));
-}
-
-void GdbServerStarter::run()
-{
- QTC_ASSERT(d->device, return);
- connect(&d->gatherer, &DeviceUsedPortsGatherer::error,
- this, &GdbServerStarter::portGathererError);
- connect(&d->gatherer, &DeviceUsedPortsGatherer::portListReady,
- this, &GdbServerStarter::portListReady);
- d->gatherer.start(d->device);
-}
-
-void GdbServerStarter::portListReady()
-{
- PortList ports = d->device->freePorts();
- const Port port = d->gatherer.getNextFreePort(&ports);
- if (!port.isValid()) {
- QTC_ASSERT(false, /**/);
- emit logMessage(tr("Process aborted"));
- return;
- }
-
- connect(&d->runner, &SshRemoteProcessRunner::connectionError,
- this, &GdbServerStarter::handleConnectionError);
- connect(&d->runner, &SshRemoteProcessRunner::processStarted,
- this, &GdbServerStarter::handleProcessStarted);
- connect(&d->runner, &SshRemoteProcessRunner::readyReadStandardOutput,
- this, &GdbServerStarter::handleProcessOutputAvailable);
- connect(&d->runner, &SshRemoteProcessRunner::readyReadStandardError,
- this, &GdbServerStarter::handleProcessErrorOutput);
- connect(&d->runner, &SshRemoteProcessRunner::processClosed,
- this, &GdbServerStarter::handleProcessClosed);
-
- QByteArray gdbServerPath = d->device->debugServerPath().toUtf8();
- if (gdbServerPath.isEmpty())
- gdbServerPath = "gdbserver";
- QByteArray cmd = gdbServerPath + " --attach :"
- + QByteArray::number(port.number()) + ' ' + QByteArray::number(d->process.pid);
- logMessage(tr("Running command: %1").arg(QString::fromLatin1(cmd)));
- d->runner.run(cmd, d->device->sshParameters());
-}
-
-void GdbServerStarter::handleConnectionError()
-{
- logMessage(tr("Connection error: %1").arg(d->runner.lastConnectionErrorString()));
-}
-
-void GdbServerStarter::handleProcessStarted()
-{
- logMessage(tr("Starting gdbserver..."));
-}
-
-void GdbServerStarter::handleProcessOutputAvailable()
-{
- logMessage(QString::fromUtf8(d->runner.readAllStandardOutput().trimmed()));
-}
-
-void GdbServerStarter::handleProcessErrorOutput()
-{
- const QByteArray ba = d->runner.readAllStandardError();
- logMessage(QString::fromUtf8(ba.trimmed()));
- // "Attached; pid = 16740"
- // "Listening on port 10000"
- foreach (const QByteArray &line, ba.split('\n')) {
- if (line.startsWith("Listening on port")) {
- const int port = line.mid(18).trimmed().toInt();
- logMessage(tr("Port %1 is now accessible.").arg(port));
- logMessage(tr("Server started on %1:%2")
- .arg(d->device->sshParameters().host).arg(port));
- if (d->attachToServer)
- attach(port);
- }
- }
-}
-
-void GdbServerStarter::attach(int port)
-{
- QString sysroot = SysRootKitInformation::sysRoot(d->kit).toString();
- QString binary;
- QString localExecutable;
- QString candidate = sysroot + d->process.exe;
- if (QFileInfo::exists(candidate))
- localExecutable = candidate;
- if (localExecutable.isEmpty()) {
- binary = d->process.cmdLine.section(QLatin1Char(' '), 0, 0);
- candidate = sysroot + QLatin1Char('/') + binary;
- if (QFileInfo::exists(candidate))
- localExecutable = candidate;
- }
- if (localExecutable.isEmpty()) {
- candidate = sysroot + QLatin1String("/usr/bin/") + binary;
- if (QFileInfo::exists(candidate))
- localExecutable = candidate;
- }
- if (localExecutable.isEmpty()) {
- candidate = sysroot + QLatin1String("/bin/") + binary;
- if (QFileInfo::exists(candidate))
- localExecutable = candidate;
- }
- if (localExecutable.isEmpty()) {
- AsynchronousMessageBox::warning(tr("Warning"),
- tr("Cannot find local executable for remote process \"%1\".")
- .arg(d->process.exe));
- return;
- }
-
- QList<Abi> abis = Abi::abisOfBinary(FileName::fromString(localExecutable));
- if (abis.isEmpty()) {
- AsynchronousMessageBox::warning(tr("Warning"),
- tr("Cannot find ABI for remote process \"%1\".")
- .arg(d->process.exe));
- return;
- }
-
- QString remoteChannel = QString("%1:%2").arg(d->device->sshParameters().host).arg(port);
-
- auto runControl = new RunControl(nullptr, ProjectExplorer::Constants::DEBUG_RUN_MODE);
- auto debugger = new DebuggerRunTool(runControl, d->kit);
- debugger->setRemoteChannel(remoteChannel);
- debugger->setRunControlName(tr("Remote: \"%1\"").arg(remoteChannel));
- debugger->setInferiorExecutable(localExecutable);
- debugger->setStartMode(AttachToRemoteServer);
- debugger->setCloseMode(KillAtClose);
-
- debugger->startRunControl();
-}
-
-void GdbServerStarter::handleProcessClosed(int status)
-{
- logMessage(tr("Process gdbserver finished. Status: %1").arg(status));
-}
-
-void GdbServerStarter::logMessage(const QString &line)
-{
- d->dialog->logMessage(line);
-}
-
-} // namespace Internal
-} // namespace Debugger
diff --git a/src/plugins/debugger/gdb/startgdbserverdialog.h b/src/plugins/debugger/gdb/startgdbserverdialog.h
deleted file mode 100644
index c90cefe7abc..00000000000
--- a/src/plugins/debugger/gdb/startgdbserverdialog.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/****************************************************************************
-**
-** 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>
-
-namespace ProjectExplorer { class DeviceProcessesDialog; }
-
-namespace Debugger {
-namespace Internal {
-
-class StartGdbServerDialogPrivate;
-
-class GdbServerStarter : public QObject
-{
- Q_OBJECT
-
-public:
- GdbServerStarter(ProjectExplorer::DeviceProcessesDialog *dlg,
- bool attachAfterServerStart);
- ~GdbServerStarter();
-
- void run();
-
-private:
- void handleRemoteError(const QString &errorMessage);
- void portGathererError(const QString &errorMessage);
- void portListReady();
-
- void handleProcessClosed(int);
- void handleProcessErrorOutput();
- void handleProcessOutputAvailable();
- void handleProcessStarted();
- void handleConnectionError();
-
- void attach(int port);
- void logMessage(const QString &line);
- StartGdbServerDialogPrivate *d;
-};
-
-} // namespace Internal
-} // namespace Debugger
diff --git a/src/plugins/genericprojectmanager/genericbuildconfiguration.cpp b/src/plugins/genericprojectmanager/genericbuildconfiguration.cpp
index 461232e4c87..cc20c2e8608 100644
--- a/src/plugins/genericprojectmanager/genericbuildconfiguration.cpp
+++ b/src/plugins/genericprojectmanager/genericbuildconfiguration.cpp
@@ -37,6 +37,8 @@
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
#include <projectexplorer/toolchain.h>
+#include <qtsupport/baseqtversion.h>
+#include <qtsupport/qtkitinformation.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/pathchooser.h>
@@ -196,6 +198,14 @@ BuildConfiguration::BuildType GenericBuildConfiguration::buildType() const
return Unknown;
}
+void GenericBuildConfiguration::addToEnvironment(Utils::Environment &env) const
+{
+ prependCompilerPathToEnvironment(env);
+ const QtSupport::BaseQtVersion *qt = QtSupport::QtKitInformation::qtVersion(target()->kit());
+ if (qt)
+ env.prependOrSetPath(qt->binPath().toString());
+}
+
////////////////////////////////////////////////////////////////////////////////////
// GenericBuildSettingsWidget
////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/plugins/genericprojectmanager/genericbuildconfiguration.h b/src/plugins/genericprojectmanager/genericbuildconfiguration.h
index 75f5ceef5d4..54e375e88f7 100644
--- a/src/plugins/genericprojectmanager/genericbuildconfiguration.h
+++ b/src/plugins/genericprojectmanager/genericbuildconfiguration.h
@@ -52,6 +52,8 @@ public:
BuildType buildType() const override;
+ void addToEnvironment(Utils::Environment &env) const final;
+
protected:
GenericBuildConfiguration(ProjectExplorer::Target *parent, GenericBuildConfiguration *source);
GenericBuildConfiguration(ProjectExplorer::Target *parent, Core::Id id);
diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp
index 705d9b9b967..bd2bbaac51d 100644
--- a/src/plugins/projectexplorer/buildconfiguration.cpp
+++ b/src/plugins/projectexplorer/buildconfiguration.cpp
@@ -33,7 +33,10 @@
#include "kit.h"
#include <projectexplorer/buildenvironmentwidget.h>
+#include <projectexplorer/kitinformation.h>
+#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectmacroexpander.h>
+#include <projectexplorer/target.h>
#include <extensionsystem/pluginmanager.h>
#include <coreplugin/idocument.h>
@@ -66,7 +69,7 @@ BuildConfiguration::BuildConfiguration(Target *target, Core::Id id) :
bsl->setDefaultDisplayName(tr("Clean"));
m_stepLists.append(bsl);
- emitEnvironmentChanged();
+ updateCacheAndEmitEnvironmentChanged();
connect(target, &Target::kitChanged,
this, &BuildConfiguration::handleKitUpdate);
@@ -88,7 +91,7 @@ BuildConfiguration::BuildConfiguration(Target *target, BuildConfiguration *sourc
// otherwise BuildStepFactories might reject to set up a BuildStep for us
// since we are not yet the derived class!
- emitEnvironmentChanged();
+ updateCacheAndEmitEnvironmentChanged();
connect(target, &Target::kitChanged,
this, &BuildConfiguration::handleKitUpdate);
@@ -168,7 +171,7 @@ bool BuildConfiguration::fromMap(const QVariantMap &map)
m_userEnvironmentChanges = Utils::EnvironmentItem::fromStringList(map.value(QLatin1String(USER_ENVIRONMENT_CHANGES_KEY)).toStringList());
m_buildDirectory = Utils::FileName::fromString(map.value(QLatin1String(BUILDDIRECTORY_KEY)).toString());
- emitEnvironmentChanged();
+ updateCacheAndEmitEnvironmentChanged();
qDeleteAll(m_stepLists);
m_stepLists.clear();
@@ -200,7 +203,7 @@ bool BuildConfiguration::fromMap(const QVariantMap &map)
return ProjectConfiguration::fromMap(map);
}
-void BuildConfiguration::emitEnvironmentChanged()
+void BuildConfiguration::updateCacheAndEmitEnvironmentChanged()
{
Utils::Environment env = baseEnvironment();
env.modify(userEnvironmentChanges());
@@ -212,7 +215,7 @@ void BuildConfiguration::emitEnvironmentChanged()
void BuildConfiguration::handleKitUpdate()
{
- emitEnvironmentChanged();
+ updateCacheAndEmitEnvironmentChanged();
}
void BuildConfiguration::emitBuildDirectoryChanged()
@@ -238,8 +241,8 @@ Utils::Environment BuildConfiguration::baseEnvironment() const
Utils::Environment result;
if (useSystemEnvironment())
result = Utils::Environment::systemEnvironment();
- target()->kit()->addToEnvironment(result);
addToEnvironment(result);
+ target()->kit()->addToEnvironment(result);
return result;
}
@@ -261,7 +264,7 @@ void BuildConfiguration::setUseSystemEnvironment(bool b)
if (useSystemEnvironment() == b)
return;
m_clearSystemEnvironment = !b;
- emitEnvironmentChanged();
+ updateCacheAndEmitEnvironmentChanged();
}
void BuildConfiguration::addToEnvironment(Utils::Environment &env) const
@@ -284,7 +287,7 @@ void BuildConfiguration::setUserEnvironmentChanges(const QList<Utils::Environmen
if (m_userEnvironmentChanges == diff)
return;
m_userEnvironmentChanges = diff;
- emitEnvironmentChanged();
+ updateCacheAndEmitEnvironmentChanged();
}
void BuildConfiguration::cloneSteps(BuildConfiguration *source)
@@ -330,6 +333,25 @@ bool BuildConfiguration::isActive() const
return target()->isActive() && target()->activeBuildConfiguration() == this;
}
+/*!
+ * Helper function that prepends the directory containing the C++ toolchain to
+ * PATH. This is used to in build configurations targeting broken build systems
+ * to provide hints about which compiler to use.
+ */
+void BuildConfiguration::prependCompilerPathToEnvironment(Utils::Environment &env) const
+{
+ const ToolChain *tc
+ = ToolChainKitInformation::toolChain(target()->kit(),
+ ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+
+ if (!tc)
+ return;
+
+ const Utils::FileName compilerDir = tc->compilerCommand().parentDir();
+ if (!compilerDir.isEmpty())
+ env.prependOrSetPath(compilerDir.toString());
+}
+
///
// IBuildConfigurationFactory
///
diff --git a/src/plugins/projectexplorer/buildconfiguration.h b/src/plugins/projectexplorer/buildconfiguration.h
index cc30d2ba44d..109cc4481ef 100644
--- a/src/plugins/projectexplorer/buildconfiguration.h
+++ b/src/plugins/projectexplorer/buildconfiguration.h
@@ -90,6 +90,8 @@ public:
bool isActive() const override;
+ void prependCompilerPathToEnvironment(Utils::Environment &env) const;
+
signals:
void environmentChanged();
void buildDirectoryChanged();
@@ -101,7 +103,7 @@ protected:
BuildConfiguration(Target *target, BuildConfiguration *source);
void cloneSteps(BuildConfiguration *source);
- void emitEnvironmentChanged();
+ void updateCacheAndEmitEnvironmentChanged();
private:
void handleKitUpdate();
diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp
index 884798ecf5e..2ed1a397e27 100644
--- a/src/plugins/projectexplorer/gcctoolchain.cpp
+++ b/src/plugins/projectexplorer/gcctoolchain.cpp
@@ -710,15 +710,16 @@ QList<HeaderPath> GccToolChain::systemHeaderPaths(const QStringList &cxxflags,
void GccToolChain::addCommandPathToEnvironment(const FileName &command, Environment &env)
{
- if (!command.isEmpty())
- env.prependOrSetPath(command.parentDir().toString());
+ const Utils::FileName compilerDir = command.parentDir();
+ if (!compilerDir.isEmpty())
+ env.prependOrSetPath(compilerDir.toString());
}
GccToolChain::GccToolChain(const GccToolChain &) = default;
void GccToolChain::addToEnvironment(Environment &env) const
{
- addCommandPathToEnvironment(m_compilerCommand, env);
+ Q_UNUSED(env);
}
FileNameList GccToolChain::suggestedMkspecList() const
diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp
index 679214925b3..3cc3625dfa7 100644
--- a/src/plugins/projectexplorer/projectexplorer.cpp
+++ b/src/plugins/projectexplorer/projectexplorer.cpp
@@ -2045,7 +2045,13 @@ void ProjectExplorerPluginPrivate::executeRunConfiguration(RunConfiguration *run
QTC_ASSERT(producer, return);
auto runControl = new RunControl(runConfiguration, runMode);
- (void) producer(runControl);
+
+ // A user needed interaction may have cancelled the run
+ // (by example asking for a process pid or server url).
+ if (!producer(runControl)) {
+ delete runControl;
+ return;
+ }
emit m_instance->aboutToExecuteProject(runConfiguration->target()->project(), runMode);
diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp
index 9e3d3339c7b..b56f1d683ea 100644
--- a/src/plugins/projectexplorer/runconfiguration.cpp
+++ b/src/plugins/projectexplorer/runconfiguration.cpp
@@ -1384,24 +1384,14 @@ bool Runnable::canReUseOutputPane(const Runnable &other) const
}
-// FIXME: Remove once ApplicationLauncher signalling does not depend on device.
-static bool isSynchronousLauncher(RunControl *runControl)
-{
- RunConfiguration *runConfig = runControl->runConfiguration();
- Target *target = runConfig ? runConfig->target() : nullptr;
- Kit *kit = target ? target->kit() : nullptr;
- Core::Id deviceId = DeviceTypeKitInformation::deviceTypeId(kit);
- return !deviceId.isValid() || deviceId == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE;
-}
-
-
// SimpleTargetRunner
SimpleTargetRunner::SimpleTargetRunner(RunControl *runControl)
: RunWorker(runControl)
{
setDisplayName("SimpleTargetRunner");
- m_runnable = runControl->runnable();
+ m_runnable = runControl->runnable(); // Default value. Can be overridden using setRunnable.
+ m_device = runControl->device(); // Default value. Can be overridden using setDevice.
}
void SimpleTargetRunner::start()
@@ -1409,7 +1399,8 @@ void SimpleTargetRunner::start()
m_stopReported = false;
m_launcher.disconnect(this);
- const bool isDesktop = isSynchronousLauncher(runControl());
+ const bool isDesktop = m_device.isNull()
+ || m_device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE;
const QString rawDisplayName = m_runnable.displayName();
const QString displayName = isDesktop
? QDir::toNativeSeparators(rawDisplayName)
@@ -1528,11 +1519,21 @@ void SimpleTargetRunner::onProcessError(QProcess::ProcessError error)
}
}
+IDevice::ConstPtr SimpleTargetRunner::device() const
+{
+ return m_device;
+}
+
void SimpleTargetRunner::setRunnable(const Runnable &runnable)
{
m_runnable = runnable;
}
+void SimpleTargetRunner::setDevice(const IDevice::ConstPtr &device)
+{
+ m_device = device;
+}
+
// RunWorkerPrivate
RunWorkerPrivate::RunWorkerPrivate(RunWorker *runWorker, RunControl *runControl)
diff --git a/src/plugins/projectexplorer/runconfiguration.h b/src/plugins/projectexplorer/runconfiguration.h
index f938f3a93d8..ebbf557d2a6 100644
--- a/src/plugins/projectexplorer/runconfiguration.h
+++ b/src/plugins/projectexplorer/runconfiguration.h
@@ -522,6 +522,9 @@ public:
void setRunnable(const Runnable &runnable);
+ void setDevice(const IDevice::ConstPtr &device);
+ IDevice::ConstPtr device() const;
+
protected:
void start() override;
void stop() override;
@@ -533,6 +536,7 @@ private:
ApplicationLauncher m_launcher;
Runnable m_runnable;
+ IDevice::ConstPtr m_device;
bool m_stopReported = false;
};
diff --git a/src/plugins/pythoneditor/pythoneditorplugin.cpp b/src/plugins/pythoneditor/pythoneditorplugin.cpp
index 29f55ad94dd..9290a2cd989 100644
--- a/src/plugins/pythoneditor/pythoneditorplugin.cpp
+++ b/src/plugins/pythoneditor/pythoneditorplugin.cpp
@@ -312,7 +312,10 @@ public:
if (!canHandle(parent))
return false;
PythonProject *project = static_cast<PythonProject *>(parent->project());
- return project->files(ProjectExplorer::Project::AllFiles).contains(scriptFromId(id));
+ const QString script = scriptFromId(id);
+ if (script.endsWith(".pyqtc"))
+ return false;
+ return project->files(ProjectExplorer::Project::AllFiles).contains(script);
}
bool canRestore(Target *parent, const QVariantMap &map) const override
@@ -475,8 +478,9 @@ void PythonProject::parseProject()
class PythonFileNode : public FileNode
{
public:
- PythonFileNode(const Utils::FileName &filePath, const QString &nodeDisplayName)
- : FileNode(filePath, FileType::Source, false)
+ PythonFileNode(const Utils::FileName &filePath, const QString &nodeDisplayName,
+ FileType fileType = FileType::Source)
+ : FileNode(filePath, fileType, false)
, m_displayName(nodeDisplayName)
{}
@@ -494,7 +498,8 @@ void PythonProject::refresh()
auto newRoot = new PythonProjectNode(this);
for (const QString &f : m_files) {
const QString displayName = baseDir.relativeFilePath(f);
- newRoot->addNestedNode(new PythonFileNode(FileName::fromString(f), displayName));
+ FileType fileType = f.endsWith(".pyqtc") ? FileType::Project : FileType::Source;
+ newRoot->addNestedNode(new PythonFileNode(FileName::fromString(f), displayName, fileType));
}
setRootProjectNode(newRoot);
@@ -560,31 +565,11 @@ Project::RestoreResult PythonProject::fromMap(const QVariantMap &map, QString *e
{
Project::RestoreResult res = Project::fromMap(map, errorMessage);
if (res == RestoreResult::Ok) {
+ refresh();
+
Kit *defaultKit = KitManager::defaultKit();
if (!activeTarget() && defaultKit)
addTarget(createTarget(defaultKit));
-
- refresh();
-
- QList<Target *> targetList = targets();
- foreach (Target *t, targetList) {
- const QList<RunConfiguration *> runConfigs = t->runConfigurations();
- foreach (const QString &file, m_files) {
- // skip the 'project' file
- if (file.endsWith(".pyqtc"))
- continue;
- const Id id = idFromScript(file);
- bool alreadyPresent = false;
- foreach (RunConfiguration *runCfg, runConfigs) {
- if (runCfg->id() == id) {
- alreadyPresent = true;
- break;
- }
- }
- if (!alreadyPresent)
- t->addRunConfiguration(IRunConfigurationFactory::createHelper<PythonRunConfiguration>(t, id));
- }
- }
}
return res;
diff --git a/src/plugins/qmakeandroidsupport/androidqmakebuildconfigurationfactory.cpp b/src/plugins/qmakeandroidsupport/androidqmakebuildconfigurationfactory.cpp
index 805624c95f6..1de61ae19f1 100644
--- a/src/plugins/qmakeandroidsupport/androidqmakebuildconfigurationfactory.cpp
+++ b/src/plugins/qmakeandroidsupport/androidqmakebuildconfigurationfactory.cpp
@@ -129,7 +129,7 @@ void AndroidQmakeBuildConfiguration::manifestSaved()
if (m_androidNdkPlatform == androidNdkPlatform)
return;
- emitEnvironmentChanged();
+ updateCacheAndEmitEnvironmentChanged();
QMakeStep *qs = qmakeStep();
if (!qs)
diff --git a/src/plugins/qmakeandroidsupport/androidqmakebuildconfigurationfactory.h b/src/plugins/qmakeandroidsupport/androidqmakebuildconfigurationfactory.h
index 25783a05cb8..55e68bf7196 100644
--- a/src/plugins/qmakeandroidsupport/androidqmakebuildconfigurationfactory.h
+++ b/src/plugins/qmakeandroidsupport/androidqmakebuildconfigurationfactory.h
@@ -57,7 +57,7 @@ public:
void addToEnvironment(Utils::Environment &env) const override;
void manifestSaved();
- using BuildConfiguration::emitEnvironmentChanged;
+ using BuildConfiguration::updateCacheAndEmitEnvironmentChanged;
private:
mutable QString m_androidNdkPlatform;
};
diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp
index e95fcdd86ca..ec014c8fa9a 100644
--- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp
@@ -756,6 +756,14 @@ BuildConfiguration::BuildType QmakeBuildConfiguration::buildType() const
return Release;
}
+void QmakeBuildConfiguration::addToEnvironment(Environment &env) const
+{
+ prependCompilerPathToEnvironment(env);
+ const BaseQtVersion *qt = QtKitInformation::qtVersion(target()->kit());
+ if (qt)
+ env.prependOrSetPath(qt->binPath().toString());
+}
+
QmakeBuildConfiguration::LastKitState::LastKitState() { }
QmakeBuildConfiguration::LastKitState::LastKitState(Kit *k)
diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h
index c526760c62e..87afc6c9376 100644
--- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h
+++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h
@@ -99,6 +99,8 @@ public:
BuildType buildType() const override;
+ void addToEnvironment(Utils::Environment &env) const override;
+
void emitProFileEvaluateNeeded();
signals:
diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.cpp
index 881903d3c04..bfa6b2b0d53 100644
--- a/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.cpp
@@ -160,6 +160,11 @@ const DesignerActionManager &DesignerActionManagerView::designerActionManager()
return m_designerActionManager;
}
+void DesignerActionManagerView::emitSelectionChanged()
+{
+ emit selectionChanged(!selectedModelNodes().isEmpty(), singleSelectedModelNode().isRootNode());
+}
+
/* We should consider compressing this. */
/* One update every 100ms should be enough. */
void DesignerActionManagerView::setupContext()
diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.h b/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.h
index fd705120c5f..e1e926639f6 100644
--- a/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.h
+++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.h
@@ -68,6 +68,7 @@ public:
void setDesignerActionList(const QList<ActionInterface* > &designerActionList);
DesignerActionManager &designerActionManager();
const DesignerActionManager &designerActionManager() const;
+ void emitSelectionChanged();
signals:
void selectionChanged(bool itemsSelected, bool rootItemIsSelected);
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.cpp
index 52d548c7ba9..d1afece6d02 100644
--- a/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.cpp
@@ -144,9 +144,9 @@ void FormEditorGraphicsView::keyReleaseEvent(QKeyEvent *event)
void FormEditorGraphicsView::paintEvent(QPaintEvent *event)
{
- if (!m_blockPainting) {
- QGraphicsView::paintEvent(event);
- } else {
+ QGraphicsView::paintEvent(event);
+
+ if (m_blockPainting) {
QWidget::paintEvent(event);
QPainter painter(viewport());
painter.drawPixmap(0, 0, m_lastUpdate);
diff --git a/src/plugins/qmldesigner/components/integration/designdocument.cpp b/src/plugins/qmldesigner/components/integration/designdocument.cpp
index 822156f53a8..f83af521cb8 100644
--- a/src/plugins/qmldesigner/components/integration/designdocument.cpp
+++ b/src/plugins/qmldesigner/components/integration/designdocument.cpp
@@ -45,6 +45,7 @@
#include <qtsupport/qtsupportconstants.h>
#include <qtsupport/qtversionmanager.h>
#include <coreplugin/idocument.h>
+#include <coreplugin/editormanager/editormanager.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
@@ -605,6 +606,13 @@ RewriterView *DesignDocument::rewriterView() const
void DesignDocument::setEditor(Core::IEditor *editor)
{
m_textEditor = editor;
+ // if the user closed the file explicit we do not want to do anything with it anymore
+ connect(Core::EditorManager::instance(), &Core::EditorManager::editorAboutToClose,
+ this, [this](Core::IEditor *editor) {
+ if (m_textEditor.data() == editor)
+ m_textEditor.clear();
+ });
+
connect(editor->document(), &Core::IDocument::filePathChanged,
this, &DesignDocument::updateFileName);
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp
index a38a6b93aff..4cad2d08cc0 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp
@@ -194,7 +194,8 @@ void PropertyEditorView::changeValue(const QString &name)
if (qmlObjectNode.modelNode().metaInfo().propertyTypeName(propertyName) == "QUrl"
|| qmlObjectNode.modelNode().metaInfo().propertyTypeName(propertyName) == "url") { //turn absolute local file paths into relative paths
QString filePath = castedValue.toUrl().toString();
- if (QFileInfo(filePath).exists() && QFileInfo(filePath).isAbsolute()) {
+ QFileInfo fi(filePath);
+ if (fi.exists() && fi.isAbsolute()) {
QDir fileDir(QFileInfo(model()->fileUrl().toLocalFile()).absolutePath());
castedValue = QUrl(fileDir.relativeFilePath(filePath));
}
diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.cpp b/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.cpp
index dc080a2577a..60e5ed419bd 100644
--- a/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.cpp
+++ b/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.cpp
@@ -133,7 +133,7 @@ void StatesEditorWidget::reloadQmlSource()
setSource(QUrl::fromLocalFile(statesListQmlFilePath));
if (!rootObject()) {
- Core::AsynchronousMessageBox::warning(tr("Cannot create QtQuick View"),
+ Core::AsynchronousMessageBox::warning(tr("Cannot Create QtQuick View"),
tr("StatesEditorWidget: %1 cannot be created. "
"Most likely QtQuick.Controls 1 are not installed.").arg(qmlSourcesPath()));
return;
diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp
index e3e16e95d42..31fb93a03d8 100644
--- a/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp
+++ b/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp
@@ -118,7 +118,11 @@ void TextEditorView::modelAboutToBeDetached(Model *model)
m_widget->setTextEditor(0);
- QmlDesignerPlugin::instance()->emitCurrentTextEditorChanged(QmlDesignerPlugin::instance()->currentDesignDocument()->textEditor());
+ // in case the user closed it explicit we do not want to do anything with the editor
+ if (TextEditor::BaseTextEditor *textEditor =
+ QmlDesignerPlugin::instance()->currentDesignDocument()->textEditor()) {
+ QmlDesignerPlugin::instance()->emitCurrentTextEditorChanged(textEditor);
+ }
}
void TextEditorView::importsChanged(const QList<Import> &/*addedImports*/, const QList<Import> &/*removedImports*/)
diff --git a/src/plugins/qmldesigner/designercore/include/qmltimelinekeyframes.h b/src/plugins/qmldesigner/designercore/include/qmltimelinekeyframes.h
index 2969d4dd9a9..06d3565fa28 100644
--- a/src/plugins/qmldesigner/designercore/include/qmltimelinekeyframes.h
+++ b/src/plugins/qmldesigner/designercore/include/qmltimelinekeyframes.h
@@ -58,6 +58,11 @@ public:
bool hasKeyframe(qreal frame);
+ qreal minActualFrame() const;
+ qreal maxActualFrame() const;
+
+ const QList<ModelNode> keyframePositions() const;
+
static bool isValidKeyframe(const ModelNode &node);
static QmlTimelineFrames keyframesForKeyframe(const ModelNode &node);
};
diff --git a/src/plugins/qmldesigner/designercore/include/qmltimelinemutator.h b/src/plugins/qmldesigner/designercore/include/qmltimelinemutator.h
index 10e00fc7b33..b1baf7d7fd6 100644
--- a/src/plugins/qmldesigner/designercore/include/qmltimelinemutator.h
+++ b/src/plugins/qmldesigner/designercore/include/qmltimelinemutator.h
@@ -52,6 +52,13 @@ public:
qreal startFrame() const;
qreal endFrame() const;
qreal currentFrame() const;
+ qreal duration() const;
+
+ qreal minActualFrame() const;
+ qreal maxActualFrame() const;
+
+ QList<ModelNode> allTargets() const;
+ QList<QmlTimelineFrames> framesForTarget(const ModelNode &target) const;
private:
void addFramesIfNotExists(const ModelNode &node, const PropertyName &propertyName);
diff --git a/src/plugins/qmldesigner/designercore/metainfo/metainfo.cpp b/src/plugins/qmldesigner/designercore/metainfo/metainfo.cpp
index 58cbd68315a..aca95350555 100644
--- a/src/plugins/qmldesigner/designercore/metainfo/metainfo.cpp
+++ b/src/plugins/qmldesigner/designercore/metainfo/metainfo.cpp
@@ -187,6 +187,8 @@ void MetaInfo::clearGlobal()
void MetaInfo::setPluginPaths(const QStringList &paths)
{
s_pluginDirs = paths;
+ global();
+ clearGlobal();
}
bool MetaInfo::isGlobal() const
diff --git a/src/plugins/qmldesigner/designercore/model/qmltimelinekeyframes.cpp b/src/plugins/qmldesigner/designercore/model/qmltimelinekeyframes.cpp
index 959f2ea3f66..b2cab942d33 100644
--- a/src/plugins/qmldesigner/designercore/model/qmltimelinekeyframes.cpp
+++ b/src/plugins/qmldesigner/designercore/model/qmltimelinekeyframes.cpp
@@ -34,6 +34,8 @@
#include <utils/qtcassert.h>
+#include <limits>
+
namespace QmlDesigner {
QmlTimelineFrames::QmlTimelineFrames()
@@ -126,6 +128,42 @@ bool QmlTimelineFrames::hasKeyframe(qreal frame)
return false;
}
+qreal QmlTimelineFrames::minActualFrame() const
+{
+ qreal min = std::numeric_limits<double>::max();
+ for (const ModelNode &childNode : modelNode().defaultNodeListProperty().toModelNodeList()) {
+ QVariant value = childNode.variantProperty("frame").value();
+ if (value.isValid() && value.toReal() < min)
+ min = value.toReal();
+ }
+
+ return min;
+}
+
+qreal QmlTimelineFrames::maxActualFrame() const
+{
+ qreal max = std::numeric_limits<double>::min();
+ for (const ModelNode &childNode : modelNode().defaultNodeListProperty().toModelNodeList()) {
+ QVariant value = childNode.variantProperty("frame").value();
+ if (value.isValid() && value.toReal() > max)
+ max = value.toReal();
+ }
+
+ return max;
+}
+
+const QList<ModelNode> QmlTimelineFrames::keyframePositions() const
+{
+ QList<ModelNode> returnValues;
+ for (const ModelNode &childNode : modelNode().defaultNodeListProperty().toModelNodeList()) {
+ QVariant value = childNode.variantProperty("frame").value();
+ if (value.isValid())
+ returnValues.append(childNode);
+ }
+
+ return returnValues;
+}
+
bool QmlTimelineFrames::isValidKeyframe(const ModelNode &node)
{
return isValidQmlModelNodeFacade(node)
diff --git a/src/plugins/qmldesigner/designercore/model/qmltimelinemutator.cpp b/src/plugins/qmldesigner/designercore/model/qmltimelinemutator.cpp
index a028b61890d..201650020ca 100644
--- a/src/plugins/qmldesigner/designercore/model/qmltimelinemutator.cpp
+++ b/src/plugins/qmldesigner/designercore/model/qmltimelinemutator.cpp
@@ -36,6 +36,8 @@
#include <utils/qtcassert.h>
+#include <limits>
+
namespace QmlDesigner {
QmlTimelineMutator::QmlTimelineMutator()
@@ -123,6 +125,73 @@ qreal QmlTimelineMutator::currentFrame() const
return 0;
}
+qreal QmlTimelineMutator::duration() const
+{
+ return endFrame() - startFrame();
+}
+
+qreal QmlTimelineMutator::minActualFrame() const
+{
+ qreal min = std::numeric_limits<double>::max();
+
+ for (const ModelNode &childNode : modelNode().defaultNodeListProperty().toModelNodeList()) {
+ if (QmlTimelineFrames::isValidQmlTimelineFrames(childNode)) {
+ QmlTimelineFrames frames(childNode);
+ qreal value = frames.minActualFrame();
+ if (value < min)
+ min = value;
+ }
+ }
+
+ return min;
+}
+
+qreal QmlTimelineMutator::maxActualFrame() const
+{
+ qreal max = std::numeric_limits<double>::min();
+
+ for (const ModelNode &childNode : modelNode().defaultNodeListProperty().toModelNodeList()) {
+ if (QmlTimelineFrames::isValidQmlTimelineFrames(childNode)) {
+ QmlTimelineFrames frames(childNode);
+ qreal value = frames.maxActualFrame();
+ if (value > max)
+ max = value;
+ }
+ }
+
+ return max;
+}
+
+QList<ModelNode> QmlTimelineMutator::allTargets() const
+{
+ QList<ModelNode> result;
+ if (isValid()) {
+ for (const ModelNode &childNode : modelNode().defaultNodeListProperty().toModelNodeList()) {
+ if (QmlTimelineFrames::isValidQmlTimelineFrames(childNode)) {
+ const QmlTimelineFrames frames(childNode);
+ if (!result.contains(frames.target()))
+ result.append(frames.target());
+ }
+ }
+ }
+ return result;
+}
+
+QList<QmlTimelineFrames> QmlTimelineMutator::framesForTarget(const ModelNode &target) const
+{
+ QList<QmlTimelineFrames> result;
+ if (isValid()) {
+ for (const ModelNode &childNode : modelNode().defaultNodeListProperty().toModelNodeList()) {
+ if (QmlTimelineFrames::isValidQmlTimelineFrames(childNode)) {
+ const QmlTimelineFrames frames(childNode);
+ if (frames.target() == target)
+ result.append(frames);
+ }
+ }
+ }
+ return result;
+}
+
void QmlTimelineMutator::addFramesIfNotExists(const ModelNode &node, const PropertyName &propertyName)
{
if (!isValid())
diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp
index 3980fe7990e..d8ea45f1245 100644
--- a/src/plugins/qmldesigner/qmldesignerplugin.cpp
+++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp
@@ -413,7 +413,6 @@ void QmlDesignerPlugin::deactivateAutoSynchronization()
viewManager().detachViewsExceptRewriterAndComponetView();
viewManager().detachComponentView();
viewManager().detachRewriterView();
- emitCurrentTextEditorChanged(documentManager().currentDesignDocument()->textEditor());
documentManager().currentDesignDocument()->resetToDocumentModel();
}
diff --git a/src/plugins/qmldesigner/shortcutmanager.cpp b/src/plugins/qmldesigner/shortcutmanager.cpp
index 8b45efc8535..a6fd4fcf3b0 100644
--- a/src/plugins/qmldesigner/shortcutmanager.cpp
+++ b/src/plugins/qmldesigner/shortcutmanager.cpp
@@ -248,12 +248,15 @@ void ShortCutManager::registerActions(const Core::Context &qmlDesignerMainContex
m_copyAction.setEnabled(itemsSelected);
});
- connect(Core::ICore::instance(), &Core::ICore::contextChanged, this, [this](const Core::Context &context){
+ connect(Core::ICore::instance(), &Core::ICore::contextChanged, this, [&designerActionManager, this](const Core::Context &context){
if (!context.contains(Constants::C_QMLFORMEDITOR) && !context.contains(Constants::C_QMLNAVIGATOR)) {
m_deleteAction.setEnabled(false);
m_cutAction.setEnabled(false);
m_copyAction.setEnabled(false);
m_pasteAction.setEnabled(false);
+ } else {
+ designerActionManager.view()->emitSelectionChanged();
+
}
});
diff --git a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp
index 2a3c81f26e8..9b98d2f13cb 100644
--- a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp
+++ b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp
@@ -106,7 +106,7 @@ QString QmlProjectRunConfiguration::disabledReason() const
{
if (mainScript().isEmpty())
return tr("No script file to execute.");
- if (!QFileInfo(executable()).exists())
+ if (!QFileInfo::exists(executable()))
return tr("No qmlviewer or qmlscene found.");
return RunConfiguration::disabledReason();
}
diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp
index 0b2f55f2bbc..6f38c5deedc 100644
--- a/src/plugins/qtsupport/baseqtversion.cpp
+++ b/src/plugins/qtsupport/baseqtversion.cpp
@@ -1374,7 +1374,6 @@ void BaseQtVersion::addToEnvironment(const Kit *k, Environment &env) const
{
Q_UNUSED(k);
env.set(QLatin1String("QTDIR"), QDir::toNativeSeparators(qmakeProperty("QT_HOST_DATA")));
- env.prependOrSetPath(qmakeProperty("QT_HOST_BINS"));
}
// Some Qt versions may require environment settings for qmake to work
diff --git a/src/tools/qml2puppet/qml2puppet/qml2puppet.pro b/src/tools/qml2puppet/qml2puppet/qml2puppet.pro
index af8591e8ec6..9644cf4bca4 100644
--- a/src/tools/qml2puppet/qml2puppet/qml2puppet.pro
+++ b/src/tools/qml2puppet/qml2puppet/qml2puppet.pro
@@ -1,7 +1,7 @@
TARGET = qml2puppet
TEMPLATE = app
-QTC_LIB_DEPENDS += utils
+
include(../../../../qtcreator.pri)
osx: DESTDIR = $$IDE_LIBEXEC_PATH/qmldesigner
@@ -9,7 +9,6 @@ else: DESTDIR = $$IDE_LIBEXEC_PATH
include(../../../rpath.pri)
-include(../../../libs/qt-breakpad/qtbreakpad.pri)
include(../../../../share/qtcreator/qml/qmlpuppet/qml2puppet/qml2puppet.pri)
isEmpty(PRECOMPILED_HEADER):PRECOMPILED_HEADER = $$PWD/../../../shared/qtcreator_pch.h
diff --git a/tests/system/shared/editor_utils.py b/tests/system/shared/editor_utils.py
index e5a652aae96..1730fed46c0 100644
--- a/tests/system/shared/editor_utils.py
+++ b/tests/system/shared/editor_utils.py
@@ -423,3 +423,14 @@ def replaceLine(fileSpec, oldLine, newLine):
type(editor, "<Backspace>")
type(editor, newLine)
return True
+
+def addTestableCodeAfterLine(editorObject, line, newCodeLines):
+ if not placeCursorToLine(editorObject, line):
+ return False
+ type(editorObject, "<Return>")
+ typeLines(editorObject, newCodeLines)
+ return True
+
+def saveAndExit():
+ invokeMenuItem("File", "Save All")
+ invokeMenuItem("File", "Exit")
diff --git a/tests/system/suite_HELP/tst_HELP05/test.py b/tests/system/suite_HELP/tst_HELP05/test.py
index 1acfac0b542..2b84e6d7afc 100755
--- a/tests/system/suite_HELP/tst_HELP05/test.py
+++ b/tests/system/suite_HELP/tst_HELP05/test.py
@@ -37,10 +37,12 @@ def verifyInteractiveQMLHelp(lineText, helpText):
type(editorArea, homeKey)
else:
type(editorArea, homeKey)
+ snooze(1)
# call help
type(editorArea, "<F1>")
- test.verify(helpText in getHelpTitle(),
- "Verifying if help is opened with documentation for '%s'." % helpText)
+ test.verify(waitFor('helpText in getHelpTitle()', 1000),
+ "Verifying if help is opened with documentation for '%s'.\nHelp title: %s"
+ % (helpText, getHelpTitle()))
def main():
startApplication("qtcreator" + SettingsPath)
@@ -52,10 +54,15 @@ def main():
addHelpDocumentation(qchs)
# create qt quick application
createNewQtQuickApplication(tempDir(), "SampleApp")
+ editorArea = waitForObject(":Qt Creator_QmlJSEditor::QmlJSTextEditorWidget")
+ # add basic MouseArea item to check it afterwards
+ codelines = ['MouseArea {', 'anchors.fill: parent', 'onClicked: Qt.quit()']
+ if not addTestableCodeAfterLine(editorArea, 'title: qsTr("Hello World")', codelines):
+ saveAndExit()
+ return
+ invokeMenuItem("File", "Save All")
# verify Rectangle help
verifyInteractiveQMLHelp("Window {", "Window QML Type")
- # go back to edit mode
- switchViewTo(ViewConstants.EDIT)
# verify MouseArea help
verifyInteractiveQMLHelp("MouseArea {", "MouseArea QML Type")
# exit
diff --git a/tests/system/suite_QMLS/tst_QMLS01/test.py b/tests/system/suite_QMLS/tst_QMLS01/test.py
index cb8f6447a2a..434b1ae47ea 100644
--- a/tests/system/suite_QMLS/tst_QMLS01/test.py
+++ b/tests/system/suite_QMLS/tst_QMLS01/test.py
@@ -108,13 +108,16 @@ def testSuggestionsManual(lineText, textToType, expectedText):
__endTestSuggestions__(editorArea)
return True
-def saveAndExit():
- invokeMenuItem("File", "Save All")
- invokeMenuItem("File", "Exit")
-
def main():
if not startQtCreatorWithNewAppAtQMLEditor(tempDir(), "SampleApp"):
return
+ # add basic TextEdit item to check it afterwards
+ codelines = ['TextEdit {', 'text: "Enter something"', 'anchors.top: parent.top',
+ 'anchors.horizontalCenter: parent.horizontalCenter', 'anchors.topMargin: 20']
+ editor = waitForObject(":Qt Creator_QmlJSEditor::QmlJSTextEditorWidget")
+ if not addTestableCodeAfterLine(editor, 'title: qsTr("Hello World")', codelines):
+ saveAndExit()
+ return
# test "color: " suggestion usage with Enter key
if not testSuggestionsAuto("TextEdit {", "col", "color:", "<Return>"):
saveAndExit()
@@ -123,11 +126,11 @@ def main():
if not testSuggestionsAuto("TextEdit {", "col", "color:", "<Tab>"):
saveAndExit()
return
- # test "textChanged: " suggestion - automatic insert, because only one suggestion available
+ # test automatic insertion (prerequisite: only one suggestion available)
shortcutToSuggestions = "<Ctrl+Space>"
if platform.system() == "Darwin":
shortcutToSuggestions = "<Meta+Space>"
- if not testSuggestionsAuto("TextEdit {","baseu", "baseUrl:", shortcutToSuggestions):
+ if not testSuggestionsAuto("TextEdit {", "online", "onLineCountChanged:", shortcutToSuggestions):
saveAndExit()
return
# change settings to manual insertion of suggestions
diff --git a/tests/system/suite_QMLS/tst_QMLS02/test.py b/tests/system/suite_QMLS/tst_QMLS02/test.py
index 78101fc08fe..687f53a53f5 100644
--- a/tests/system/suite_QMLS/tst_QMLS02/test.py
+++ b/tests/system/suite_QMLS/tst_QMLS02/test.py
@@ -27,9 +27,15 @@ source("../shared/qmls.py")
source("../../shared/suites_qtta.py")
def main():
- editorArea = startQtCreatorWithNewAppAtQMLEditor(tempDir(), "SampleApp", "TextEdit {")
+ editorArea = startQtCreatorWithNewAppAtQMLEditor(tempDir(), "SampleApp")
if not editorArea:
return
+ # add basic TextEdit item to check it afterwards
+ codelines = ['TextEdit {', 'text: "Enter something"', 'anchors.top: parent.top',
+ 'anchors.horizontalCenter: parent.horizontalCenter', 'anchors.topMargin: 20']
+ if not addTestableCodeAfterLine(editorArea, 'title: qsTr("Hello World")', codelines):
+ saveAndExit()
+ return
# write code with error (C should be lower case)
testingCodeLine = 'Color : "blue"'
type(editorArea, "<Return>")
diff --git a/tests/system/suite_QMLS/tst_QMLS04/test.py b/tests/system/suite_QMLS/tst_QMLS04/test.py
index 5dabdf7f0f2..6d4d9624775 100644
--- a/tests/system/suite_QMLS/tst_QMLS04/test.py
+++ b/tests/system/suite_QMLS/tst_QMLS04/test.py
@@ -27,9 +27,16 @@ source("../shared/qmls.py")
def main():
projectDir = tempDir()
- editorArea = startQtCreatorWithNewAppAtQMLEditor(projectDir, "SampleApp", "TextEdit {")
+ editorArea = startQtCreatorWithNewAppAtQMLEditor(projectDir, "SampleApp")
if not editorArea:
return
+ # add basic TextEdit item to check it afterwards
+ codelines = ['TextEdit {', 'id: textEdit', 'text: "Enter something"', 'anchors.top: parent.top',
+ 'anchors.horizontalCenter: parent.horizontalCenter', 'anchors.topMargin: 20']
+ if not addTestableCodeAfterLine(editorArea, 'title: qsTr("Hello World")', codelines):
+ saveAndExit()
+ return
+ placeCursorToLine(editorArea, "TextEdit {")
for i in range(5):
type(editorArea, "<Left>")
# invoke Refactoring - Move Component into separate file
diff --git a/tests/system/suite_QMLS/tst_QMLS05/test.py b/tests/system/suite_QMLS/tst_QMLS05/test.py
index 3db2f02f015..111bf68f391 100644
--- a/tests/system/suite_QMLS/tst_QMLS05/test.py
+++ b/tests/system/suite_QMLS/tst_QMLS05/test.py
@@ -26,7 +26,7 @@
source("../shared/qmls.py")
def main():
- editorArea = startQtCreatorWithNewAppAtQMLEditor(tempDir(), "SampleApp", "TextEdit {")
+ editorArea = startQtCreatorWithNewAppAtQMLEditor(tempDir(), "SampleApp", "}")
if not editorArea:
return
homeKey = "<Home>"
diff --git a/tests/system/suite_QMLS/tst_QMLS06/test.py b/tests/system/suite_QMLS/tst_QMLS06/test.py
index e114fd2f238..f4e9a12d92d 100644
--- a/tests/system/suite_QMLS/tst_QMLS06/test.py
+++ b/tests/system/suite_QMLS/tst_QMLS06/test.py
@@ -29,7 +29,14 @@ def main():
editorArea = startQtCreatorWithNewAppAtQMLEditor(tempDir(), "SampleApp", "}")
if not editorArea:
return
+ homeKey = "<Home>"
+ if platform.system() == "Darwin":
+ homeKey = "<Ctrl+Left>"
+ for i in range(2):
+ type(editorArea, homeKey)
type(editorArea, "<Return>")
+ type(editorArea, "<Up>")
+ type(editorArea, "<Tab>")
testingItemText = "Item { x: 10; y: 20; width: 10 }"
type(editorArea, testingItemText)
for i in range(30):
diff --git a/tests/system/suite_editors/tst_qml_indent/test.py b/tests/system/suite_editors/tst_qml_indent/test.py
index 585a6334c79..f05da16317e 100644
--- a/tests/system/suite_editors/tst_qml_indent/test.py
+++ b/tests/system/suite_editors/tst_qml_indent/test.py
@@ -42,24 +42,43 @@ def prepareQmlFile():
test.fatal("Could not open main.qml")
return None
editor = waitForObject(":Qt Creator_QmlJSEditor::QmlJSTextEditorWidget")
+ isDarwin = platform.system() == 'Darwin'
for i in range(3):
content = "%s" % editor.plainText
- start = content.find("MouseArea {")
- if not placeCursorToLine(editor, "MouseArea {"):
+ if not placeCursorToLine(editor, 'title: qsTr("Hello World")'):
test.fatal("Couldn't find line(s) I'm looking for - QML file seems to "
"have changed!\nLeaving test...")
return None
+ # add some copyable code
+ if i == 0:
+ code = ["", "MouseArea {", "anchors.fill: parent", "onClicked: {",
+ "console.log(parent.title)"]
+ typeLines(editor, code)
+ # avoid having 'correctly' indented empty line
+ if isDarwin:
+ type(editor, "<Command+Shift+Left>")
+ else:
+ type(editor, "<Shift+Home>")
+ type(editor, "<Delete>")
+ # get back to the first entered line
+ for _ in range(5):
+ type(editor, "<Up>")
+ if isDarwin:
+ type(editor, "<Command+Right>")
+ else:
+ type(editor, "<End>")
+ else:
+ type(editor, "<Up>")
type(editor, "<Right>")
- type(editor, "<Up>")
# mark until the end of file
- if platform.system() == 'Darwin':
+ if isDarwin:
markText(editor, "End")
else:
markText(editor, "Ctrl+End")
# unmark the closing brace
type(editor, "<Shift+Up>")
type(editor, "<Ctrl+c>")
- for j in range(10):
+ for _ in range(11):
type(editor, "<Ctrl+v>")
# assume the current editor content to be indented correctly
originalText = "%s" % editor.plainText
@@ -71,13 +90,12 @@ def prepareQmlFile():
def testReIndent(originalText):
editor = waitForObject(":Qt Creator_QmlJSEditor::QmlJSTextEditorWidget")
- correctIndented = len(originalText)
- incorrectIndented = correctIndented + 4004
type(editor, "<Ctrl+a>")
+ filenameCombo = waitForObject(":Qt Creator_FilenameQComboBox")
test.log("calling re-indent")
starttime = datetime.utcnow()
type(editor, "<Ctrl+i>")
- waitFor("len(str(editor.plainText)) in (incorrectIndented, correctIndented)", 25000)
+ waitFor("str(filenameCombo.currentText).endswith('*')", 25000)
endtime = datetime.utcnow()
test.xverify(originalText == str(editor.plainText),
"Verify that indenting restored the original text. "
diff --git a/tests/system/suite_general/tst_default_settings/test.py b/tests/system/suite_general/tst_default_settings/test.py
index 23487e4bd40..a4230fe17fa 100644
--- a/tests/system/suite_general/tst_default_settings/test.py
+++ b/tests/system/suite_general/tst_default_settings/test.py
@@ -184,7 +184,9 @@ def __getExpectedCompilers__():
expected.extend(__getWinCompilers__())
compilers = ["g++", "gcc"]
if platform.system() in ('Linux', 'Darwin'):
- compilers.extend(["g++-4.0", "g++-4.2", "clang++", "clang"])
+ compilers.extend(["clang++", "clang"])
+ compilers.extend(findAllFilesInPATH("*g++*"))
+ compilers.extend(findAllFilesInPATH("*gcc*"))
if platform.system() == 'Darwin':
xcodeClang = getOutputFromCmdline(["xcrun", "--find", "clang++"]).strip("\n")
if xcodeClang and os.path.exists(xcodeClang) and xcodeClang not in expected:
@@ -333,7 +335,6 @@ def __checkCreatedSettings__(settingsFolder):
{os.path.join(folders[0], "qtversion.xml"):0},
{os.path.join(folders[0], "toolchains.xml"):0}])
folders.extend([os.path.join(folders[0], "generic-highlighter"),
- os.path.join(folders[0], "json"),
os.path.join(folders[0], "macros")])
for f in folders:
test.verify(os.path.isdir(f),
diff --git a/tests/unit/unittest/activationsequencecontextprocessor-test.cpp b/tests/unit/unittest/activationsequencecontextprocessor-test.cpp
index 5ccc7d500a6..62a70d752cb 100644
--- a/tests/unit/unittest/activationsequencecontextprocessor-test.cpp
+++ b/tests/unit/unittest/activationsequencecontextprocessor-test.cpp
@@ -147,7 +147,9 @@ TEST(ActivationSequenceContextProcessor, TemplateFunctionLeftParen)
TEST(ActivationSequenceContextProcessor, TemplateFunctionSecondParameter)
{
ClangCompletionAssistInterface interface("foo<X>(", 7);
- int startOfname = ContextProcessor::findStartOfName(&interface, 6);
+ int startOfname = ContextProcessor::findStartOfName(&interface,
+ 6,
+ ContextProcessor::NameCategory::Function);
ASSERT_THAT(startOfname, 0);
}
diff --git a/tests/unit/unittest/clangcompletioncontextanalyzer-test.cpp b/tests/unit/unittest/clangcompletioncontextanalyzer-test.cpp
index 09938b2c5da..9047b091656 100644
--- a/tests/unit/unittest/clangcompletioncontextanalyzer-test.cpp
+++ b/tests/unit/unittest/clangcompletioncontextanalyzer-test.cpp
@@ -178,6 +178,13 @@ TEST_F(ClangCompletionContextAnalyzer, AfterSpace)
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText));
}
+TEST_F(ClangCompletionContextAnalyzer, AfterQualification)
+{
+ auto analyzer = runAnalyzer(" Foo::@");
+
+ ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText));
+}
+
TEST_F(ClangCompletionContextAnalyzer, AtEndOfDotMember)
{
auto analyzer = runAnalyzer("o.mem@");