Merge remote-tracking branch 'origin/8.0'

Change-Id: I9f41e115adb25c08acc01110b6027020eff1a1e7
This commit is contained in:
Eike Ziller
2022-06-17 11:29:14 +02:00
216 changed files with 1616 additions and 1419 deletions

7
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,7 @@
Thank you for contributing to Qt Creator! Unfortunately the GitHub Qt Creator
presence is only a git mirror.
Please submit your patch via gerrit:
https://wiki.qt.io/Qt_Creator#Setting_up_Gerrit_to_contribute_back_to_Qt_Creator
We are sorry for the inconvenience.

View File

@@ -7,7 +7,7 @@ on:
- 'doc/**' - 'doc/**'
env: env:
QT_VERSION: 6.2.3 QT_VERSION: 6.3.0
CLANG_VERSION: 14.0.3 CLANG_VERSION: 14.0.3
ELFUTILS_VERSION: 0.175 ELFUTILS_VERSION: 0.175
CMAKE_VERSION: 3.21.1 CMAKE_VERSION: 3.21.1

22
dist/changes-8.0.0.md vendored
View File

@@ -10,17 +10,26 @@ the public Git repository. For example:
git clone git://code.qt.io/qt-creator/qt-creator.git git clone git://code.qt.io/qt-creator/qt-creator.git
git log --cherry-pick --pretty=oneline origin/7.0..v8.0.0 git log --cherry-pick --pretty=oneline origin/7.0..v8.0.0
Help
----
* Added support for mouse forward and backward buttons (QTCREATORBUG-25168)
Editing Editing
------- -------
* Added shortcut for adding next search match to multi-selection * Added shortcut for adding next search match to multi-selection
* Added warning when editing generated file (QTCREATORBUG-27173) * Added warning when editing generated file (QTCREATORBUG-27173)
* Added option for hiding line ending information
* Fixed updating of annotations (QTCREATORBUG-26812) * Fixed updating of annotations (QTCREATORBUG-26812)
* Fixed that whitespace was not selected on double-click (QTCREATORBUG-24607) * Fixed that whitespace was not selected on double-click (QTCREATORBUG-24607)
* Fixed `Rewrap Paragraph` when indenting with tabs (QTCREATORBUG-27602)
### C++ ### C++
* Removed `libclang` based code model * Removed `libclang` based code model
* Fixed that `Generate Setter and Getter` generated non-static methods for
static pointer types (QTCREATORBUG-27547)
* Clangd * Clangd
* Increased minimum `Clangd` version to 14 * Increased minimum `Clangd` version to 14
* Improved performance of `compile_commands.json` creation * Improved performance of `compile_commands.json` creation
@@ -64,6 +73,8 @@ Editing
* Fixed semantic highlighting after server reset * Fixed semantic highlighting after server reset
* Fixed that semantic update was delayed by `Document update threshold` even * Fixed that semantic update was delayed by `Document update threshold` even
after saving after saving
* Fixed that tooltips could appear while Qt Creator is not in the foreground
* Fixed synchronization of outline view (QTCREATORBUG-27595)
### Image Viewer ### Image Viewer
@@ -73,11 +84,14 @@ Projects
-------- --------
* Added locator filter for starting run configurations * Added locator filter for starting run configurations
* Added `BuildSystem:Name` variable for default build directory
(QTCREATORBUG-26147)
### CMake ### CMake
* Added `Profile` build configuration type that is `RelWithDebInfo` with `QML * Added `Profile` build configuration type that is `RelWithDebInfo` with `QML
debugging and profiling` debugging and profiling`
* Added `install` command to wizard generated projects
* Turned `QML debugging and profiling` option on by default for `Debug` * Turned `QML debugging and profiling` option on by default for `Debug`
configurations configurations
* Removed hardcoded `QT_QML_DEBUG` from wizard created project files * Removed hardcoded `QT_QML_DEBUG` from wizard created project files
@@ -96,6 +110,7 @@ Analyzer
### Coco ### Coco
* Added experimental `Coco` integration * Added experimental `Coco` integration
* Added visualization of code coverage in code editor
### CppCheck ### CppCheck
@@ -129,6 +144,11 @@ Platforms
* Added auto-detection for MSVC ARM toolchain and debugger * Added auto-detection for MSVC ARM toolchain and debugger
* Fixed ABI detection on ARM Windows * Fixed ABI detection on ARM Windows
### macOS
* Fixed import of existing builds of CMake projects that were done on the
command line (QTCREATORBUG-27591)
### Android ### Android
* Added option to connect physical device over WiFi * Added option to connect physical device over WiFi
@@ -160,6 +180,7 @@ Aaron Barany
Adam Treat Adam Treat
Alesandro Portale Alesandro Portale
Alessandro Portale Alessandro Portale
Alexander Akulich
Alexander Drozdov Alexander Drozdov
Alexandru Croitor Alexandru Croitor
Andre Hartmann Andre Hartmann
@@ -176,6 +197,7 @@ David Schulz
Dmitry Shachnev Dmitry Shachnev
Eike Ziller Eike Ziller
Erik Verbruggen Erik Verbruggen
Evgeny Shtanov
Fawzi Mohamed Fawzi Mohamed
Henning Gruendl Henning Gruendl
Ihor Ivlev Ihor Ivlev

View File

@@ -162,6 +162,8 @@
the application from running until the debug client connects to the the application from running until the debug client connects to the
server. This enables debugging from the start. server. This enables debugging from the start.
\note Setting breakpoints is only possible if the application is started with block mode.
\li Select \uicontrol Debug > \uicontrol {Start Debugging} > \li Select \uicontrol Debug > \uicontrol {Start Debugging} >
\uicontrol {Attach to QML Port}. \uicontrol {Attach to QML Port}.

View File

@@ -1740,6 +1740,11 @@ def qdump__QString(d, value):
d.putArrayData(data, size, d.createType('@QChar')) d.putArrayData(data, size, d.createType('@QChar'))
def qdump__QSettingsKey(d, value):
qdump__QString(d, value)
d.putBetterType(value.type)
def qdump__QStaticStringData(d, value): def qdump__QStaticStringData(d, value):
size = value.type[0] size = value.type[0]
(ref, size, alloc, pad, offset, data) = value.split('iii@p%ss' % (2 * size)) (ref, size, alloc, pad, offset, data) = value.split('iii@p%ss' % (2 * size))

View File

@@ -1,4 +1,4 @@
import QtQuick 2.0 import QtQuick 2.15
import QtTest 1.0 import QtTest 1.0
TestCase { TestCase {

View File

@@ -1,4 +1,4 @@
import QtQuick 2.0 import QtQuick %{QtQuickVersion}
Item { Item {

View File

@@ -3,13 +3,16 @@
"supportedProjectTypes": [ ], "supportedProjectTypes": [ ],
"id": "Q.Qml.2", "id": "Q.Qml.2",
"category": "R.Qt", "category": "R.Qt",
"trDescription": "Creates a QML file with boilerplate code, starting with \"import QtQuick 2.0\".", "trDescription": "Creates a QML file with boilerplate code, starting with \"import QtQuick\".",
"trDisplayName": "QML File (Qt Quick 2)", "trDisplayName": "QML File (Qt Quick 2)",
"trDisplayCategory": "Qt", "trDisplayCategory": "Qt",
"iconText": "qml", "iconText": "qml",
"enabled": "%{JS: value('Plugins').indexOf('QmlJSEditor') >= 0}", "enabled": "%{JS: value('Plugins').indexOf('QmlJSEditor') >= 0}",
"options": { "key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('text/x-qml')}" }, "options": [
{"key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('text/x-qml')}"},
{"key": "QtQuickVersion", "value": "%{JS: Util.qtQuickVersion(value('TargetPath'))}"}
],
"pages" : "pages" :
[ [

View File

@@ -36,3 +36,5 @@ else()
qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES}) qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
endif() endif()
@endif @endif
install(TARGETS %{ProjectName})

View File

@@ -3,3 +3,5 @@ cmake_minimum_required(VERSION 3.5)
project(%{ProjectName} LANGUAGES C) project(%{ProjectName} LANGUAGES C)
add_executable(%{ProjectName} %{CFileName}) add_executable(%{ProjectName} %{CFileName})
install(TARGETS %{ProjectName})

View File

@@ -6,3 +6,5 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(%{ProjectName} %{CppFileName}) add_executable(%{ProjectName} %{CppFileName})
install(TARGETS %{ProjectName})

View File

@@ -27,3 +27,5 @@ set_target_properties(%{TargetName} PROPERTIES
target_link_libraries(%{TargetName} target_link_libraries(%{TargetName}
PRIVATE Qt6::Quick) PRIVATE Qt6::Quick)
install(TARGETS %{TargetName} BUNDLE DESTINATION .)

View File

@@ -71,6 +71,8 @@ set_target_properties(%{ProjectName} PROPERTIES
WIN32_EXECUTABLE TRUE WIN32_EXECUTABLE TRUE
) )
install(TARGETS %{ProjectName} BUNDLE DESTINATION .)
if(QT_VERSION_MAJOR EQUAL 6) if(QT_VERSION_MAJOR EQUAL 6)
qt_import_qml_plugins(%{ProjectName}) qt_import_qml_plugins(%{ProjectName})
qt_finalize_executable(%{ProjectName}) qt_finalize_executable(%{ProjectName})

View File

@@ -74,6 +74,8 @@ set_target_properties(%{ProjectName} PROPERTIES
WIN32_EXECUTABLE TRUE WIN32_EXECUTABLE TRUE
) )
install(TARGETS %{ProjectName} BUNDLE DESTINATION .)
if(QT_VERSION_MAJOR EQUAL 6) if(QT_VERSION_MAJOR EQUAL 6)
qt_finalize_executable(%{ProjectName}) qt_finalize_executable(%{ProjectName})
endif() endif()

View File

@@ -96,86 +96,6 @@ protected:
} }
}; };
class ContainingFunctionAt: protected SymbolVisitor
{
TranslationUnit *translationUnit;
Symbol *root;
int line;
int column;
Symbol *functionSymbol;
bool foundFunction;
bool foundBlock;
bool scopeContains(Scope* scope, int line, int column){
if (!scope)
return false;
int scopeStartLine{-1}, scopeStartColumn{-1}, scopeEndLine{-1}, scopeEndColumn{-1};
translationUnit->getPosition(scope->startOffset(), &scopeStartLine, &scopeStartColumn);
translationUnit->getPosition(scope->endOffset(), &scopeEndLine, &scopeEndColumn);
if (line < scopeStartLine || line > scopeEndLine)
return false;
if (line > scopeStartLine && line < scopeEndLine)
return true;
if (scopeStartLine == line && column >= scopeStartColumn)
return true;
if (scopeEndLine == line && column <= scopeEndColumn)
return true;
return false;
}
public:
ContainingFunctionAt(TranslationUnit *unit, Symbol *root)
: translationUnit(unit), root(root), line(0), column(0), functionSymbol(nullptr)
, foundFunction(false), foundBlock(false) {}
Symbol *operator()(int line, int column)
{
this->line = line;
this->column = column;
this->functionSymbol = nullptr;
accept(root);
return foundBlock ? functionSymbol : nullptr;
}
protected:
bool preVisit(Symbol *s) final
{
if (foundBlock)
return false;
if (foundFunction) {
auto block = s->asBlock();
if (!block)
return true;
if (scopeContains(block->asScope(), line, column)) {
foundBlock = true;
return false;
}
return true;
}
auto asFunction = s->asFunction();
if (asFunction) {
if (s->line() < line || (s->line() == line && s->column() <= column)) {
foundFunction = scopeContains(s->asScope(), line, column);
if (foundFunction)
functionSymbol = asFunction;
}
}
return true;
}
};
class FindScopeAt: protected SymbolVisitor class FindScopeAt: protected SymbolVisitor
{ {
TranslationUnit *_unit; TranslationUnit *_unit;
@@ -592,11 +512,19 @@ QString Document::functionAt(int line, int column, int *lineOpeningDeclaratorPar
if (line < 1 || column < 1) if (line < 1 || column < 1)
return QString(); return QString();
Symbol *symbol = ContainingFunctionAt{translationUnit(), globalNamespace()}(line, column); Symbol *symbol = lastVisibleSymbolAt(line, column);
if (!symbol) if (!symbol)
return QString(); return QString();
// Find the enclosing function scope (which might be several levels up, or we might be standing
// on it)
Scope *scope = symbol->asScope(); Scope *scope = symbol->asScope();
if (!scope)
scope = symbol->enclosingScope();
while (scope && !scope->isFunction() )
scope = scope->enclosingScope();
if (!scope) if (!scope)
return QString(); return QString();

View File

@@ -142,11 +142,30 @@ void FindUsages::reportResult(unsigned tokenIndex, const QList<LookupItem> &cand
const int len = tk.utf16chars(); const int len = tk.utf16chars();
const Usage u(Utils::FilePath::fromString(_doc->fileName()), lineText, const Usage u(Utils::FilePath::fromString(_doc->fileName()), lineText,
getType(line, col, tokenIndex), line, col - 1, len); getContainingFunction(line, col), getType(line, col, tokenIndex),
line, col - 1, len);
_usages.append(u); _usages.append(u);
_references.append(tokenIndex); _references.append(tokenIndex);
} }
QString FindUsages::getContainingFunction(int line, int column)
{
const QList<AST *> astPath = ASTPath(_doc)(line, column);
bool hasBlock = false;
for (auto it = astPath.crbegin(); it != astPath.crend(); ++it) {
if (!hasBlock && (*it)->asCompoundStatement())
hasBlock = true;
if (const auto func = (*it)->asFunctionDefinition()) {
if (!hasBlock)
return {};
if (!func->symbol)
return {};
return Overview().prettyName(func->symbol->name());
}
}
return {};
}
class FindUsages::GetUsageType class FindUsages::GetUsageType
{ {
public: public:

View File

@@ -42,11 +42,14 @@ public:
enum class Type { Declaration, Initialization, Read, Write, WritableRef, Other }; enum class Type { Declaration, Initialization, Read, Write, WritableRef, Other };
Usage() = default; Usage() = default;
Usage(const Utils::FilePath &path, const QString &lineText, Type t, int line, int col, int len) Usage(const Utils::FilePath &path, const QString &lineText, const QString &func, Type t,
: path(path), lineText(lineText), type(t), line(line), col(col), len(len) {} int line, int col, int len)
: path(path), lineText(lineText), containingFunction(func), type(t),
line(line), col(col), len(len) {}
Utils::FilePath path; Utils::FilePath path;
QString lineText; QString lineText;
QString containingFunction;
Type type = Type::Other; Type type = Type::Other;
int line = 0; int line = 0;
int col = 0; int col = 0;
@@ -75,6 +78,7 @@ protected:
void reportResult(unsigned tokenIndex, const Name *name, Scope *scope = nullptr); void reportResult(unsigned tokenIndex, const Name *name, Scope *scope = nullptr);
void reportResult(unsigned tokenIndex, const QList<LookupItem> &candidates); void reportResult(unsigned tokenIndex, const QList<LookupItem> &candidates);
Usage::Type getType(int line, int column, int tokenIndex); Usage::Type getType(int line, int column, int tokenIndex);
QString getContainingFunction(int line, int column);
bool checkCandidates(const QList<LookupItem> &candidates) const; bool checkCandidates(const QList<LookupItem> &candidates) const;
void checkExpression(unsigned startToken, unsigned endToken, Scope *scope = nullptr); void checkExpression(unsigned startToken, unsigned endToken, Scope *scope = nullptr);

View File

@@ -557,9 +557,11 @@ void DiagramController::onBeginResetModel()
void DiagramController::onEndResetModel() void DiagramController::onEndResetModel()
{ {
updateAllDiagramsList(); updateAllDiagramsList();
foreach (MDiagram *diagram, m_allDiagrams) { for (MDiagram *diagram : qAsConst(m_allDiagrams)) {
const QList<DElement *> elements = diagram->diagramElements();
// remove all elements which are not longer part of the model // remove all elements which are not longer part of the model
foreach (DElement *element, diagram->diagramElements()) { for (int i = elements.size() - 1; i >= 0; --i) {
DElement *element = elements.at(i);
if (element->modelUid().isValid()) { if (element->modelUid().isValid()) {
MElement *modelElement = m_modelController->findElement(element->modelUid()); MElement *modelElement = m_modelController->findElement(element->modelUid());
if (!modelElement) if (!modelElement)
@@ -567,7 +569,7 @@ void DiagramController::onEndResetModel()
} }
} }
// update all remaining elements from model // update all remaining elements from model
foreach (DElement *element, diagram->diagramElements()) for (DElement *element : diagram->diagramElements())
updateElementFromModel(element, diagram, false); updateElementFromModel(element, diagram, false);
} }
emit endResetAllDiagrams(); emit endResetAllDiagrams();

View File

@@ -76,6 +76,8 @@ bool allOf(const T &container, F predicate);
///////////////////////// /////////////////////////
template<typename T, typename F> template<typename T, typename F>
void erase(T &container, F predicate); void erase(T &container, F predicate);
template<typename T, typename F>
bool eraseOne(T &container, F predicate);
///////////////////////// /////////////////////////
// contains // contains
@@ -442,7 +444,15 @@ void erase(T &container, F predicate)
container.erase(std::remove_if(std::begin(container), std::end(container), predicate), container.erase(std::remove_if(std::begin(container), std::end(container), predicate),
std::end(container)); std::end(container));
} }
template<typename T, typename F>
bool eraseOne(T &container, F predicate)
{
const auto it = std::find_if(std::begin(container), std::end(container), predicate);
if (it == std::end(container))
return false;
container.erase(it);
return true;
}
////////////////// //////////////////
// contains // contains

View File

@@ -527,10 +527,11 @@ QString FilePath::fileNameWithPathComponents(int pathComponents) const
; ;
} }
// If there are no more slashes before the found one, return the entire string
if (i > 0 && m_data.lastIndexOf(slash, i) != -1) if (i > 0 && m_data.lastIndexOf(slash, i) != -1)
return m_data.mid(component); return m_data.mid(component);
return m_data;
// If there are no more slashes before the found one, return the entire string
return displayName();
} }
/// \returns the base name of the file without the path. /// \returns the base name of the file without the path.

View File

@@ -89,21 +89,6 @@ CallerHandle::~CallerHandle()
qDeleteAll(m_signals); qDeleteAll(m_signals);
} }
bool CallerHandle::waitForStarted(int msecs)
{
return waitForSignal(msecs, SignalType::Started);
}
bool CallerHandle::waitForReadyRead(int msces)
{
return waitForSignal(msces, SignalType::ReadyRead);
}
bool CallerHandle::waitForFinished(int msecs)
{
return waitForSignal(msecs, SignalType::Done);
}
void CallerHandle::flush() void CallerHandle::flush()
{ {
flushFor(SignalType::NoSignal); flushFor(SignalType::NoSignal);
@@ -329,11 +314,11 @@ void CallerHandle::setProcessSetupData(ProcessSetupData *setup)
m_setup = setup; m_setup = setup;
} }
bool CallerHandle::waitForSignal(int msecs, SignalType newSignal) bool CallerHandle::waitForSignal(SignalType signalType, int msecs)
{ {
QTC_ASSERT(isCalledFromCallersThread(), return false); QTC_ASSERT(isCalledFromCallersThread(), return false);
QTC_ASSERT(m_launcherHandle, return false); QTC_ASSERT(m_launcherHandle, return false);
return m_launcherHandle->waitForSignal(msecs, newSignal); return m_launcherHandle->waitForSignal(signalType, msecs);
} }
// Called from caller's or launcher's thread. // Called from caller's or launcher's thread.
@@ -351,7 +336,7 @@ bool CallerHandle::isCalledFromLaunchersThread() const
} }
// Called from caller's thread exclusively. // Called from caller's thread exclusively.
bool LauncherHandle::waitForSignal(int msecs, CallerHandle::SignalType newSignal) bool LauncherHandle::waitForSignal(CallerHandle::SignalType newSignal, int msecs)
{ {
QTC_ASSERT(!isCalledFromLaunchersThread(), return false); QTC_ASSERT(!isCalledFromLaunchersThread(), return false);
QDeadlineTimer deadline(msecs); QDeadlineTimer deadline(msecs);

View File

@@ -73,9 +73,7 @@ public:
LauncherHandle *launcherHandle() const { return m_launcherHandle; } LauncherHandle *launcherHandle() const { return m_launcherHandle; }
void setLauncherHandle(LauncherHandle *handle) { QMutexLocker locker(&m_mutex); m_launcherHandle = handle; } void setLauncherHandle(LauncherHandle *handle) { QMutexLocker locker(&m_mutex); m_launcherHandle = handle; }
bool waitForStarted(int msecs); bool waitForSignal(CallerHandle::SignalType signalType, int msecs);
bool waitForReadyRead(int msces);
bool waitForFinished(int msecs);
// Returns the list of flushed signals. // Returns the list of flushed signals.
void flush(); void flush();
@@ -109,8 +107,6 @@ signals:
void done(const Utils::ProcessResultData &resultData); void done(const Utils::ProcessResultData &resultData);
private: private:
bool waitForSignal(int msecs, SignalType newSignal);
// Called from caller's thread exclusively. // Called from caller's thread exclusively.
void sendPacket(const Internal::LauncherPacket &packet); void sendPacket(const Internal::LauncherPacket &packet);
// Called from caller's or launcher's thread. // Called from caller's or launcher's thread.
@@ -158,7 +154,7 @@ public:
// Called from caller's thread, moved to launcher's thread afterwards. // Called from caller's thread, moved to launcher's thread afterwards.
LauncherHandle(quintptr token) : m_token(token) {} LauncherHandle(quintptr token) : m_token(token) {}
// Called from caller's thread exclusively. // Called from caller's thread exclusively.
bool waitForSignal(int msecs, CallerHandle::SignalType newSignal); bool waitForSignal(CallerHandle::SignalType newSignal, int msecs);
CallerHandle *callerHandle() const { return m_callerHandle; } CallerHandle *callerHandle() const { return m_callerHandle; }
void setCallerHandle(CallerHandle *handle) { QMutexLocker locker(&m_mutex); m_callerHandle = handle; } void setCallerHandle(CallerHandle *handle) { QMutexLocker locker(&m_mutex); m_callerHandle = handle; }

View File

@@ -60,12 +60,6 @@ MimeType mimeTypeForFile(const QString &fileName, MimeMatchMode mode)
return mdb.mimeTypeForFile(fileName, MimeDatabase::MatchMode(mode)); return mdb.mimeTypeForFile(fileName, MimeDatabase::MatchMode(mode));
} }
MimeType mimeTypeForFile(const QFileInfo &fileInfo, MimeMatchMode mode)
{
MimeDatabase mdb;
return mdb.mimeTypeForFile(fileInfo, MimeDatabase::MatchMode(mode));
}
MimeType mimeTypeForFile(const FilePath &filePath, MimeMatchMode mode) MimeType mimeTypeForFile(const FilePath &filePath, MimeMatchMode mode)
{ {
MimeDatabase mdb; MimeDatabase mdb;

View File

@@ -44,10 +44,6 @@
#include <mimemagicrule_p.h> #include <mimemagicrule_p.h>
#include <mimetype.h> #include <mimetype.h>
QT_BEGIN_NAMESPACE
class QFileInfo;
QT_END_NAMESPACE
namespace Utils { namespace Utils {
class FilePath; class FilePath;
@@ -59,8 +55,6 @@ enum class MimeMatchMode { MatchDefault = 0x0, MatchExtension = 0x1, MatchConten
QTCREATOR_UTILS_EXPORT MimeType mimeTypeForFile(const QString &fileName, QTCREATOR_UTILS_EXPORT MimeType mimeTypeForFile(const QString &fileName,
MimeMatchMode mode = MimeMatchMode::MatchDefault); MimeMatchMode mode = MimeMatchMode::MatchDefault);
QTCREATOR_UTILS_EXPORT MimeType mimeTypeForFile(const QFileInfo &fileInfo,
MimeMatchMode mode = MimeMatchMode::MatchDefault);
QTCREATOR_UTILS_EXPORT MimeType mimeTypeForFile(const FilePath &filePath, QTCREATOR_UTILS_EXPORT MimeType mimeTypeForFile(const FilePath &filePath,
MimeMatchMode mode = MimeMatchMode::MatchDefault); MimeMatchMode mode = MimeMatchMode::MatchDefault);
QTCREATOR_UTILS_EXPORT QList<MimeType> mimeTypesForFileName(const QString &fileName); QTCREATOR_UTILS_EXPORT QList<MimeType> mimeTypesForFileName(const QString &fileName);

View File

@@ -85,13 +85,22 @@ enum class ProcessSignalType {
Done Done
}; };
class QTCREATOR_UTILS_EXPORT ProcessBlockingInterface : public QObject
{
private:
// Wait for:
// - Started is being called only in Starting state.
// - ReadyRead is being called in Starting or Running state.
// - Done is being called in Starting or Running state.
virtual bool waitForSignal(ProcessSignalType signalType, int msecs) = 0;
friend class Internal::QtcProcessPrivate;
};
class QTCREATOR_UTILS_EXPORT ProcessInterface : public QObject class QTCREATOR_UTILS_EXPORT ProcessInterface : public QObject
{ {
Q_OBJECT Q_OBJECT
public:
ProcessInterface(QObject *parent = nullptr) : QObject(parent) {}
signals: signals:
// This should be emitted when being in Starting state only. // This should be emitted when being in Starting state only.
// After emitting this signal the process enters Running state. // After emitting this signal the process enters Running state.
@@ -121,14 +130,7 @@ private:
// It's being called in Starting or Running state. // It's being called in Starting or Running state.
virtual void sendControlSignal(ControlSignal controlSignal) = 0; virtual void sendControlSignal(ControlSignal controlSignal) = 0;
// It's being called only in Starting state. virtual ProcessBlockingInterface *processBlockingInterface() const { return nullptr; }
virtual bool waitForStarted(int msecs) = 0;
// It's being called in Starting or Running state.
virtual bool waitForReadyRead(int msecs) = 0;
// It's being called in Starting or Running state.
virtual bool waitForFinished(int msecs) = 0;
friend class QtcProcess; friend class QtcProcess;
friend class Internal::QtcProcessPrivate; friend class Internal::QtcProcessPrivate;

View File

@@ -322,10 +322,34 @@ bool DefaultImpl::ensureProgramExists(const QString &program)
return false; return false;
} }
class QProcessBlockingImpl : public ProcessBlockingInterface
{
public:
QProcessBlockingImpl(QProcess *process) : m_process(process) {}
private:
bool waitForSignal(ProcessSignalType signalType, int msecs) final
{
switch (signalType) {
case ProcessSignalType::Started:
return m_process->waitForStarted(msecs);
case ProcessSignalType::ReadyRead:
return m_process->waitForReadyRead(msecs);
case ProcessSignalType::Done:
return m_process->waitForFinished(msecs);
}
return false;
}
QProcess *m_process = nullptr;
};
class QProcessImpl final : public DefaultImpl class QProcessImpl final : public DefaultImpl
{ {
public: public:
QProcessImpl() : m_process(new ProcessHelper(this)) QProcessImpl()
: m_process(new ProcessHelper(this))
, m_blockingImpl(new QProcessBlockingImpl(m_process))
{ {
connect(m_process, &QProcess::started, connect(m_process, &QProcess::started,
this, &QProcessImpl::handleStarted); this, &QProcessImpl::handleStarted);
@@ -361,9 +385,7 @@ private:
} }
} }
bool waitForStarted(int msecs) final { return m_process->waitForStarted(msecs); } virtual ProcessBlockingInterface *processBlockingInterface() const { return m_blockingImpl; }
bool waitForReadyRead(int msecs) final { return m_process->waitForReadyRead(msecs); }
bool waitForFinished(int msecs) final { return m_process->waitForFinished(msecs); }
void doDefaultStart(const QString &program, const QStringList &arguments) final void doDefaultStart(const QString &program, const QStringList &arguments) final
{ {
@@ -411,7 +433,8 @@ private:
emit done(result); emit done(result);
} }
ProcessHelper *m_process; ProcessHelper *m_process = nullptr;
QProcessBlockingImpl *m_blockingImpl = nullptr;
}; };
static uint uniqueToken() static uint uniqueToken()
@@ -420,6 +443,33 @@ static uint uniqueToken()
return ++globalUniqueToken; return ++globalUniqueToken;
} }
class ProcessLauncherBlockingImpl : public ProcessBlockingInterface
{
public:
ProcessLauncherBlockingImpl(CallerHandle *caller) : m_caller(caller) {}
private:
bool waitForSignal(ProcessSignalType signalType, int msecs) final
{
// TODO: Remove CallerHandle::SignalType
const CallerHandle::SignalType type = [signalType] {
switch (signalType) {
case ProcessSignalType::Started:
return CallerHandle::SignalType::Started;
case ProcessSignalType::ReadyRead:
return CallerHandle::SignalType::ReadyRead;
case ProcessSignalType::Done:
return CallerHandle::SignalType::Done;
}
QTC_CHECK(false);
return CallerHandle::SignalType::NoSignal;
}();
return m_caller->waitForSignal(type, msecs);
}
CallerHandle *m_caller = nullptr;
};
class ProcessLauncherImpl final : public DefaultImpl class ProcessLauncherImpl final : public DefaultImpl
{ {
Q_OBJECT Q_OBJECT
@@ -434,6 +484,7 @@ public:
this, &ProcessInterface::readyRead); this, &ProcessInterface::readyRead);
connect(m_handle, &CallerHandle::done, connect(m_handle, &CallerHandle::done,
this, &ProcessInterface::done); this, &ProcessInterface::done);
m_blockingImpl = new ProcessLauncherBlockingImpl(m_handle);
} }
~ProcessLauncherImpl() final ~ProcessLauncherImpl() final
{ {
@@ -462,9 +513,7 @@ private:
} }
} }
bool waitForStarted(int msecs) final { return m_handle->waitForStarted(msecs); } virtual ProcessBlockingInterface *processBlockingInterface() const { return m_blockingImpl; }
bool waitForReadyRead(int msecs) final { return m_handle->waitForReadyRead(msecs); }
bool waitForFinished(int msecs) final { return m_handle->waitForFinished(msecs); }
void doDefaultStart(const QString &program, const QStringList &arguments) final void doDefaultStart(const QString &program, const QStringList &arguments) final
{ {
@@ -476,6 +525,7 @@ private:
const uint m_token = 0; const uint m_token = 0;
// Lives in caller's thread. // Lives in caller's thread.
CallerHandle *m_handle = nullptr; CallerHandle *m_handle = nullptr;
ProcessLauncherBlockingImpl *m_blockingImpl = nullptr;
}; };
static ProcessImpl defaultProcessImpl() static ProcessImpl defaultProcessImpl()
@@ -535,13 +585,15 @@ private:
const ProcessResultData m_resultData; const ProcessResultData m_resultData;
}; };
class GeneralProcessBlockingImpl;
class ProcessInterfaceHandler : public QObject class ProcessInterfaceHandler : public QObject
{ {
public: public:
ProcessInterfaceHandler(QtcProcessPrivate *caller, ProcessInterface *process); ProcessInterfaceHandler(GeneralProcessBlockingImpl *caller, ProcessInterface *process);
// Called from caller's thread exclusively. // Called from caller's thread exclusively.
bool waitForSignal(int msecs, ProcessSignalType newSignal); bool waitForSignal(ProcessSignalType newSignal, int msecs);
void moveToCallerThread(); void moveToCallerThread();
private: private:
@@ -555,11 +607,44 @@ private:
void handleDone(const ProcessResultData &data); void handleDone(const ProcessResultData &data);
void appendSignal(ProcessInterfaceSignal *newSignal); void appendSignal(ProcessInterfaceSignal *newSignal);
QtcProcessPrivate *m_caller = nullptr; GeneralProcessBlockingImpl *m_caller = nullptr;
QMutex m_mutex; QMutex m_mutex;
QWaitCondition m_waitCondition; QWaitCondition m_waitCondition;
}; };
class GeneralProcessBlockingImpl : public ProcessBlockingInterface
{
public:
GeneralProcessBlockingImpl(QtcProcessPrivate *parent);
void flush() { flushSignals(takeAllSignals()); }
bool flushFor(ProcessSignalType signalType) {
return flushSignals(takeSignalsFor(signalType), &signalType);
}
bool shouldFlush() const { QMutexLocker locker(&m_mutex); return !m_signals.isEmpty(); }
// Called from ProcessInterfaceHandler thread exclusively.
void appendSignal(ProcessInterfaceSignal *launcherSignal);
private:
// Called from caller's thread exclusively
bool waitForSignal(ProcessSignalType newSignal, int msecs) final;
QList<ProcessInterfaceSignal *> takeAllSignals();
QList<ProcessInterfaceSignal *> takeSignalsFor(ProcessSignalType signalType);
bool flushSignals(const QList<ProcessInterfaceSignal *> &signalList,
ProcessSignalType *signalType = nullptr);
void handleStartedSignal(const StartedSignal *launcherSignal);
void handleReadyReadSignal(const ReadyReadSignal *launcherSignal);
void handleDoneSignal(const DoneSignal *launcherSignal);
QtcProcessPrivate *m_caller = nullptr;
std::unique_ptr<ProcessInterfaceHandler> m_processHandler;
mutable QMutex m_mutex;
QList<ProcessInterfaceSignal *> m_signals;
};
class QtcProcessPrivate : public QObject class QtcProcessPrivate : public QObject
{ {
public: public:
@@ -591,11 +676,18 @@ public:
void setProcessInterface(ProcessInterface *process) void setProcessInterface(ProcessInterface *process)
{ {
m_process.reset(process); m_process.reset(process);
m_processHandler.reset(new ProcessInterfaceHandler(this, process)); m_process->setParent(this);
connect(m_process.get(), &ProcessInterface::started,
this, &QtcProcessPrivate::handleStarted);
connect(m_process.get(), &ProcessInterface::readyRead,
this, &QtcProcessPrivate::handleReadyRead);
connect(m_process.get(), &ProcessInterface::done,
this, &QtcProcessPrivate::handleDone);
// In order to move the process into another thread together with handle m_blockingInterface.reset(process->processBlockingInterface());
m_process->setParent(m_processHandler.get()); if (!m_blockingInterface)
m_processHandler->setParent(this); m_blockingInterface.reset(new GeneralProcessBlockingImpl(this));
m_blockingInterface->setParent(this);
} }
CommandLine fullCommandLine() const CommandLine fullCommandLine() const
@@ -624,14 +716,11 @@ public:
} }
QtcProcess *q; QtcProcess *q;
std::unique_ptr<ProcessInterfaceHandler> m_processHandler; std::unique_ptr<ProcessBlockingInterface> m_blockingInterface;
std::unique_ptr<ProcessInterface> m_process; std::unique_ptr<ProcessInterface> m_process;
ProcessSetupData m_setup; ProcessSetupData m_setup;
void slotTimeout(); void slotTimeout();
void handleStartedSignal(const StartedSignal *launcherSignal);
void handleReadyReadSignal(const ReadyReadSignal *launcherSignal);
void handleDoneSignal(const DoneSignal *launcherSignal);
void handleStarted(qint64 processId, qint64 applicationMainThreadId); void handleStarted(qint64 processId, qint64 applicationMainThreadId);
void handleReadyRead(const QByteArray &outputData, const QByteArray &errorData); void handleReadyRead(const QByteArray &outputData, const QByteArray &errorData);
void handleDone(const ProcessResultData &data); void handleDone(const ProcessResultData &data);
@@ -647,31 +736,11 @@ public:
ProcessResult interpretExitCode(int exitCode); ProcessResult interpretExitCode(int exitCode);
// === ProcessInterfaceHandler related === bool waitForSignal(ProcessSignalType signalType, int msecs);
// Called from caller's thread exclusively
bool waitForSignal(int msecs, ProcessSignalType newSignal);
void flush() { flushSignals(takeAllSignals()); }
bool flushFor(ProcessSignalType signalType) {
return flushSignals(takeSignalsFor(signalType), &signalType);
}
QList<ProcessInterfaceSignal *> takeAllSignals();
QList<ProcessInterfaceSignal *> takeSignalsFor(ProcessSignalType signalType);
bool flushSignals(const QList<ProcessInterfaceSignal *> &signalList,
ProcessSignalType *signalType = nullptr);
bool shouldFlush() const { QMutexLocker locker(&m_mutex); return !m_signals.isEmpty(); }
Qt::ConnectionType connectionType() const; Qt::ConnectionType connectionType() const;
void sendControlSignal(ControlSignal controlSignal); void sendControlSignal(ControlSignal controlSignal);
// Called from ProcessInterfaceHandler thread exclusively.
void appendSignal(ProcessInterfaceSignal *launcherSignal);
mutable QMutex m_mutex;
QList<ProcessInterfaceSignal *> m_signals;
QTimer m_killTimer; QTimer m_killTimer;
// =======================================
QProcess::ProcessState m_state = QProcess::NotRunning; QProcess::ProcessState m_state = QProcess::NotRunning;
qint64 m_processId = 0; qint64 m_processId = 0;
qint64 m_applicationMainThreadId = 0; qint64 m_applicationMainThreadId = 0;
@@ -692,10 +761,11 @@ public:
Guard m_guard; Guard m_guard;
}; };
ProcessInterfaceHandler::ProcessInterfaceHandler(QtcProcessPrivate *caller, ProcessInterfaceHandler::ProcessInterfaceHandler(GeneralProcessBlockingImpl *caller,
ProcessInterface *process) ProcessInterface *process)
: m_caller(caller) : m_caller(caller)
{ {
process->disconnect();
connect(process, &ProcessInterface::started, connect(process, &ProcessInterface::started,
this, &ProcessInterfaceHandler::handleStarted); this, &ProcessInterfaceHandler::handleStarted);
connect(process, &ProcessInterface::readyRead, connect(process, &ProcessInterface::readyRead,
@@ -705,7 +775,7 @@ ProcessInterfaceHandler::ProcessInterfaceHandler(QtcProcessPrivate *caller,
} }
// Called from caller's thread exclusively. // Called from caller's thread exclusively.
bool ProcessInterfaceHandler::waitForSignal(int msecs, ProcessSignalType newSignal) bool ProcessInterfaceHandler::waitForSignal(ProcessSignalType newSignal, int msecs)
{ {
QDeadlineTimer deadline(msecs); QDeadlineTimer deadline(msecs);
while (true) { while (true) {
@@ -769,17 +839,20 @@ void ProcessInterfaceHandler::appendSignal(ProcessInterfaceSignal *newSignal)
} }
m_waitCondition.wakeOne(); m_waitCondition.wakeOne();
// call in callers thread // call in callers thread
QMetaObject::invokeMethod(m_caller, &QtcProcessPrivate::flush); QMetaObject::invokeMethod(m_caller, &GeneralProcessBlockingImpl::flush);
} }
// Called from caller's thread exclusively GeneralProcessBlockingImpl::GeneralProcessBlockingImpl(QtcProcessPrivate *parent)
bool QtcProcessPrivate::waitForSignal(int msecs, ProcessSignalType newSignal) : m_caller(parent)
, m_processHandler(new ProcessInterfaceHandler(this, parent->m_process.get()))
{ {
const QDeadlineTimer timeout(msecs); // In order to move the process interface into another thread together with handle
const QDeadlineTimer currentKillTimeout(m_killTimer.remainingTime()); parent->m_process.get()->setParent(m_processHandler.get());
const bool needsSplit = m_killTimer.isActive() ? timeout > currentKillTimeout : false; m_processHandler->setParent(this);
const QDeadlineTimer mainTimeout = needsSplit ? currentKillTimeout : timeout; }
bool GeneralProcessBlockingImpl::waitForSignal(ProcessSignalType newSignal, int msecs)
{
m_processHandler->setParent(nullptr); m_processHandler->setParent(nullptr);
QThread thread; QThread thread;
@@ -789,12 +862,7 @@ bool QtcProcessPrivate::waitForSignal(int msecs, ProcessSignalType newSignal)
// the caller here is blocked, so all signals should be buffered and we are going // the caller here is blocked, so all signals should be buffered and we are going
// to flush them from inside waitForSignal(). // to flush them from inside waitForSignal().
m_processHandler->moveToThread(&thread); m_processHandler->moveToThread(&thread);
bool result = m_processHandler->waitForSignal(mainTimeout.remainingTime(), newSignal); const bool result = m_processHandler->waitForSignal(newSignal, msecs);
if (!result && needsSplit) {
m_killTimer.stop();
sendControlSignal(ControlSignal::Kill);
result = m_processHandler->waitForSignal(timeout.remainingTime(), newSignal);
}
m_processHandler->moveToCallerThread(); m_processHandler->moveToCallerThread();
m_processHandler->setParent(this); m_processHandler->setParent(this);
thread.quit(); thread.quit();
@@ -803,14 +871,14 @@ bool QtcProcessPrivate::waitForSignal(int msecs, ProcessSignalType newSignal)
} }
// Called from caller's thread exclusively // Called from caller's thread exclusively
QList<ProcessInterfaceSignal *> QtcProcessPrivate::takeAllSignals() QList<ProcessInterfaceSignal *> GeneralProcessBlockingImpl::takeAllSignals()
{ {
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
return std::exchange(m_signals, {}); return std::exchange(m_signals, {});
} }
// Called from caller's thread exclusively // Called from caller's thread exclusively
QList<ProcessInterfaceSignal *> QtcProcessPrivate::takeSignalsFor(ProcessSignalType signalType) QList<ProcessInterfaceSignal *> GeneralProcessBlockingImpl::takeSignalsFor(ProcessSignalType signalType)
{ {
// If we are flushing for ReadyRead or Done - flush all. // If we are flushing for ReadyRead or Done - flush all.
if (signalType != ProcessSignalType::Started) if (signalType != ProcessSignalType::Started)
@@ -840,7 +908,7 @@ QList<ProcessInterfaceSignal *> QtcProcessPrivate::takeSignalsFor(ProcessSignalT
} }
// Called from caller's thread exclusively // Called from caller's thread exclusively
bool QtcProcessPrivate::flushSignals(const QList<ProcessInterfaceSignal *> &signalList, bool GeneralProcessBlockingImpl::flushSignals(const QList<ProcessInterfaceSignal *> &signalList,
ProcessSignalType *signalType) ProcessSignalType *signalType)
{ {
bool signalMatched = false; bool signalMatched = false;
@@ -866,14 +934,50 @@ bool QtcProcessPrivate::flushSignals(const QList<ProcessInterfaceSignal *> &sign
return signalMatched; return signalMatched;
} }
// Called from caller's thread exclusively void GeneralProcessBlockingImpl::handleStartedSignal(const StartedSignal *aSignal)
{
m_caller->handleStarted(aSignal->processId(), aSignal->applicationMainThreadId());
}
void GeneralProcessBlockingImpl::handleReadyReadSignal(const ReadyReadSignal *aSignal)
{
m_caller->handleReadyRead(aSignal->stdOut(), aSignal->stdErr());
}
void GeneralProcessBlockingImpl::handleDoneSignal(const DoneSignal *aSignal)
{
m_caller->handleDone(aSignal->resultData());
}
// Called from ProcessInterfaceHandler thread exclusively.
void GeneralProcessBlockingImpl::appendSignal(ProcessInterfaceSignal *newSignal)
{
QMutexLocker locker(&m_mutex);
m_signals.append(newSignal);
}
bool QtcProcessPrivate::waitForSignal(ProcessSignalType newSignal, int msecs)
{
const QDeadlineTimer timeout(msecs);
const QDeadlineTimer currentKillTimeout(m_killTimer.remainingTime());
const bool needsSplit = m_killTimer.isActive() ? timeout > currentKillTimeout : false;
const QDeadlineTimer mainTimeout = needsSplit ? currentKillTimeout : timeout;
bool result = m_blockingInterface->waitForSignal(newSignal, mainTimeout.remainingTime());
if (!result && needsSplit) {
m_killTimer.stop();
sendControlSignal(ControlSignal::Kill);
result = m_blockingInterface->waitForSignal(newSignal, timeout.remainingTime());
}
return result;
}
Qt::ConnectionType QtcProcessPrivate::connectionType() const Qt::ConnectionType QtcProcessPrivate::connectionType() const
{ {
return (m_process->thread() == thread()) ? Qt::DirectConnection return (m_process->thread() == thread()) ? Qt::DirectConnection
: Qt::BlockingQueuedConnection; : Qt::BlockingQueuedConnection;
} }
// Called from caller's thread exclusively
void QtcProcessPrivate::sendControlSignal(ControlSignal controlSignal) void QtcProcessPrivate::sendControlSignal(ControlSignal controlSignal)
{ {
QTC_ASSERT(QThread::currentThread() == thread(), return); QTC_ASSERT(QThread::currentThread() == thread(), return);
@@ -885,13 +989,6 @@ void QtcProcessPrivate::sendControlSignal(ControlSignal controlSignal)
}, connectionType()); }, connectionType());
} }
// Called from ProcessInterfaceHandler thread exclusively.
void QtcProcessPrivate::appendSignal(ProcessInterfaceSignal *newSignal)
{
QMutexLocker locker(&m_mutex);
m_signals.append(newSignal);
}
void QtcProcessPrivate::clearForRun() void QtcProcessPrivate::clearForRun()
{ {
m_hangTimerCount = 0; m_hangTimerCount = 0;
@@ -1188,17 +1285,6 @@ void QtcProcess::setRemoteProcessHooks(const DeviceProcessHooks &hooks)
s_deviceHooks = hooks; s_deviceHooks = hooks;
} }
void QtcProcess::stopProcess()
{
if (state() == QProcess::NotRunning)
return;
terminate();
if (waitForFinished(300))
return;
kill();
waitForFinished(300);
}
static bool askToKill(const QString &command) static bool askToKill(const QString &command)
{ {
#ifdef QT_GUI_LIB #ifdef QT_GUI_LIB
@@ -1275,7 +1361,7 @@ bool QtcProcess::readDataFromProcess(int timeoutS,
QString QtcProcess::normalizeNewlines(const QString &text) QString QtcProcess::normalizeNewlines(const QString &text)
{ {
QString res = text; QString res = text;
const auto newEnd = std::unique(res.begin(), res.end(), [](const QChar &c1, const QChar &c2) { const auto newEnd = std::unique(res.begin(), res.end(), [](const QChar c1, const QChar c2) {
return c1 == '\r' && c2 == '\r'; // QTCREATORBUG-24556 return c1 == '\r' && c2 == '\r'; // QTCREATORBUG-24556
}); });
res.chop(std::distance(newEnd, res.end())); res.chop(std::distance(newEnd, res.end()));
@@ -1444,8 +1530,8 @@ bool QtcProcess::waitForStarted(int msecs)
return true; return true;
if (d->m_state == QProcess::NotRunning) if (d->m_state == QProcess::NotRunning)
return false; return false;
return s_waitForStarted.measureAndRun(&QtcProcessPrivate::waitForSignal, d, msecs, return s_waitForStarted.measureAndRun(&QtcProcessPrivate::waitForSignal, d,
ProcessSignalType::Started); ProcessSignalType::Started, msecs);
} }
bool QtcProcess::waitForReadyRead(int msecs) bool QtcProcess::waitForReadyRead(int msecs)
@@ -1453,7 +1539,7 @@ bool QtcProcess::waitForReadyRead(int msecs)
QTC_ASSERT(d->m_process, return false); QTC_ASSERT(d->m_process, return false);
if (d->m_state == QProcess::NotRunning) if (d->m_state == QProcess::NotRunning)
return false; return false;
return d->waitForSignal(msecs, ProcessSignalType::ReadyRead); return d->waitForSignal(ProcessSignalType::ReadyRead, msecs);
} }
bool QtcProcess::waitForFinished(int msecs) bool QtcProcess::waitForFinished(int msecs)
@@ -1461,7 +1547,7 @@ bool QtcProcess::waitForFinished(int msecs)
QTC_ASSERT(d->m_process, return false); QTC_ASSERT(d->m_process, return false);
if (d->m_state == QProcess::NotRunning) if (d->m_state == QProcess::NotRunning)
return false; return false;
return d->waitForSignal(msecs, ProcessSignalType::Done); return d->waitForSignal(ProcessSignalType::Done, msecs);
} }
QByteArray QtcProcess::readAllStandardOutput() QByteArray QtcProcess::readAllStandardOutput()
@@ -1511,9 +1597,9 @@ void QtcProcess::close()
d->m_process->disconnect(); d->m_process->disconnect();
d->m_process.release()->deleteLater(); d->m_process.release()->deleteLater();
} }
if (d->m_processHandler) { if (d->m_blockingInterface) {
d->m_processHandler->disconnect(); d->m_blockingInterface->disconnect();
d->m_processHandler.release()->deleteLater(); d->m_blockingInterface.release()->deleteLater();
} }
d->clearForRun(); d->clearForRun();
} }
@@ -1618,10 +1704,16 @@ QString QtcProcess::allOutput() const
return !out.isEmpty() ? out : err; return !out.isEmpty() ? out : err;
} }
QByteArray QtcProcess::rawStdOut() const
{
QTC_CHECK(d->m_stdOut.keepRawData);
return d->m_stdOut.rawData;
}
QString QtcProcess::stdOut() const QString QtcProcess::stdOut() const
{ {
QTC_CHECK(d->m_stdOut.keepRawData); QTC_CHECK(d->m_stdOut.keepRawData);
return normalizeNewlines(d->m_codec->toUnicode(d->m_stdOut.rawData)); return d->m_codec->toUnicode(d->m_stdOut.rawData);
} }
QString QtcProcess::stdErr() const QString QtcProcess::stdErr() const
@@ -1631,13 +1723,37 @@ QString QtcProcess::stdErr() const
// is not trivial. So weaken it a bit for now. // is not trivial. So weaken it a bit for now.
//QTC_CHECK(d->m_stdErr.keepRawData); //QTC_CHECK(d->m_stdErr.keepRawData);
QTC_CHECK(d->m_stdErr.keepRawData || d->m_stdErr.rawData.isEmpty()); QTC_CHECK(d->m_stdErr.keepRawData || d->m_stdErr.rawData.isEmpty());
return normalizeNewlines(d->m_codec->toUnicode(d->m_stdErr.rawData)); return d->m_codec->toUnicode(d->m_stdErr.rawData);
} }
QByteArray QtcProcess::rawStdOut() const QString QtcProcess::cleanedStdOut() const
{ {
QTC_CHECK(d->m_stdOut.keepRawData); return normalizeNewlines(stdOut());
return d->m_stdOut.rawData; }
QString QtcProcess::cleanedStdErr() const
{
return normalizeNewlines(stdErr());
}
static QStringList splitLines(const QString &text)
{
QStringList result = text.split('\n');
for (QString &line : result) {
if (line.endsWith('\r'))
line.chop(1);
}
return result;
}
const QStringList QtcProcess::stdOutLines() const
{
return splitLines(stdOut());
}
const QStringList QtcProcess::stdErrLines() const
{
return splitLines(stdErr());
} }
QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const QtcProcess &r) QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const QtcProcess &r)
@@ -1843,7 +1959,8 @@ void QtcProcessPrivate::slotTimeout()
|| askToKill(m_setup.m_commandLine.executable().toString()); || askToKill(m_setup.m_commandLine.executable().toString());
m_waitingForUser = false; m_waitingForUser = false;
if (terminate) { if (terminate) {
q->stopProcess(); q->stop();
q->waitForFinished();
m_result = ProcessResult::Hang; m_result = ProcessResult::Hang;
} else { } else {
m_hangTimerCount = 0; m_hangTimerCount = 0;
@@ -1854,22 +1971,6 @@ void QtcProcessPrivate::slotTimeout()
} }
} }
void QtcProcessPrivate::handleStartedSignal(const StartedSignal *aSignal)
{
handleStarted(aSignal->processId(), aSignal->applicationMainThreadId());
}
void QtcProcessPrivate::handleReadyReadSignal(const ReadyReadSignal *aSignal)
{
handleReadyRead(aSignal->stdOut(), aSignal->stdErr());
}
void QtcProcessPrivate::handleDoneSignal(const DoneSignal *aSignal)
{
m_killTimer.stop();
handleDone(aSignal->resultData());
}
void QtcProcessPrivate::handleStarted(qint64 processId, qint64 applicationMainThreadId) void QtcProcessPrivate::handleStarted(qint64 processId, qint64 applicationMainThreadId)
{ {
QTC_CHECK(m_state == QProcess::Starting); QTC_CHECK(m_state == QProcess::Starting);
@@ -1908,6 +2009,7 @@ void QtcProcessPrivate::handleReadyRead(const QByteArray &outputData, const QByt
void QtcProcessPrivate::handleDone(const ProcessResultData &data) void QtcProcessPrivate::handleDone(const ProcessResultData &data)
{ {
m_killTimer.stop();
m_resultData = data; m_resultData = data;
switch (m_state) { switch (m_state) {

View File

@@ -175,7 +175,6 @@ public:
void setStdErrCallback(const std::function<void(const QString &)> &callback); void setStdErrCallback(const std::function<void(const QString &)> &callback);
void setStdErrLineCallback(const std::function<void(const QString &)> &callback); void setStdErrLineCallback(const std::function<void(const QString &)> &callback);
void stopProcess();
bool readDataFromProcess(int timeoutS, QByteArray *stdOut, QByteArray *stdErr, bool readDataFromProcess(int timeoutS, QByteArray *stdOut, QByteArray *stdErr,
bool showTimeOutMessageBox); bool showTimeOutMessageBox);
@@ -185,11 +184,17 @@ public:
QByteArray allRawOutput() const; QByteArray allRawOutput() const;
QString allOutput() const; QString allOutput() const;
QString stdOut() const;
QString stdErr() const;
QByteArray rawStdOut() const; QByteArray rawStdOut() const;
QString stdOut() const; // possibly with CR
QString stdErr() const; // possibly with CR
QString cleanedStdOut() const; // with CR removed
QString cleanedStdErr() const; // with CR removed
const QStringList stdOutLines() const; // split, CR removed
const QStringList stdErrLines() const; // split, CR removed
QString exitMessage() const; QString exitMessage() const;
QString toStandaloneCommandLine() const; QString toStandaloneCommandLine() const;

View File

@@ -368,7 +368,10 @@ void ShellCommand::runFullySynchronous(QtcProcess &process, const FilePath &work
void ShellCommand::runSynchronous(QtcProcess &process, const FilePath &workingDirectory) void ShellCommand::runSynchronous(QtcProcess &process, const FilePath &workingDirectory)
{ {
connect(this, &ShellCommand::terminate, &process, &QtcProcess::stopProcess); connect(this, &ShellCommand::terminate, &process, [&process] {
process.stop();
process.waitForFinished();
});
process.setEnvironment(processEnvironment()); process.setEnvironment(processEnvironment());
if (d->m_codec) if (d->m_codec)
process.setCodec(d->m_codec); process.setCodec(d->m_codec);

View File

@@ -50,12 +50,6 @@ private:
qint64 write(const QByteArray &) final { QTC_CHECK(false); return -1; } qint64 write(const QByteArray &) final { QTC_CHECK(false); return -1; }
void sendControlSignal(ControlSignal controlSignal) final; void sendControlSignal(ControlSignal controlSignal) final;
// intentionally no-op without an assert
bool waitForStarted(int) final { return false; }
bool waitForReadyRead(int) final { QTC_CHECK(false); return false; }
// intentionally no-op without an assert
bool waitForFinished(int) final { return false; }
// OK, however, impl looks a bit different (!= NotRunning vs == Running). // OK, however, impl looks a bit different (!= NotRunning vs == Running).
// Most probably changing it into (== Running) should be OK. // Most probably changing it into (== Running) should be OK.
bool isRunning() const; bool isRunning() const;

View File

@@ -127,7 +127,7 @@ bool AndroidQmlPreviewWorker::isPreviewRunning(int lastKnownPid) const
void AndroidQmlPreviewWorker::startPidWatcher() void AndroidQmlPreviewWorker::startPidWatcher()
{ {
m_pidFutureWatcher.setFuture(Utils::runAsync([this]() { m_pidFutureWatcher.setFuture(runAsync([this]() {
// wait for started // wait for started
const int sleepTimeMs = 2000; const int sleepTimeMs = 2000;
QDeadlineTimer deadline(20000); QDeadlineTimer deadline(20000);
@@ -157,7 +157,7 @@ void AndroidQmlPreviewWorker::startLogcat()
QString args = QString("logcat --pid=%1").arg(m_viewerPid); QString args = QString("logcat --pid=%1").arg(m_viewerPid);
if (!m_logcatStartTimeStamp.isEmpty()) if (!m_logcatStartTimeStamp.isEmpty())
args += QString(" -T '%1'").arg(m_logcatStartTimeStamp); args += QString(" -T '%1'").arg(m_logcatStartTimeStamp);
Utils::CommandLine cmd(AndroidConfigurations::currentConfig().adbToolPath()); CommandLine cmd(AndroidConfigurations::currentConfig().adbToolPath());
cmd.setArguments(args); cmd.setArguments(args);
m_logcatProcess.setCommand(cmd); m_logcatProcess.setCommand(cmd);
m_logcatProcess.setUseCtrlCStub(true); m_logcatProcess.setUseCtrlCStub(true);
@@ -190,7 +190,7 @@ AndroidQmlPreviewWorker::AndroidQmlPreviewWorker(ProjectExplorer::RunControl *ru
connect(this, &AndroidQmlPreviewWorker::previewPidChanged, connect(this, &AndroidQmlPreviewWorker::previewPidChanged,
this, &AndroidQmlPreviewWorker::startLogcat); this, &AndroidQmlPreviewWorker::startLogcat);
connect(this, &RunWorker::stopped, &m_logcatProcess, &Utils::QtcProcess::stopProcess); connect(this, &RunWorker::stopped, &m_logcatProcess, &QtcProcess::stop);
m_logcatProcess.setStdOutCallback([this](const QString &stdOut) { m_logcatProcess.setStdOutCallback([this](const QString &stdOut) {
filterLogcatAndAppendMessage(stdOut); filterLogcatAndAppendMessage(stdOut);
}); });
@@ -314,7 +314,7 @@ bool AndroidQmlPreviewWorker::preparePreviewArtefacts()
} }
} else { } else {
const FilePaths allFiles = m_rc->project()->files(m_rc->project()->SourceFiles); const FilePaths allFiles = m_rc->project()->files(m_rc->project()->SourceFiles);
const FilePaths filesToExport = Utils::filtered(allFiles,[](const FilePath &path) { const FilePaths filesToExport = filtered(allFiles, [](const FilePath &path) {
return path.suffix() == "qmlproject"; return path.suffix() == "qmlproject";
}); });
@@ -363,7 +363,8 @@ FilePath AndroidQmlPreviewWorker::createQmlrcFile(const FilePath &workFolder,
QByteArray stdOut; QByteArray stdOut;
QByteArray stdErr; QByteArray stdErr;
if (!rccProcess.readDataFromProcess(30, &stdOut, &stdErr, true)) { if (!rccProcess.readDataFromProcess(30, &stdOut, &stdErr, true)) {
rccProcess.stopProcess(); rccProcess.stop();
rccProcess.waitForFinished();
appendMessage(tr("A timeout occurred running \"%1\""). appendMessage(tr("A timeout occurred running \"%1\"").
arg(rccProcess.commandLine().toUserOutput()), StdErrFormat); arg(rccProcess.commandLine().toUserOutput()), StdErrFormat);
qrcPath.removeFile(); qrcPath.removeFile();

View File

@@ -166,8 +166,10 @@ static void sdkManagerCommand(const AndroidConfig &config, const QStringList &ar
proc.setTimeoutS(timeout); proc.setTimeoutS(timeout);
proc.setStdOutCallback([offset, progressQuota, &proc, &assertionFound, &fi](const QString &out) { proc.setStdOutCallback([offset, progressQuota, &proc, &assertionFound, &fi](const QString &out) {
int progressPercent = parseProgress(out, assertionFound); int progressPercent = parseProgress(out, assertionFound);
if (assertionFound) if (assertionFound) {
proc.stopProcess(); proc.stop();
proc.waitForFinished();
}
if (progressPercent != -1) if (progressPercent != -1)
fi.setProgressValue(offset + qRound((progressPercent / 100.0) * progressQuota)); fi.setProgressValue(offset + qRound((progressPercent / 100.0) * progressQuota));
}); });
@@ -175,8 +177,10 @@ static void sdkManagerCommand(const AndroidConfig &config, const QStringList &ar
output.stdError = err; output.stdError = err;
}); });
if (interruptible) { if (interruptible) {
QObject::connect(&sdkManager, &AndroidSdkManager::cancelActiveOperations, QObject::connect(&sdkManager, &AndroidSdkManager::cancelActiveOperations, &proc, [&proc] {
&proc, &QtcProcess::stopProcess); proc.stop();
proc.waitForFinished();
});
} }
proc.setCommand({config.sdkManagerToolPath(), newArgs}); proc.setCommand({config.sdkManagerToolPath(), newArgs});
proc.runBlocking(EventLoopMode::On); proc.runBlocking(EventLoopMode::On);

View File

@@ -39,7 +39,7 @@ namespace Autotest {
namespace Internal { namespace Internal {
TestOutputReader *BoostTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi, TestOutputReader *BoostTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const Utils::QtcProcess *app) const
{ {
auto settings = static_cast<BoostTestSettings *>(framework()->testSettings()); auto settings = static_cast<BoostTestSettings *>(framework()->testSettings());
return new BoostTestOutputReader(fi, app, buildDirectory(), projectFile(), return new BoostTestOutputReader(fi, app, buildDirectory(), projectFile(),

View File

@@ -36,7 +36,7 @@ public:
explicit BoostTestConfiguration(ITestFramework *framework) explicit BoostTestConfiguration(ITestFramework *framework)
: DebuggableTestConfiguration(framework) {} : DebuggableTestConfiguration(framework) {}
TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi, TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const override; Utils::QtcProcess *app) const override;
QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override;
Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; Utils::Environment filteredEnvironment(const Utils::Environment &original) const override;
}; };

View File

@@ -29,6 +29,7 @@
#include "boosttesttreeitem.h" #include "boosttesttreeitem.h"
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
@@ -41,7 +42,7 @@ namespace Internal {
static Q_LOGGING_CATEGORY(orLog, "qtc.autotest.boost.outputreader", QtWarningMsg) static Q_LOGGING_CATEGORY(orLog, "qtc.autotest.boost.outputreader", QtWarningMsg)
BoostTestOutputReader::BoostTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface, BoostTestOutputReader::BoostTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
QProcess *testApplication, Utils::QtcProcess *testApplication,
const Utils::FilePath &buildDirectory, const Utils::FilePath &buildDirectory,
const Utils::FilePath &projectFile, const Utils::FilePath &projectFile,
LogLevel log, ReportLevel report) LogLevel log, ReportLevel report)
@@ -51,7 +52,7 @@ BoostTestOutputReader::BoostTestOutputReader(const QFutureInterface<TestResultPt
, m_reportLevel(report) , m_reportLevel(report)
{ {
if (m_testApplication) { if (m_testApplication) {
connect(m_testApplication, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), connect(m_testApplication, &Utils::QtcProcess::finished,
this, &BoostTestOutputReader::onFinished); this, &BoostTestOutputReader::onFinished);
} }
} }
@@ -405,7 +406,8 @@ TestResultPtr BoostTestOutputReader::createDefaultResult() const
return TestResultPtr(result); return TestResultPtr(result);
} }
void BoostTestOutputReader::onFinished(int exitCode, QProcess::ExitStatus /*exitState*/) { void BoostTestOutputReader::onFinished() {
int exitCode = m_testApplication->exitCode();
if (m_reportLevel == ReportLevel::No && m_testCaseCount != -1) { if (m_reportLevel == ReportLevel::No && m_testCaseCount != -1) {
int reportedFailsAndSkips = m_summary[ResultType::Fail] + m_summary[ResultType::Skip]; int reportedFailsAndSkips = m_summary[ResultType::Fail] + m_summary[ResultType::Skip];
m_summary.insert(ResultType::Pass, m_testCaseCount - reportedFailsAndSkips); m_summary.insert(ResultType::Pass, m_testCaseCount - reportedFailsAndSkips);

View File

@@ -39,7 +39,7 @@ class BoostTestOutputReader : public TestOutputReader
Q_OBJECT Q_OBJECT
public: public:
BoostTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface, BoostTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
QProcess *testApplication, const Utils::FilePath &buildDirectory, Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory,
const Utils::FilePath &projectFile, LogLevel log, ReportLevel report); const Utils::FilePath &projectFile, LogLevel log, ReportLevel report);
protected: protected:
void processOutputLine(const QByteArray &outputLine) override; void processOutputLine(const QByteArray &outputLine) override;
@@ -47,7 +47,7 @@ protected:
TestResultPtr createDefaultResult() const override; TestResultPtr createDefaultResult() const override;
private: private:
void onFinished(int exitCode, QProcess::ExitStatus /*exitState*/); void onFinished();
void sendCompleteInformation(); void sendCompleteInformation();
void handleMessageMatch(const QRegularExpressionMatch &match); void handleMessageMatch(const QRegularExpressionMatch &match);
void reportNoOutputFinish(const QString &description, ResultType type); void reportNoOutputFinish(const QString &description, ResultType type);

View File

@@ -90,22 +90,24 @@ void CatchCodeParser::handleIdentifier()
QTC_ASSERT(m_currentIndex < m_tokens.size(), return); QTC_ASSERT(m_currentIndex < m_tokens.size(), return);
const Token &token = m_tokens.at(m_currentIndex); const Token &token = m_tokens.at(m_currentIndex);
const QByteArray &identifier = m_source.mid(int(token.bytesBegin()), int(token.bytes())); const QByteArray &identifier = m_source.mid(int(token.bytesBegin()), int(token.bytes()));
if (identifier == "TEST_CASE") { const QByteArray unprefixed = identifier.startsWith("CATCH_") ? identifier.mid(6) : identifier;
if (unprefixed == "TEST_CASE") {
handleTestCase(false); handleTestCase(false);
} else if (identifier == "SCENARIO") { } else if (unprefixed == "SCENARIO") {
handleTestCase(true); handleTestCase(true);
} else if (identifier == "TEMPLATE_TEST_CASE" || identifier == "TEMPLATE_PRODUCT_TEST_CASE" } else if (unprefixed == "TEMPLATE_TEST_CASE" || unprefixed == "TEMPLATE_PRODUCT_TEST_CASE"
|| identifier == "TEMPLATE_LIST_TEST_CASE" || identifier == "TEMPLATE_TEST_CASE_SIG" || unprefixed == "TEMPLATE_LIST_TEST_CASE" || unprefixed == "TEMPLATE_TEST_CASE_SIG"
|| identifier == "TEMPLATE_PRODUCT_TEST_CASE_SIG") { || unprefixed == "TEMPLATE_PRODUCT_TEST_CASE_SIG") {
handleParameterizedTestCase(false); handleParameterizedTestCase(false);
} else if (identifier == "TEST_CASE_METHOD") { } else if (unprefixed == "TEST_CASE_METHOD") {
handleFixtureOrRegisteredTestCase(true); handleFixtureOrRegisteredTestCase(true);
} else if (identifier == "TEMPLATE_TEST_CASE_METHOD_SIG" } else if (unprefixed == "TEMPLATE_TEST_CASE_METHOD_SIG"
|| identifier == "TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG" || unprefixed == "TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG"
|| identifier == "TEMPLATE_TEST_CASE_METHOD" || unprefixed == "TEMPLATE_TEST_CASE_METHOD"
|| identifier == "TEMPLATE_LIST_TEST_CASE_METHOD") { || unprefixed == "TEMPLATE_LIST_TEST_CASE_METHOD") {
handleParameterizedTestCase(true); handleParameterizedTestCase(true);
} else if (identifier == "METHOD_AS_TEST_CASE" || identifier == "REGISTER_TEST_CASE") { } else if (unprefixed == "METHOD_AS_TEST_CASE" || unprefixed == "REGISTER_TEST_CASE") {
handleFixtureOrRegisteredTestCase(false); handleFixtureOrRegisteredTestCase(false);
} }
} }

View File

@@ -35,7 +35,8 @@
namespace Autotest { namespace Autotest {
namespace Internal { namespace Internal {
TestOutputReader *CatchConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi, QProcess *app) const TestOutputReader *CatchConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi,
Utils::QtcProcess *app) const
{ {
return new CatchOutputReader(fi, app, buildDirectory(), projectFile()); return new CatchOutputReader(fi, app, buildDirectory(), projectFile());
} }
@@ -97,7 +98,7 @@ QStringList CatchConfiguration::argumentsForTestRunner(QStringList *omitted) con
{ {
QStringList arguments; QStringList arguments;
if (testCaseCount()) if (testCaseCount())
arguments << "\"" + testCases().join("\",\"") + "\""; arguments << "\"" + testCases().join("\", \"") + "\"";
arguments << "--reporter" << "xml"; arguments << "--reporter" << "xml";
if (AutotestPlugin::settings()->processArgs) { if (AutotestPlugin::settings()->processArgs) {

View File

@@ -34,7 +34,7 @@ class CatchConfiguration : public DebuggableTestConfiguration
public: public:
CatchConfiguration(ITestFramework *framework) : DebuggableTestConfiguration(framework) {} CatchConfiguration(ITestFramework *framework) : DebuggableTestConfiguration(framework) {}
TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi, TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const override; Utils::QtcProcess *app) const override;
QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override;
Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; Utils::Environment filteredEnvironment(const Utils::Environment &original) const override;
}; };

View File

@@ -49,7 +49,8 @@ namespace CatchXml {
} }
CatchOutputReader::CatchOutputReader(const QFutureInterface<TestResultPtr> &futureInterface, CatchOutputReader::CatchOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
QProcess *testApplication, const Utils::FilePath &buildDirectory, Utils::QtcProcess *testApplication,
const Utils::FilePath &buildDirectory,
const Utils::FilePath &projectFile) const Utils::FilePath &projectFile)
: TestOutputReader (futureInterface, testApplication, buildDirectory) : TestOutputReader (futureInterface, testApplication, buildDirectory)
, m_projectFile(projectFile) , m_projectFile(projectFile)

View File

@@ -39,7 +39,7 @@ class CatchOutputReader : public TestOutputReader
public: public:
CatchOutputReader(const QFutureInterface<TestResultPtr> &futureInterface, CatchOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
QProcess *testApplication, const Utils::FilePath &buildDirectory, Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory,
const Utils::FilePath &projectFile); const Utils::FilePath &projectFile);
protected: protected:

View File

@@ -57,10 +57,11 @@ static bool isCatchTestCaseMacro(const QString &macroName)
static bool isCatchMacro(const QString &macroName) static bool isCatchMacro(const QString &macroName)
{ {
QString unprefixed = macroName.startsWith("CATCH_") ? macroName.mid(6) : macroName;
const QStringList validSectionMacros = { const QStringList validSectionMacros = {
QStringLiteral("SECTION"), QStringLiteral("WHEN") QStringLiteral("SECTION"), QStringLiteral("WHEN")
}; };
return isCatchTestCaseMacro(macroName) || validSectionMacros.contains(macroName); return isCatchTestCaseMacro(unprefixed) || validSectionMacros.contains(unprefixed);
} }
static bool includesCatchHeader(const CPlusPlus::Document::Ptr &doc, static bool includesCatchHeader(const CPlusPlus::Document::Ptr &doc,
@@ -123,7 +124,8 @@ bool CatchTestParser::processDocument(QFutureInterface<TestParseResultPtr> &futu
const QByteArray &fileContent = getFileContent(fileName); const QByteArray &fileContent = getFileContent(fileName);
if (!hasCatchNames(doc)) { if (!hasCatchNames(doc)) {
const QRegularExpression regex("\\b(SCENARIO|(TEMPLATE_(PRODUCT_)?)?TEST_CASE(_METHOD)?|" const QRegularExpression regex("\\b(CATCH_)?"
"(SCENARIO|(TEMPLATE_(PRODUCT_)?)?TEST_CASE(_METHOD)?|"
"TEMPLATE_TEST_CASE(_METHOD)?_SIG|" "TEMPLATE_TEST_CASE(_METHOD)?_SIG|"
"TEMPLATE_PRODUCT_TEST_CASE(_METHOD)?_SIG|" "TEMPLATE_PRODUCT_TEST_CASE(_METHOD)?_SIG|"
"TEMPLATE_LIST_TEST_CASE_METHOD|METHOD_AS_TEST_CASE|" "TEMPLATE_LIST_TEST_CASE_METHOD|METHOD_AS_TEST_CASE|"

View File

@@ -37,7 +37,9 @@ namespace Internal {
QString CatchTreeItem::testCasesString() const QString CatchTreeItem::testCasesString() const
{ {
return m_state & CatchTreeItem::Parameterized ? QString(name() + " -*") : name(); QString testcase = m_state & CatchTreeItem::Parameterized ? QString(name() + " -*") : name();
// mask comma if it is part of the test case name
return testcase.replace(',', "\\,");
} }
static QString nonRootDisplayName(const CatchTreeItem *it) static QString nonRootDisplayName(const CatchTreeItem *it)

View File

@@ -36,7 +36,7 @@ CTestConfiguration::CTestConfiguration(ITestBase *testBase)
} }
TestOutputReader *CTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi, TestOutputReader *CTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const Utils::QtcProcess *app) const
{ {
return new CTestOutputReader(fi, app, workingDirectory()); return new CTestOutputReader(fi, app, workingDirectory());
} }

View File

@@ -36,7 +36,7 @@ public:
explicit CTestConfiguration(ITestBase *testBase); explicit CTestConfiguration(ITestBase *testBase);
TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi, TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const final; Utils::QtcProcess *app) const final;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -71,7 +71,7 @@ private:
}; };
CTestOutputReader::CTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface, CTestOutputReader::CTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
QProcess *testApplication, Utils::QtcProcess *testApplication,
const Utils::FilePath &buildDirectory) const Utils::FilePath &buildDirectory)
: TestOutputReader(futureInterface, testApplication, buildDirectory) : TestOutputReader(futureInterface, testApplication, buildDirectory)
{ {

View File

@@ -28,6 +28,8 @@
#include <QCoreApplication> #include <QCoreApplication>
namespace Utils { class QtcProcess; }
namespace Autotest { namespace Autotest {
namespace Internal { namespace Internal {
@@ -36,7 +38,7 @@ class CTestOutputReader final : public Autotest::TestOutputReader
Q_DECLARE_TR_FUNCTIONS(Autotest::Internal::CTestOutputReader) Q_DECLARE_TR_FUNCTIONS(Autotest::Internal::CTestOutputReader)
public: public:
CTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface, CTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
QProcess *testApplication, const Utils::FilePath &buildDirectory); Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory);
protected: protected:
void processOutputLine(const QByteArray &outputLineWithNewLine) final; void processOutputLine(const QByteArray &outputLineWithNewLine) final;

View File

@@ -38,7 +38,7 @@ namespace Autotest {
namespace Internal { namespace Internal {
TestOutputReader *GTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi, TestOutputReader *GTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const Utils::QtcProcess *app) const
{ {
return new GTestOutputReader(fi, app, buildDirectory(), projectFile()); return new GTestOutputReader(fi, app, buildDirectory(), projectFile());
} }

View File

@@ -37,7 +37,7 @@ public:
: DebuggableTestConfiguration(framework) {} : DebuggableTestConfiguration(framework) {}
TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi, TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const override; Utils::QtcProcess *app) const override;
QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override;
Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; Utils::Environment filteredEnvironment(const Utils::Environment &original) const override;
}; };

View File

@@ -28,6 +28,7 @@
#include "../testtreemodel.h" #include "../testtreemodel.h"
#include "../testtreeitem.h" #include "../testtreeitem.h"
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <utils/qtcprocess.h>
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
@@ -37,18 +38,19 @@ namespace Autotest {
namespace Internal { namespace Internal {
GTestOutputReader::GTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface, GTestOutputReader::GTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
QProcess *testApplication, Utils::QtcProcess *testApplication,
const Utils::FilePath &buildDirectory, const Utils::FilePath &buildDirectory,
const Utils::FilePath &projectFile) const Utils::FilePath &projectFile)
: TestOutputReader(futureInterface, testApplication, buildDirectory) : TestOutputReader(futureInterface, testApplication, buildDirectory)
, m_projectFile(projectFile) , m_projectFile(projectFile)
{ {
if (m_testApplication) { if (m_testApplication) {
connect(m_testApplication, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), connect(m_testApplication, &Utils::QtcProcess::finished,
this, [this] (int exitCode, QProcess::ExitStatus /*exitStatus*/) { this, [this]() {
int exitCode = m_testApplication->exitCode();
if (exitCode == 1 && !m_description.isEmpty()) { if (exitCode == 1 && !m_description.isEmpty()) {
createAndReportResult(tr("Running tests failed.\n %1\nExecutable: %2") createAndReportResult(tr("Running tests failed.\n %1\nExecutable: %2")
.arg(m_description).arg(id()), ResultType::MessageFatal); .arg(m_description).arg(id()), ResultType::MessageFatal);
} }
// on Windows abort() will result in normal termination, but exit code will be set to 3 // on Windows abort() will result in normal termination, but exit code will be set to 3
if (Utils::HostOsInfo::isWindowsHost() && exitCode == 3) if (Utils::HostOsInfo::isWindowsHost() && exitCode == 3)

View File

@@ -38,7 +38,7 @@ class GTestOutputReader : public TestOutputReader
public: public:
GTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface, GTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
QProcess *testApplication, const Utils::FilePath &buildDirectory, Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory,
const Utils::FilePath &projectFile); const Utils::FilePath &projectFile);
protected: protected:
void processOutputLine(const QByteArray &outputLine) override; void processOutputLine(const QByteArray &outputLine) override;

View File

@@ -38,7 +38,7 @@ namespace Autotest {
namespace Internal { namespace Internal {
TestOutputReader *QtTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi, TestOutputReader *QtTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const Utils::QtcProcess *app) const
{ {
auto qtSettings = static_cast<QtTestSettings *>(framework()->testSettings()); auto qtSettings = static_cast<QtTestSettings *>(framework()->testSettings());
const QtTestOutputReader::OutputMode mode = qtSettings && qtSettings->useXMLOutput.value() const QtTestOutputReader::OutputMode mode = qtSettings && qtSettings->useXMLOutput.value()

View File

@@ -36,7 +36,7 @@ public:
explicit QtTestConfiguration(ITestFramework *framework) explicit QtTestConfiguration(ITestFramework *framework)
: DebuggableTestConfiguration(framework) {} : DebuggableTestConfiguration(framework) {}
TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi, TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const override; Utils::QtcProcess *app) const override;
QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override;
Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; Utils::Environment filteredEnvironment(const Utils::Environment &original) const override;
}; };

View File

@@ -126,7 +126,7 @@ static QString constructBenchmarkInformation(const QString &metric, double value
} }
QtTestOutputReader::QtTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface, QtTestOutputReader::QtTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
QProcess *testApplication, Utils::QtcProcess *testApplication,
const Utils::FilePath &buildDirectory, const Utils::FilePath &buildDirectory,
const Utils::FilePath &projectFile, const Utils::FilePath &projectFile,
OutputMode mode, TestType type) OutputMode mode, TestType type)

View File

@@ -48,7 +48,7 @@ public:
}; };
QtTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface, QtTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
QProcess *testApplication, const Utils::FilePath &buildDirectory, Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory,
const Utils::FilePath &projectFile, OutputMode mode, TestType type); const Utils::FilePath &projectFile, OutputMode mode, TestType type);
protected: protected:
void processOutputLine(const QByteArray &outputLine) override; void processOutputLine(const QByteArray &outputLine) override;

View File

@@ -52,7 +52,9 @@ const QString QtTestResult::outputString(bool selected) const
case ResultType::UnexpectedPass: case ResultType::UnexpectedPass:
case ResultType::BlacklistedFail: case ResultType::BlacklistedFail:
case ResultType::BlacklistedPass: case ResultType::BlacklistedPass:
output = className + "::" + m_function; output = className;
if (!m_function.isEmpty())
output.append("::" + m_function);
if (!m_dataTag.isEmpty()) if (!m_dataTag.isEmpty())
output.append(QString(" (%1)").arg(m_dataTag)); output.append(QString(" (%1)").arg(m_dataTag));
if (selected && !desc.isEmpty()) { if (selected && !desc.isEmpty()) {
@@ -60,7 +62,9 @@ const QString QtTestResult::outputString(bool selected) const
} }
break; break;
case ResultType::Benchmark: case ResultType::Benchmark:
output = className + "::" + m_function; output = className;
if (!m_function.isEmpty())
output.append("::" + m_function);
if (!m_dataTag.isEmpty()) if (!m_dataTag.isEmpty())
output.append(QString(" (%1)").arg(m_dataTag)); output.append(QString(" (%1)").arg(m_dataTag));
if (!desc.isEmpty()) { if (!desc.isEmpty()) {

View File

@@ -44,7 +44,7 @@ QuickTestConfiguration::QuickTestConfiguration(ITestFramework *framework)
} }
TestOutputReader *QuickTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi, TestOutputReader *QuickTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const Utils::QtcProcess *app) const
{ {
auto qtSettings = static_cast<QtTestSettings *>(framework()->testSettings()); auto qtSettings = static_cast<QtTestSettings *>(framework()->testSettings());
const QtTestOutputReader::OutputMode mode = qtSettings && qtSettings->useXMLOutput.value() const QtTestOutputReader::OutputMode mode = qtSettings && qtSettings->useXMLOutput.value()

View File

@@ -35,7 +35,7 @@ class QuickTestConfiguration : public DebuggableTestConfiguration
public: public:
explicit QuickTestConfiguration(ITestFramework *framework); explicit QuickTestConfiguration(ITestFramework *framework);
TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi, TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const override; Utils::QtcProcess *app) const override;
QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override;
Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; Utils::Environment filteredEnvironment(const Utils::Environment &original) const override;
}; };

View File

@@ -35,9 +35,7 @@
#include <QPointer> #include <QPointer>
#include <QStringList> #include <QStringList>
QT_BEGIN_NAMESPACE namespace Utils { class QtcProcess; }
class QProcess;
QT_END_NAMESPACE
namespace Autotest { namespace Autotest {
namespace Internal { namespace Internal {
@@ -66,7 +64,7 @@ public:
Utils::FilePath executableFilePath() const; Utils::FilePath executableFilePath() const;
virtual TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi, virtual TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const = 0; Utils::QtcProcess *app) const = 0;
virtual Utils::Environment filteredEnvironment(const Utils::Environment &original) const; virtual Utils::Environment filteredEnvironment(const Utils::Environment &original) const;
ITestBase *testBase() const { return m_testBase; } ITestBase *testBase() const { return m_testBase; }

View File

@@ -30,6 +30,7 @@
#include "testtreeitem.h" #include "testtreeitem.h"
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <QDebug> #include <QDebug>
#include <QDir> #include <QDir>
@@ -46,11 +47,12 @@ Utils::FilePath TestOutputReader::constructSourceFilePath(const Utils::FilePath
} }
TestOutputReader::TestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface, TestOutputReader::TestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
QProcess *testApplication, const Utils::FilePath &buildDirectory) Utils::QtcProcess *testApplication,
const Utils::FilePath &buildDirectory)
: m_futureInterface(futureInterface) : m_futureInterface(futureInterface)
, m_testApplication(testApplication) , m_testApplication(testApplication)
, m_buildDir(buildDirectory) , m_buildDir(buildDirectory)
, m_id(testApplication ? testApplication->program() : QString()) , m_id(testApplication ? testApplication->commandLine().executable().toUserOutput() : QString())
{ {
auto chopLineBreak = [](QByteArray line) { auto chopLineBreak = [](QByteArray line) {
if (line.endsWith('\n')) if (line.endsWith('\n'))
@@ -61,17 +63,11 @@ TestOutputReader::TestOutputReader(const QFutureInterface<TestResultPtr> &future
}; };
if (m_testApplication) { if (m_testApplication) {
connect(m_testApplication, &QProcess::readyReadStandardOutput, m_testApplication->setStdOutLineCallback([this, &chopLineBreak](const QString &line) {
this, [chopLineBreak, this] () { processStdOutput(chopLineBreak(line.toUtf8()));
m_testApplication->setReadChannel(QProcess::StandardOutput);
while (m_testApplication->canReadLine())
processStdOutput(chopLineBreak(m_testApplication->readLine()));
}); });
connect(m_testApplication, &QProcess::readyReadStandardError, m_testApplication->setStdErrLineCallback([this, &chopLineBreak](const QString &line) {
this, [chopLineBreak, this] () { processStdError(chopLineBreak(line.toUtf8()));
m_testApplication->setReadChannel(QProcess::StandardError);
while (m_testApplication->canReadLine())
processStdError(chopLineBreak(m_testApplication->readLine()));
}); });
} }
} }

View File

@@ -29,9 +29,10 @@
#include <QFutureInterface> #include <QFutureInterface>
#include <QObject> #include <QObject>
#include <QProcess>
#include <QString> #include <QString>
namespace Utils { class QtcProcess; }
namespace Autotest { namespace Autotest {
class TestOutputReader : public QObject class TestOutputReader : public QObject
@@ -39,7 +40,7 @@ class TestOutputReader : public QObject
Q_OBJECT Q_OBJECT
public: public:
TestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface, TestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
QProcess *testApplication, const Utils::FilePath &buildDirectory); Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory);
virtual ~TestOutputReader(); virtual ~TestOutputReader();
void processStdOutput(const QByteArray &outputLine); void processStdOutput(const QByteArray &outputLine);
virtual void processStdError(const QByteArray &outputLine); virtual void processStdError(const QByteArray &outputLine);
@@ -67,7 +68,7 @@ protected:
void reportResult(const TestResultPtr &result); void reportResult(const TestResultPtr &result);
QFutureInterface<TestResultPtr> m_futureInterface; QFutureInterface<TestResultPtr> m_futureInterface;
QProcess *m_testApplication; // not owned Utils::QtcProcess *m_testApplication; // not owned
Utils::FilePath m_buildDir; Utils::FilePath m_buildDir;
QString m_id; QString m_id;
QHash<ResultType, int> m_summary; QHash<ResultType, int> m_summary;

View File

@@ -66,7 +66,7 @@ public:
ProjectExplorer::Runnable r; ProjectExplorer::Runnable r;
QTC_ASSERT(m_testConfig, return r); QTC_ASSERT(m_testConfig, return r);
r.command.setExecutable(m_testConfig->executableFilePath()); r.command.setExecutable(m_testConfig->executableFilePath());
r.command.setArguments(m_testConfig->argumentsForTestRunner().join(' ')); r.command.addArgs(m_testConfig->argumentsForTestRunner().join(' '), Utils::CommandLine::Raw);
r.workingDirectory = m_testConfig->workingDirectory(); r.workingDirectory = m_testConfig->workingDirectory();
r.environment = m_testConfig->environment(); r.environment = m_testConfig->environment();
return r; return r;

View File

@@ -90,6 +90,8 @@ TestRunner::TestRunner()
{ {
s_instance = this; s_instance = this;
m_cancelTimer.setSingleShot(true);
connect(&m_cancelTimer, &QTimer::timeout, this, [this]() { cancelCurrent(Timeout); });
connect(&m_futureWatcher, &QFutureWatcher<TestResultPtr>::resultReadyAt, connect(&m_futureWatcher, &QFutureWatcher<TestResultPtr>::resultReadyAt,
this, [this](int index) { emit testResultReady(m_futureWatcher.resultAt(index)); }); this, [this](int index) { emit testResultReady(m_futureWatcher.resultAt(index)); });
connect(&m_futureWatcher, &QFutureWatcher<TestResultPtr>::finished, connect(&m_futureWatcher, &QFutureWatcher<TestResultPtr>::finished,
@@ -131,16 +133,17 @@ void TestRunner::runTest(TestRunMode mode, const ITestTreeItem *item)
} }
} }
static QString processInformation(const QProcess *proc) static QString processInformation(const QtcProcess *proc)
{ {
QTC_ASSERT(proc, return QString()); QTC_ASSERT(proc, return QString());
QString information("\nCommand line: " + proc->program() + ' ' + proc->arguments().join(' ')); const Utils::CommandLine command = proc->commandLine();
QString information("\nCommand line: " + command.executable().toUserOutput() + ' ' + command.arguments());
QStringList important = { "PATH" }; QStringList important = { "PATH" };
if (Utils::HostOsInfo::isLinuxHost()) if (Utils::HostOsInfo::isLinuxHost())
important.append("LD_LIBRARY_PATH"); important.append("LD_LIBRARY_PATH");
else if (Utils::HostOsInfo::isMacHost()) else if (Utils::HostOsInfo::isMacHost())
important.append({ "DYLD_LIBRARY_PATH", "DYLD_FRAMEWORK_PATH" }); important.append({ "DYLD_LIBRARY_PATH", "DYLD_FRAMEWORK_PATH" });
const QProcessEnvironment &environment = proc->processEnvironment(); const Utils::Environment &environment = proc->environment();
for (const QString &var : important) for (const QString &var : important)
information.append('\n' + var + ": " + environment.value(var)); information.append('\n' + var + ": " + environment.value(var));
return information; return information;
@@ -204,34 +207,35 @@ bool TestRunner::currentConfigValid()
void TestRunner::setUpProcess() void TestRunner::setUpProcess()
{ {
QTC_ASSERT(m_currentConfig, return); QTC_ASSERT(m_currentConfig, return);
m_currentProcess = new QProcess; m_currentProcess = new QtcProcess;
m_currentProcess->setReadChannel(QProcess::StandardOutput);
if (m_currentConfig->testBase()->type() == ITestBase::Framework) { if (m_currentConfig->testBase()->type() == ITestBase::Framework) {
TestConfiguration *current = static_cast<TestConfiguration *>(m_currentConfig); TestConfiguration *current = static_cast<TestConfiguration *>(m_currentConfig);
m_currentProcess->setProgram(current->executableFilePath().toString()); m_currentProcess->setCommand({current->executableFilePath(), {}});
} else { } else {
TestToolConfiguration *current = static_cast<TestToolConfiguration *>(m_currentConfig); TestToolConfiguration *current = static_cast<TestToolConfiguration *>(m_currentConfig);
m_currentProcess->setProgram(current->commandLine().executable().toString()); m_currentProcess->setCommand({current->commandLine().executable(), {}});
} }
} }
void TestRunner::setUpProcessEnv() void TestRunner::setUpProcessEnv()
{ {
Utils::CommandLine command = m_currentProcess->commandLine();
if (m_currentConfig->testBase()->type() == ITestBase::Framework) { if (m_currentConfig->testBase()->type() == ITestBase::Framework) {
TestConfiguration *current = static_cast<TestConfiguration *>(m_currentConfig); TestConfiguration *current = static_cast<TestConfiguration *>(m_currentConfig);
QStringList omitted; QStringList omitted;
m_currentProcess->setArguments(current->argumentsForTestRunner(&omitted)); command.addArgs(current->argumentsForTestRunner(&omitted).join(' '), Utils::CommandLine::Raw);
if (!omitted.isEmpty()) { if (!omitted.isEmpty()) {
const QString &details = constructOmittedDetailsString(omitted); const QString &details = constructOmittedDetailsString(omitted);
reportResult(ResultType::MessageWarn, details.arg(current->displayName())); reportResult(ResultType::MessageWarn, details.arg(current->displayName()));
} }
} else { } else {
TestToolConfiguration *current = static_cast<TestToolConfiguration *>(m_currentConfig); TestToolConfiguration *current = static_cast<TestToolConfiguration *>(m_currentConfig);
m_currentProcess->setArguments(current->commandLine().splitArguments()); command.setArguments(current->commandLine().arguments());
} }
m_currentProcess->setCommand(command);
m_currentProcess->setWorkingDirectory(m_currentConfig->workingDirectory().toString()); m_currentProcess->setWorkingDirectory(m_currentConfig->workingDirectory());
const Utils::Environment &original = m_currentConfig->environment(); const Utils::Environment &original = m_currentConfig->environment();
Utils::Environment environment = m_currentConfig->filteredEnvironment(original); Utils::Environment environment = m_currentConfig->filteredEnvironment(original);
const Utils::EnvironmentItems removedVariables = Utils::filtered( const Utils::EnvironmentItems removedVariables = Utils::filtered(
@@ -243,7 +247,7 @@ void TestRunner::setUpProcessEnv()
.arg(m_currentConfig->displayName()); .arg(m_currentConfig->displayName());
reportResult(ResultType::MessageWarn, details); reportResult(ResultType::MessageWarn, details);
} }
m_currentProcess->setProcessEnvironment(environment.toProcessEnvironment()); m_currentProcess->setEnvironment(environment);
} }
void TestRunner::scheduleNext() void TestRunner::scheduleNext()
@@ -272,15 +276,16 @@ void TestRunner::scheduleNext()
setUpProcessEnv(); setUpProcessEnv();
connect(m_currentProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), connect(m_currentProcess, &Utils::QtcProcess::finished,
this, &TestRunner::onProcessFinished); this, &TestRunner::onProcessFinished);
const int timeout = AutotestPlugin::settings()->timeout; const int timeout = AutotestPlugin::settings()->timeout;
QTimer::singleShot(timeout, m_currentProcess, [this]() { cancelCurrent(Timeout); }); m_cancelTimer.setInterval(timeout);
m_cancelTimer.start();
qCInfo(runnerLog) << "Command:" << m_currentProcess->program(); qCInfo(runnerLog) << "Command:" << m_currentProcess->commandLine().executable();
qCInfo(runnerLog) << "Arguments:" << m_currentProcess->arguments(); qCInfo(runnerLog) << "Arguments:" << m_currentProcess->commandLine().arguments();
qCInfo(runnerLog) << "Working directory:" << m_currentProcess->workingDirectory(); qCInfo(runnerLog) << "Working directory:" << m_currentProcess->workingDirectory();
qCDebug(runnerLog) << "Environment:" << m_currentProcess->environment(); qCDebug(runnerLog) << "Environment:" << m_currentProcess->environment().toStringList();
m_currentProcess->start(); m_currentProcess->start();
if (!m_currentProcess->waitForStarted()) { if (!m_currentProcess->waitForStarted()) {
@@ -355,7 +360,8 @@ void TestRunner::onProcessFinished()
void TestRunner::resetInternalPointers() void TestRunner::resetInternalPointers()
{ {
delete m_currentOutputReader; delete m_currentOutputReader;
delete m_currentProcess; if (m_currentProcess)
m_currentProcess->deleteLater();
delete m_currentConfig; delete m_currentConfig;
m_currentOutputReader = nullptr; m_currentOutputReader = nullptr;
m_currentProcess = nullptr; m_currentProcess = nullptr;
@@ -812,6 +818,7 @@ void TestRunner::onBuildQueueFinished(bool success)
void TestRunner::onFinished() void TestRunner::onFinished()
{ {
m_cancelTimer.stop();
// if we've been canceled and we still have test configurations queued just throw them away // if we've been canceled and we still have test configurations queued just throw them away
qDeleteAll(m_selectedTests); qDeleteAll(m_selectedTests);
m_selectedTests.clear(); m_selectedTests.clear();

View File

@@ -32,16 +32,17 @@
#include <QFutureWatcher> #include <QFutureWatcher>
#include <QObject> #include <QObject>
#include <QQueue> #include <QQueue>
#include <QTimer>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QCheckBox; class QCheckBox;
class QComboBox; class QComboBox;
class QDialogButtonBox; class QDialogButtonBox;
class QLabel; class QLabel;
class QProcess;
QT_END_NAMESPACE QT_END_NAMESPACE
namespace ProjectExplorer { class Project; } namespace ProjectExplorer { class Project; }
namespace Utils { class QtcProcess; }
namespace Autotest { namespace Autotest {
@@ -105,7 +106,7 @@ private:
bool m_executingTests = false; bool m_executingTests = false;
bool m_canceled = false; bool m_canceled = false;
ITestConfiguration *m_currentConfig = nullptr; ITestConfiguration *m_currentConfig = nullptr;
QProcess *m_currentProcess = nullptr; Utils::QtcProcess *m_currentProcess = nullptr;
TestOutputReader *m_currentOutputReader = nullptr; TestOutputReader *m_currentOutputReader = nullptr;
TestRunMode m_runMode = TestRunMode::None; TestRunMode m_runMode = TestRunMode::None;
@@ -116,6 +117,7 @@ private:
QMetaObject::Connection m_finishDebugConnect; QMetaObject::Connection m_finishDebugConnect;
// temporarily used for handling of switching the current target // temporarily used for handling of switching the current target
QMetaObject::Connection m_targetConnect; QMetaObject::Connection m_targetConnect;
QTimer m_cancelTimer;
bool m_skipTargetsCheck = false; bool m_skipTargetsCheck = false;
}; };

View File

@@ -52,7 +52,6 @@ QdbDeployConfigurationFactory::QdbDeployConfigurationFactory()
return prj->deploymentKnowledge() == DeploymentKnowledge::Bad return prj->deploymentKnowledge() == DeploymentKnowledge::Bad
&& prj->hasMakeInstallEquivalent(); && prj->hasMakeInstallEquivalent();
}); });
addInitialStep(RemoteLinux::Constants::CheckForFreeDiskSpaceId);
addInitialStep(Qdb::Constants::QdbStopApplicationStepId); addInitialStep(Qdb::Constants::QdbStopApplicationStepId);
addInitialStep(RemoteLinux::Constants::DirectUploadStepId); addInitialStep(RemoteLinux::Constants::DirectUploadStepId);
} }

View File

@@ -45,7 +45,6 @@
#include <qtsupport/qtversionfactory.h> #include <qtsupport/qtversionfactory.h>
#include <remotelinux/checkforfreediskspacestep.h>
#include <remotelinux/genericdirectuploadstep.h> #include <remotelinux/genericdirectuploadstep.h>
#include <remotelinux/makeinstallstep.h> #include <remotelinux/makeinstallstep.h>
#include <remotelinux/remotelinux_constants.h> #include <remotelinux/remotelinux_constants.h>
@@ -177,8 +176,6 @@ public:
QdbStopApplicationStepFactory m_stopApplicationStepFactory; QdbStopApplicationStepFactory m_stopApplicationStepFactory;
QdbMakeDefaultAppStepFactory m_makeDefaultAppStepFactory; QdbMakeDefaultAppStepFactory m_makeDefaultAppStepFactory;
QdbDeployStepFactory<RemoteLinux::CheckForFreeDiskSpaceStep>
m_checkForFreeDiskSpaceStepFactory{RemoteLinux::Constants::CheckForFreeDiskSpaceId};
QdbDeployStepFactory<RemoteLinux::GenericDirectUploadStep> QdbDeployStepFactory<RemoteLinux::GenericDirectUploadStep>
m_directUploadStepFactory{RemoteLinux::Constants::DirectUploadStepId}; m_directUploadStepFactory{RemoteLinux::Constants::DirectUploadStepId};
QdbDeployStepFactory<RemoteLinux::MakeInstallStep> QdbDeployStepFactory<RemoteLinux::MakeInstallStep>

View File

@@ -34,8 +34,6 @@
# include "test/clangfixittest.h" # include "test/clangfixittest.h"
#endif #endif
#include <utils/runextensions.h>
#include <coreplugin/actionmanager/actioncontainer.h> #include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h> #include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/messagemanager.h> #include <coreplugin/messagemanager.h>
@@ -45,6 +43,7 @@
#include <cppeditor/cppmodelmanager.h> #include <cppeditor/cppmodelmanager.h>
#include <projectexplorer/buildconfiguration.h> #include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectpanelfactory.h> #include <projectexplorer/projectpanelfactory.h>
#include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorer.h>
#include <projectexplorer/session.h> #include <projectexplorer/session.h>
@@ -53,6 +52,9 @@
#include <texteditor/textmark.h> #include <texteditor/textmark.h>
#include <utils/temporarydirectory.h>
#include <utils/runextensions.h>
using namespace Utils; using namespace Utils;
namespace ClangCodeModel { namespace ClangCodeModel {
@@ -69,10 +71,13 @@ void ClangCodeModelPlugin::generateCompilationDB()
const auto projectInfo = CppModelManager::instance()->projectInfo(target->project()); const auto projectInfo = CppModelManager::instance()->projectInfo(target->project());
if (!projectInfo) if (!projectInfo)
return; return;
FilePath baseDir = projectInfo->buildRoot();
if (baseDir == target->project()->projectDirectory())
baseDir = TemporaryDirectory::masterDirectoryFilePath();
QFuture<GenerateCompilationDbResult> task QFuture<GenerateCompilationDbResult> task
= Utils::runAsync(&Internal::generateCompilationDB, projectInfo, = Utils::runAsync(&Internal::generateCompilationDB, projectInfo,
projectInfo->buildRoot(), CompilationDbPurpose::Project, baseDir, CompilationDbPurpose::Project,
warningsConfigForProject(target->project()), warningsConfigForProject(target->project()),
globalClangOptions(), globalClangOptions(),
FilePath()); FilePath());

View File

@@ -185,11 +185,6 @@ CppEditor::CppCompletionAssistProvider *ClangModelManagerSupport::completionAssi
return nullptr; return nullptr;
} }
CppEditor::CppCompletionAssistProvider *ClangModelManagerSupport::functionHintAssistProvider()
{
return nullptr;
}
void ClangModelManagerSupport::followSymbol(const CppEditor::CursorInEditor &data, void ClangModelManagerSupport::followSymbol(const CppEditor::CursorInEditor &data,
const Utils::LinkHandler &processLinkCallback, bool resolveTarget, const Utils::LinkHandler &processLinkCallback, bool resolveTarget,
bool inNextSplit) bool inNextSplit)

View File

@@ -63,7 +63,6 @@ public:
~ClangModelManagerSupport() override; ~ClangModelManagerSupport() override;
CppEditor::CppCompletionAssistProvider *completionAssistProvider() override; CppEditor::CppCompletionAssistProvider *completionAssistProvider() override;
CppEditor::CppCompletionAssistProvider *functionHintAssistProvider() override;
TextEditor::BaseHoverHandler *createHoverHandler() override { return nullptr; } TextEditor::BaseHoverHandler *createHoverHandler() override { return nullptr; }
CppEditor::BaseEditorDocumentProcessor *createEditorDocumentProcessor( CppEditor::BaseEditorDocumentProcessor *createEditorDocumentProcessor(
TextEditor::TextDocument *baseTextDocument) override; TextEditor::TextDocument *baseTextDocument) override;

View File

@@ -25,8 +25,6 @@
#include "clangtoolrunner.h" #include "clangtoolrunner.h"
#include "clangtoolsconstants.h"
#include <utils/environment.h> #include <utils/environment.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/qtcprocess.h> #include <utils/qtcprocess.h>
@@ -60,32 +58,17 @@ static QString finishedWithBadExitCode(const QString &name, int exitCode)
} }
ClangToolRunner::ClangToolRunner(QObject *parent) ClangToolRunner::ClangToolRunner(QObject *parent)
: QObject(parent), m_process(new QtcProcess) : QObject(parent)
{} {}
ClangToolRunner::~ClangToolRunner()
{
if (m_process->state() != QProcess::NotRunning) {
// asking politly to terminate costs ~300 ms on windows so skip the courtasy and direct kill the process
if (HostOsInfo::isWindowsHost()) {
m_process->kill();
m_process->waitForFinished(100);
} else {
m_process->stopProcess();
}
}
m_process->deleteLater();
}
void ClangToolRunner::init(const FilePath &outputDirPath, const Environment &environment) void ClangToolRunner::init(const FilePath &outputDirPath, const Environment &environment)
{ {
m_outputDirPath = outputDirPath; m_outputDirPath = outputDirPath;
QTC_CHECK(!m_outputDirPath.isEmpty()); QTC_CHECK(!m_outputDirPath.isEmpty());
m_process->setEnvironment(environment); m_process.setEnvironment(environment);
m_process->setWorkingDirectory(m_outputDirPath); // Current clang-cl puts log file into working dir. m_process.setWorkingDirectory(m_outputDirPath); // Current clang-cl puts log file into working dir.
connect(m_process, &QtcProcess::done, this, &ClangToolRunner::onProcessDone); connect(&m_process, &QtcProcess::done, this, &ClangToolRunner::onProcessDone);
} }
QStringList ClangToolRunner::mainToolArguments() const QStringList ClangToolRunner::mainToolArguments() const
@@ -139,20 +122,20 @@ bool ClangToolRunner::run(const QString &fileToAnalyze, const QStringList &compi
m_commandLine = {m_executable, m_argsCreator(compilerOptions)}; m_commandLine = {m_executable, m_argsCreator(compilerOptions)};
qCDebug(LOG).noquote() << "Starting" << m_commandLine.toUserOutput(); qCDebug(LOG).noquote() << "Starting" << m_commandLine.toUserOutput();
m_process->setCommand(m_commandLine); m_process.setCommand(m_commandLine);
m_process->start(); m_process.start();
return true; return true;
} }
void ClangToolRunner::onProcessDone() void ClangToolRunner::onProcessDone()
{ {
if (m_process->result() == ProcessResult::StartFailed) { if (m_process.result() == ProcessResult::StartFailed) {
emit finishedWithFailure(generalProcessError(m_name), commandlineAndOutput()); emit finishedWithFailure(generalProcessError(m_name), commandlineAndOutput());
} else if (m_process->result() == ProcessResult::FinishedWithSuccess) { } else if (m_process.result() == ProcessResult::FinishedWithSuccess) {
qCDebug(LOG).noquote() << "Output:\n" << m_process->stdOut(); qCDebug(LOG).noquote() << "Output:\n" << m_process.stdOut();
emit finishedWithSuccess(m_fileToAnalyze); emit finishedWithSuccess(m_fileToAnalyze);
} else if (m_process->result() == ProcessResult::FinishedWithError) { } else if (m_process.result() == ProcessResult::FinishedWithError) {
emit finishedWithFailure(finishedWithBadExitCode(m_name, m_process->exitCode()), emit finishedWithFailure(finishedWithBadExitCode(m_name, m_process.exitCode()),
commandlineAndOutput()); commandlineAndOutput());
} else { // == QProcess::CrashExit } else { // == QProcess::CrashExit
emit finishedWithFailure(finishedDueToCrash(m_name), commandlineAndOutput()); emit finishedWithFailure(finishedDueToCrash(m_name), commandlineAndOutput());
@@ -165,8 +148,8 @@ QString ClangToolRunner::commandlineAndOutput() const
"Process Error: %2\n" "Process Error: %2\n"
"Output:\n%3") "Output:\n%3")
.arg(m_commandLine.toUserOutput()) .arg(m_commandLine.toUserOutput())
.arg(m_process->error()) .arg(m_process.error())
.arg(m_process->stdOut()); .arg(m_process.stdOut());
} }
} // namespace Internal } // namespace Internal

View File

@@ -28,13 +28,10 @@
#include "clangtoolslogfilereader.h" #include "clangtoolslogfilereader.h"
#include <utils/commandline.h> #include <utils/commandline.h>
#include <utils/qtcprocess.h>
#include <QProcess>
#include <memory> #include <memory>
namespace Utils { class QtcProcess; }
namespace ClangTools { namespace ClangTools {
namespace Internal { namespace Internal {
@@ -46,7 +43,6 @@ class ClangToolRunner : public QObject
public: public:
ClangToolRunner(QObject *parent = nullptr); ClangToolRunner(QObject *parent = nullptr);
~ClangToolRunner() override;
void init(const Utils::FilePath &outputDirPath, const Utils::Environment &environment); void init(const Utils::FilePath &outputDirPath, const Utils::Environment &environment);
void setName(const QString &name) { m_name = name; } void setName(const QString &name) { m_name = name; }
@@ -83,7 +79,7 @@ private:
private: private:
Utils::FilePath m_outputDirPath; Utils::FilePath m_outputDirPath;
Utils::QtcProcess *m_process = nullptr; Utils::QtcProcess m_process;
QString m_name; QString m_name;
Utils::FilePath m_executable; Utils::FilePath m_executable;

View File

@@ -28,7 +28,6 @@
#include "cmakebuildconfiguration.h" #include "cmakebuildconfiguration.h"
#include "cmakebuildsystem.h" #include "cmakebuildsystem.h"
#include "cmakekitinformation.h" #include "cmakekitinformation.h"
#include "cmakeprojectconstants.h"
#include "cmakeprojectplugin.h" #include "cmakeprojectplugin.h"
#include "cmakespecificsettings.h" #include "cmakespecificsettings.h"
#include "cmaketoolmanager.h" #include "cmaketoolmanager.h"
@@ -90,12 +89,6 @@ BuildDirParameters::BuildDirParameters(CMakeBuildSystem *buildSystem)
if (Utils::HostOsInfo::isAnyUnixHost()) if (Utils::HostOsInfo::isAnyUnixHost())
environment.set("ICECC", "no"); environment.set("ICECC", "no");
CMakeSpecificSettings *settings = CMakeProjectPlugin::projectTypeSpecificSettings();
if (!settings->ninjaPath.filePath().isEmpty()) {
const Utils::FilePath ninja = settings->ninjaPath.filePath();
environment.appendOrSetPath(ninja.isFile() ? ninja.parentDir() : ninja);
}
cmakeToolId = CMakeKitAspect::cmakeToolId(k); cmakeToolId = CMakeKitAspect::cmakeToolId(k);
} }
@@ -109,8 +102,5 @@ CMakeTool *BuildDirParameters::cmakeTool() const
return CMakeToolManager::findById(cmakeToolId); return CMakeToolManager::findById(cmakeToolId);
} }
BuildDirParameters::BuildDirParameters(const BuildDirParameters &) = default;
BuildDirParameters &BuildDirParameters::operator=(const BuildDirParameters &) = default;
} // namespace Internal } // namespace Internal
} // namespace CMakeProjectManager } // namespace CMakeProjectManager

View File

@@ -25,14 +25,10 @@
#pragma once #pragma once
#include "cmakeconfigitem.h"
#include "cmaketool.h" #include "cmaketool.h"
#include <utils/environment.h> #include <utils/environment.h>
#include <utils/fileutils.h> #include <utils/filepath.h>
#include <utils/macroexpander.h>
#include <QString>
namespace CMakeProjectManager { namespace CMakeProjectManager {
namespace Internal { namespace Internal {
@@ -44,8 +40,6 @@ class BuildDirParameters
public: public:
BuildDirParameters(); BuildDirParameters();
explicit BuildDirParameters(CMakeBuildSystem *buildSystem); explicit BuildDirParameters(CMakeBuildSystem *buildSystem);
BuildDirParameters(const BuildDirParameters &other);
BuildDirParameters &operator=(const BuildDirParameters &other);
bool isValid() const; bool isValid() const;
CMakeTool *cmakeTool() const; CMakeTool *cmakeTool() const;

View File

@@ -379,7 +379,16 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildSystem *bs) :
} }
connect(m_buildSystem, &BuildSystem::parsingFinished, this, [this] { connect(m_buildSystem, &BuildSystem::parsingFinished, this, [this] {
m_configModel->setConfiguration(m_buildSystem->configurationFromCMake()); const CMakeConfig config = m_buildSystem->configurationFromCMake();
auto qmlDebugAspect = m_buildSystem->buildConfiguration()
->aspect<QtSupport::QmlDebuggingAspect>();
const TriState qmlDebugSetting = qmlDebugAspect->value();
bool qmlDebugConfig = CMakeBuildConfiguration::hasQmlDebugging(config);
if ((qmlDebugSetting == TriState::Enabled && !qmlDebugConfig)
|| (qmlDebugSetting == TriState::Disabled && qmlDebugConfig)) {
qmlDebugAspect->setValue(TriState::Default);
}
m_configModel->setConfiguration(config);
m_configModel->setInitialParametersConfiguration( m_configModel->setInitialParametersConfiguration(
m_buildSystem->initialCMakeConfiguration()); m_buildSystem->initialCMakeConfiguration());
m_buildSystem->filterConfigArgumentsFromAdditionalCMakeArguments(); m_buildSystem->filterConfigArgumentsFromAdditionalCMakeArguments();
@@ -738,7 +747,8 @@ void CMakeBuildSettingsWidget::updateButtonState()
} else { } else {
m_reconfigureButton->setText(tr("Run CMake")); m_reconfigureButton->setText(tr("Run CMake"));
} }
reconfigureButtonFont.setBold(m_configModel->hasChanges(isInitial)); reconfigureButtonFont.setBold(isInitial ? m_configModel->hasChanges(isInitial)
: !configChanges.isEmpty());
} }
m_reconfigureButton->setFont(reconfigureButtonFont); m_reconfigureButton->setFont(reconfigureButtonFont);
@@ -1388,6 +1398,16 @@ bool CMakeBuildConfiguration::isIos(const Kit *k)
|| deviceType == Ios::Constants::IOS_SIMULATOR_TYPE; || deviceType == Ios::Constants::IOS_SIMULATOR_TYPE;
} }
bool CMakeBuildConfiguration::hasQmlDebugging(const CMakeConfig &config)
{
// Determine QML debugging flags. This must match what we do in
// CMakeBuildSettingsWidget::getQmlDebugCxxFlags()
// such that in doubt we leave the QML Debugging setting at "Leave at default"
const QString cxxFlagsInit = config.stringValueOf("CMAKE_CXX_FLAGS_INIT");
const QString cxxFlags = config.stringValueOf("CMAKE_CXX_FLAGS");
return cxxFlagsInit.contains("-DQT_QML_DEBUG") && cxxFlags.contains("-DQT_QML_DEBUG");
}
void CMakeBuildConfiguration::buildTarget(const QString &buildTarget) void CMakeBuildConfiguration::buildTarget(const QString &buildTarget)
{ {
auto cmBs = qobject_cast<CMakeBuildStep *>(findOrDefault( auto cmBs = qobject_cast<CMakeBuildStep *>(findOrDefault(
@@ -1694,6 +1714,15 @@ FilePath CMakeBuildConfiguration::sourceDirectory() const
return aspect<SourceDirectoryAspect>()->filePath(); return aspect<SourceDirectoryAspect>()->filePath();
} }
void CMakeBuildConfiguration::addToEnvironment(Utils::Environment &env) const
{
CMakeSpecificSettings *settings = CMakeProjectPlugin::projectTypeSpecificSettings();
if (!settings->ninjaPath.filePath().isEmpty()) {
const Utils::FilePath ninja = settings->ninjaPath.filePath();
env.appendOrSetPath(ninja.isFile() ? ninja.parentDir() : ninja);
}
}
QString CMakeBuildSystem::cmakeBuildType() const QString CMakeBuildSystem::cmakeBuildType() const
{ {
auto setBuildTypeFromConfig = [this](const CMakeConfig &config) { auto setBuildTypeFromConfig = [this](const CMakeConfig &config) {

View File

@@ -55,6 +55,7 @@ public:
shadowBuildDirectory(const Utils::FilePath &projectFilePath, const ProjectExplorer::Kit *k, shadowBuildDirectory(const Utils::FilePath &projectFilePath, const ProjectExplorer::Kit *k,
const QString &bcName, BuildConfiguration::BuildType buildType); const QString &bcName, BuildConfiguration::BuildType buildType);
static bool isIos(const ProjectExplorer::Kit *k); static bool isIos(const ProjectExplorer::Kit *k);
static bool hasQmlDebugging(const CMakeConfig &config);
// Context menu action: // Context menu action:
void buildTarget(const QString &buildTarget); void buildTarget(const QString &buildTarget);
@@ -63,6 +64,8 @@ public:
void setSourceDirectory(const Utils::FilePath& path); void setSourceDirectory(const Utils::FilePath& path);
Utils::FilePath sourceDirectory() const; Utils::FilePath sourceDirectory() const;
void addToEnvironment(Utils::Environment &env) const override;
signals: signals:
void signingFlagsChanged(); void signingFlagsChanged();

View File

@@ -36,26 +36,31 @@
#include "cmakeprojectplugin.h" #include "cmakeprojectplugin.h"
#include "cmakespecificsettings.h" #include "cmakespecificsettings.h"
#include "projecttreehelper.h" #include "projecttreehelper.h"
#include "utils/algorithm.h"
#include <android/androidconstants.h> #include <android/androidconstants.h>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h> #include <coreplugin/progressmanager/progressmanager.h>
#include <cppeditor/cppeditorconstants.h> #include <cppeditor/cppeditorconstants.h>
#include <cppeditor/cppprojectupdater.h> #include <cppeditor/cppprojectupdater.h>
#include <cppeditor/generatedcodemodelsupport.h> #include <cppeditor/generatedcodemodelsupport.h>
#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/kitinformation.h> #include <projectexplorer/kitinformation.h>
#include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/session.h> #include <projectexplorer/session.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
#include <projectexplorer/taskhub.h> #include <projectexplorer/taskhub.h>
#include <qmljs/qmljsmodelmanagerinterface.h> #include <qmljs/qmljsmodelmanagerinterface.h>
#include <qtsupport/qtcppkitinfo.h> #include <qtsupport/qtcppkitinfo.h>
#include <qtsupport/qtkitinformation.h> #include <qtsupport/qtkitinformation.h>
#include <app/app_version.h> #include <app/app_version.h>
#include <utils/algorithm.h>
#include <utils/checkablemessagebox.h> #include <utils/checkablemessagebox.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/macroexpander.h> #include <utils/macroexpander.h>
@@ -1314,5 +1319,31 @@ void CMakeBuildSystem::updateInitialCMakeExpandableVars()
emit configurationChanged(config); emit configurationChanged(config);
} }
MakeInstallCommand CMakeBuildSystem::makeInstallCommand(const FilePath &installRoot) const
{
MakeInstallCommand cmd;
if (CMakeTool *tool = CMakeKitAspect::cmakeTool(target()->kit()))
cmd.command.setExecutable(tool->cmakeExecutable());
QString installTarget = "install";
if (usesAllCapsTargets())
installTarget = "INSTALL";
FilePath buildDirectory = ".";
if (auto bc = buildConfiguration())
buildDirectory = bc->buildDirectory();
cmd.command.addArg("--build");
cmd.command.addArg(buildDirectory.onDevice(cmd.command.executable()).path());
cmd.command.addArg("--target");
cmd.command.addArg(installTarget);
if (isMultiConfigReader())
cmd.command.addArgs({"--config", cmakeBuildType()});
cmd.environment.set("DESTDIR", installRoot.nativePath());
return cmd;
}
} // namespace Internal } // namespace Internal
} // namespace CMakeProjectManager } // namespace CMakeProjectManager

View File

@@ -98,6 +98,9 @@ public:
Utils::CommandLine commandLineForTests(const QList<QString> &tests, Utils::CommandLine commandLineForTests(const QList<QString> &tests,
const QStringList &options) const final; const QStringList &options) const final;
ProjectExplorer::MakeInstallCommand makeInstallCommand(
const Utils::FilePath &installRoot) const final;
static bool filteredOutTarget(const CMakeBuildTarget &target); static bool filteredOutTarget(const CMakeBuildTarget &target);
bool isMultiConfig() const; bool isMultiConfig() const;

View File

@@ -64,6 +64,13 @@ void CMakeParser::setSourceDirectory(const QString &sourceDir)
OutputLineParser::Result CMakeParser::handleLine(const QString &line, OutputFormat type) OutputLineParser::Result CMakeParser::handleLine(const QString &line, OutputFormat type)
{ {
if (line.startsWith("ninja: build stopped")) {
m_lastTask = BuildSystemTask(Task::Error, line);
m_lines = 1;
flush();
return Status::Done;
}
if (type != StdErrFormat) if (type != StdErrFormat)
return Status::NotHandled; return Status::NotHandled;

View File

@@ -116,40 +116,4 @@ ProjectExplorer::DeploymentKnowledge CMakeProject::deploymentKnowledge() const
: DeploymentKnowledge::Bad; : DeploymentKnowledge::Bad;
} }
MakeInstallCommand CMakeProject::makeInstallCommand(const Target *target,
const FilePath &installRoot)
{
MakeInstallCommand cmd;
if (const BuildConfiguration * const bc = target->activeBuildConfiguration()) {
if (const auto cmakeStep = bc->buildSteps()->firstOfType<CMakeBuildStep>()) {
if (CMakeTool *tool = CMakeKitAspect::cmakeTool(target->kit()))
cmd.command.setExecutable(tool->cmakeExecutable());
}
}
QString installTarget = "install";
QStringList config;
auto bs = qobject_cast<CMakeBuildSystem*>(target->buildSystem());
QTC_ASSERT(bs, return {});
if (bs->usesAllCapsTargets())
installTarget = "INSTALL";
if (bs->isMultiConfigReader())
config << "--config" << bs->cmakeBuildType();
FilePath buildDirectory = ".";
if (auto bc = bs->buildConfiguration())
buildDirectory = bc->buildDirectory();
cmd.command.addArg("--build");
cmd.command.addArg(buildDirectory.onDevice(cmd.command.executable()).path());
cmd.command.addArg("--target");
cmd.command.addArg(installTarget);
cmd.command.addArgs(config);
cmd.environment.set("DESTDIR", installRoot.nativePath());
return cmd;
}
} // namespace CMakeProjectManager } // namespace CMakeProjectManager

View File

@@ -54,8 +54,6 @@ protected:
private: private:
ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const override; ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const override;
ProjectExplorer::MakeInstallCommand makeInstallCommand(const ProjectExplorer::Target *target,
const Utils::FilePath &installRoot) final;
mutable Internal::CMakeProjectImporter *m_projectImporter = nullptr; mutable Internal::CMakeProjectImporter *m_projectImporter = nullptr;

View File

@@ -337,13 +337,7 @@ QList<void *> CMakeProjectImporter::examineDirectory(const FilePath &importPath,
canonicalProjectDirectory.toUserOutput()); canonicalProjectDirectory.toUserOutput());
} }
// Determine QML debugging flags. This must match what we do in data->hasQmlDebugging = CMakeBuildConfiguration::hasQmlDebugging(config);
// CMakeBuildSettingsWidget::getQmlDebugCxxFlags()
// such that in doubt we leave the QML Debugging setting at "Leave at default"
const QString cxxFlagsInit = config.stringValueOf("CMAKE_CXX_FLAGS_INIT");
const QString cxxFlags = config.stringValueOf("CMAKE_CXX_FLAGS");
data->hasQmlDebugging = cxxFlagsInit.contains("-DQT_QML_DEBUG")
&& cxxFlags.contains("-DQT_QML_DEBUG");
data->buildDirectory = importPath; data->buildDirectory = importPath;
data->cmakeBuildType = buildType; data->cmakeBuildType = buildType;
@@ -394,10 +388,7 @@ bool CMakeProjectImporter::matchKit(void *directoryData, const Kit *k) const
if (!Utils::contains(allLanguages, [&tcd](const Id& language) {return language == tcd.language;})) if (!Utils::contains(allLanguages, [&tcd](const Id& language) {return language == tcd.language;}))
continue; continue;
ToolChain *tc = ToolChainKitAspect::toolChain(k, tcd.language); ToolChain *tc = ToolChainKitAspect::toolChain(k, tcd.language);
if (!tc if (!tc || !tc->matchesCompilerCommand(tcd.compilerPath)) {
|| !Utils::Environment::systemEnvironment()
.isSameExecutable(tc->compilerCommand().toString(),
tcd.compilerPath.toString())) {
return false; return false;
} }
} }

View File

@@ -154,15 +154,11 @@ class CocoTextMark : public TextEditor::TextMark
public: public:
CocoTextMark(const FilePath &fileName, const CocoDiagnostic &diag, const Id &clientId) CocoTextMark(const FilePath &fileName, const CocoDiagnostic &diag, const Id &clientId)
: TextEditor::TextMark(fileName, diag.range().start().line() + 1, clientId) : TextEditor::TextMark(fileName, diag.range().start().line() + 1, clientId)
, m_severity(diag.cocoSeverity())
{ {
setLineAnnotation(diag.message()); setLineAnnotation(diag.message());
setToolTip(diag.message()); setToolTip(diag.message());
if (optional<CocoDiagnosticSeverity> severity = diag.cocoSeverity()) { updateAnnotationColor();
const TextEditor::TextStyle style = styleForSeverity(*severity);
m_annotationColor =
TextEditor::TextEditorSettings::fontSettings().formatFor(style).foreground();
}
} }
QColor annotationColor() const override QColor annotationColor() const override
@@ -171,6 +167,16 @@ public:
: TextEditor::TextMark::annotationColor(); : TextEditor::TextMark::annotationColor();
} }
void updateAnnotationColor()
{
if (m_severity) {
const TextEditor::TextStyle style = styleForSeverity(*m_severity);
m_annotationColor =
TextEditor::TextEditorSettings::fontSettings().formatFor(style).foreground();
}
}
optional<CocoDiagnosticSeverity> m_severity;
QColor m_annotationColor; QColor m_annotationColor;
}; };
@@ -180,10 +186,22 @@ public:
CocoDiagnosticManager(Client *client) CocoDiagnosticManager(Client *client)
: DiagnosticManager(client) : DiagnosticManager(client)
{ {
connect(TextEditor::TextEditorSettings::instance(),
&TextEditor::TextEditorSettings::fontSettingsChanged,
this,
&CocoDiagnosticManager::fontSettingsChanged);
setExtraSelectionsId("CocoExtraSelections"); setExtraSelectionsId("CocoExtraSelections");
} }
private: private:
void fontSettingsChanged()
{
forAllMarks([](TextEditor::TextMark *mark){
static_cast<CocoTextMark *>(mark)->updateAnnotationColor();
mark->updateMarker();
});
}
TextEditor::TextMark *createTextMark(const FilePath &filePath, TextEditor::TextMark *createTextMark(const FilePath &filePath,
const Diagnostic &diagnostic, const Diagnostic &diagnostic,
bool /*isProjectFile*/) const override bool /*isProjectFile*/) const override

View File

@@ -188,7 +188,7 @@ const char G_VIEW_PANES[] = "QtCreator.Group.View.Panes";
// Tools menu groups // Tools menu groups
const char G_TOOLS_DEBUG[] = "QtCreator.Group.Tools.Debug"; const char G_TOOLS_DEBUG[] = "QtCreator.Group.Tools.Debug";
const char G_TOOLS_OPTIONS[] = "QtCreator.Group.Tools.Options"; const char G_EDIT_PREFERENCES[] = "QtCreator.Group.Edit.Preferences";
// Window menu groups // Window menu groups
const char G_WINDOW_SIZE[] = "QtCreator.Group.Window.Size"; const char G_WINDOW_SIZE[] = "QtCreator.Group.Window.Size";

View File

@@ -32,8 +32,10 @@
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QDir> #include <QDir>
#include <QDirIterator>
#include <QTemporaryFile> #include <QTemporaryFile>
#include <QVariant> #include <QVariant>
#include <QVersionNumber>
namespace Core { namespace Core {
namespace Internal { namespace Internal {
@@ -165,5 +167,34 @@ QString UtilsJsExtension::asciify(const QString &input) const
return result; return result;
} }
QString UtilsJsExtension::qtQuickVersion(const QString &filePath) const
{
QDirIterator dirIt(Utils::FilePath::fromString(filePath).parentDir().path(), {"*.qml"},
QDir::Files, QDirIterator::Subdirectories);
while (dirIt.hasNext()) {
Utils::FileReader reader;
if (!reader.fetch(Utils::FilePath::fromString(dirIt.next())))
continue;
const QString data = QString::fromUtf8(reader.data());
static const QString importString("import QtQuick");
const int importIndex = data.indexOf(importString);
if (importIndex == -1)
continue;
const int versionIndex = importIndex + importString.length();
const int newLineIndex = data.indexOf('\n', versionIndex);
if (newLineIndex == -1)
continue;
const QString versionString = data.mid(versionIndex,
newLineIndex - versionIndex).simplified();
if (versionString.isEmpty())
return {};
const auto version = QVersionNumber::fromString(versionString);
if (version.isNull())
return {};
return version.toString();
}
return QLatin1String("2.15");
}
} // namespace Internal } // namespace Internal
} // namespace Core } // namespace Core

View File

@@ -76,6 +76,9 @@ public:
// Generate a ascii-only string: // Generate a ascii-only string:
Q_INVOKABLE QString asciify(const QString &input) const; Q_INVOKABLE QString asciify(const QString &input) const;
// Heuristic to find out which QtQuick import version to use for the given file.
Q_INVOKABLE QString qtQuickVersion(const QString &filePath) const;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -152,7 +152,7 @@ void FilePropertiesDialog::refresh()
m_ui->name->setText(fileInfo.fileName()); m_ui->name->setText(fileInfo.fileName());
m_ui->path->setText(QDir::toNativeSeparators(fileInfo.canonicalPath())); m_ui->path->setText(QDir::toNativeSeparators(fileInfo.canonicalPath()));
const Utils::MimeType mimeType = Utils::mimeTypeForFile(fileInfo); const Utils::MimeType mimeType = Utils::mimeTypeForFile(m_filePath);
m_ui->mimeType->setText(mimeType.name()); m_ui->mimeType->setText(mimeType.name());
const EditorTypeList factories = IEditorFactory::preferredEditorTypes(m_filePath); const EditorTypeList factories = IEditorFactory::preferredEditorTypes(m_filePath);

View File

@@ -2148,8 +2148,8 @@ void EditorManagerPrivate::updateWindowTitleForDocument(IDocument *document, QWi
if (!documentName.isEmpty()) if (!documentName.isEmpty())
windowTitle.append(documentName); windowTitle.append(documentName);
const QString filePath = document ? document->filePath().absoluteFilePath().path() const Utils::FilePath filePath = document ? document->filePath().absoluteFilePath()
: QString(); : Utils::FilePath();
const QString windowTitleAddition = d->m_titleAdditionHandler const QString windowTitleAddition = d->m_titleAdditionHandler
? d->m_titleAdditionHandler(filePath) ? d->m_titleAdditionHandler(filePath)
: QString(); : QString();
@@ -2181,7 +2181,7 @@ void EditorManagerPrivate::updateWindowTitleForDocument(IDocument *document, QWi
windowTitle.append(dashSep); windowTitle.append(dashSep);
windowTitle.append(Core::Constants::IDE_DISPLAY_NAME); windowTitle.append(Core::Constants::IDE_DISPLAY_NAME);
window->window()->setWindowTitle(windowTitle); window->window()->setWindowTitle(windowTitle);
window->window()->setWindowFilePath(filePath); window->window()->setWindowFilePath(filePath.path());
if (HostOsInfo::isMacHost()) { if (HostOsInfo::isMacHost()) {
if (document) if (document)

View File

@@ -71,7 +71,7 @@ class CORE_EXPORT EditorManager : public QObject
Q_OBJECT Q_OBJECT
public: public:
using WindowTitleHandler = std::function<QString (const QString &)>; using WindowTitleHandler = std::function<QString (const Utils::FilePath &)>;
static EditorManager *instance(); static EditorManager *instance();

View File

@@ -717,14 +717,14 @@ void MainWindow::registerDefaultActions()
connect(m_loggerAction, &QAction::triggered, this, [] { LoggingViewer::showLoggingView(); }); connect(m_loggerAction, &QAction::triggered, this, [] { LoggingViewer::showLoggingView(); });
// Options Action // Options Action
mtools->appendGroup(Constants::G_TOOLS_OPTIONS); medit->appendGroup(Constants::G_EDIT_PREFERENCES);
mtools->addSeparator(Constants::G_TOOLS_OPTIONS); medit->addSeparator(Constants::G_EDIT_PREFERENCES);
m_optionsAction = new QAction(tr("&Options..."), this); m_optionsAction = new QAction(tr("&Preferences..."), this);
m_optionsAction->setMenuRole(QAction::PreferencesRole); m_optionsAction->setMenuRole(QAction::PreferencesRole);
cmd = ActionManager::registerAction(m_optionsAction, Constants::OPTIONS); cmd = ActionManager::registerAction(m_optionsAction, Constants::OPTIONS);
cmd->setDefaultKeySequence(QKeySequence::Preferences); cmd->setDefaultKeySequence(QKeySequence::Preferences);
mtools->addAction(cmd, Constants::G_TOOLS_OPTIONS); medit->addAction(cmd, Constants::G_EDIT_PREFERENCES);
connect(m_optionsAction, &QAction::triggered, this, [] { ICore::showOptionsDialog(Id()); }); connect(m_optionsAction, &QAction::triggered, this, [] { ICore::showOptionsDialog(Id()); });
mwindow->addSeparator(Constants::G_WINDOW_LIST); mwindow->addSeparator(Constants::G_WINDOW_LIST);

View File

@@ -112,7 +112,8 @@ static bool runPatchHelper(const QByteArray &input, const FilePath &workingDirec
QByteArray stdOut; QByteArray stdOut;
QByteArray stdErr; QByteArray stdErr;
if (!patchProcess.readDataFromProcess(30, &stdOut, &stdErr, true)) { if (!patchProcess.readDataFromProcess(30, &stdOut, &stdErr, true)) {
patchProcess.stopProcess(); patchProcess.stop();
patchProcess.waitForFinished();
MessageManager::writeFlashing( MessageManager::writeFlashing(
QApplication::translate("Core::PatchTool", "A timeout occurred running \"%1\"") QApplication::translate("Core::PatchTool", "A timeout occurred running \"%1\"")
.arg(patch.toUserOutput())); .arg(patch.toUserOutput()));

View File

@@ -124,11 +124,6 @@ CppCompletionAssistProvider *BuiltinModelManagerSupport::completionAssistProvide
} }
CppCompletionAssistProvider *BuiltinModelManagerSupport::functionHintAssistProvider()
{
return nullptr;
}
TextEditor::BaseHoverHandler *BuiltinModelManagerSupport::createHoverHandler() TextEditor::BaseHoverHandler *BuiltinModelManagerSupport::createHoverHandler()
{ {
return new CppHoverHandler; return new CppHoverHandler;

View File

@@ -42,7 +42,6 @@ public:
~BuiltinModelManagerSupport() override; ~BuiltinModelManagerSupport() override;
CppCompletionAssistProvider *completionAssistProvider() final; CppCompletionAssistProvider *completionAssistProvider() final;
CppCompletionAssistProvider *functionHintAssistProvider() override;
TextEditor::BaseHoverHandler *createHoverHandler() final; TextEditor::BaseHoverHandler *createHoverHandler() final;
BaseEditorDocumentProcessor *createEditorDocumentProcessor( BaseEditorDocumentProcessor *createEditorDocumentProcessor(
TextEditor::TextDocument *baseTextDocument) final; TextEditor::TextDocument *baseTextDocument) final;

View File

@@ -87,7 +87,7 @@ static FilePath fallbackClangdFilePath()
{ {
if (g_defaultClangdFilePath.exists()) if (g_defaultClangdFilePath.exists())
return g_defaultClangdFilePath; return g_defaultClangdFilePath;
return "clangd"; return Environment::systemEnvironment().searchInPath("clangd");
} }
void CppCodeModelSettings::fromSettings(QSettings *s) void CppCodeModelSettings::fromSettings(QSettings *s)

View File

@@ -26,16 +26,13 @@
#include "cppeditordocument.h" #include "cppeditordocument.h"
#include "baseeditordocumentparser.h" #include "baseeditordocumentparser.h"
#include "builtineditordocumentprocessor.h"
#include "cppcodeformatter.h" #include "cppcodeformatter.h"
#include "cppcodemodelsettings.h"
#include "cppeditorconstants.h" #include "cppeditorconstants.h"
#include "cppeditorplugin.h" #include "cppeditorplugin.h"
#include "cppmodelmanager.h" #include "cppmodelmanager.h"
#include "cppeditorconstants.h" #include "cppeditorconstants.h"
#include "cppeditorplugin.h" #include "cppeditorplugin.h"
#include "cpphighlighter.h" #include "cpphighlighter.h"
#include "cppqtstyleindenter.h"
#include "cppquickfixassistant.h" #include "cppquickfixassistant.h"
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
@@ -58,20 +55,17 @@
const char NO_PROJECT_CONFIGURATION[] = "NoProject"; const char NO_PROJECT_CONFIGURATION[] = "NoProject";
namespace {
CppEditor::CppModelManager *mm()
{
return CppEditor::CppModelManager::instance();
}
} // anonymous namespace
using namespace TextEditor; using namespace TextEditor;
using namespace Utils;
namespace CppEditor { namespace CppEditor {
namespace Internal { namespace Internal {
static CppEditor::CppModelManager *mm()
{
return CppEditor::CppModelManager::instance();
}
enum { processDocumentIntervalInMs = 150 }; enum { processDocumentIntervalInMs = 150 };
class CppEditorDocumentHandleImpl : public CppEditorDocumentHandle class CppEditorDocumentHandleImpl : public CppEditorDocumentHandle
@@ -150,24 +144,12 @@ void CppEditorDocument::setCompletionAssistProvider(TextEditor::CompletionAssist
m_completionAssistProvider = nullptr; m_completionAssistProvider = nullptr;
} }
void CppEditorDocument::setFunctionHintAssistProvider(TextEditor::CompletionAssistProvider *provider)
{
TextDocument::setFunctionHintAssistProvider(provider);
m_functionHintAssistProvider = nullptr;
}
CompletionAssistProvider *CppEditorDocument::completionAssistProvider() const CompletionAssistProvider *CppEditorDocument::completionAssistProvider() const
{ {
return m_completionAssistProvider return m_completionAssistProvider
? m_completionAssistProvider : TextDocument::completionAssistProvider(); ? m_completionAssistProvider : TextDocument::completionAssistProvider();
} }
CompletionAssistProvider *CppEditorDocument::functionHintAssistProvider() const
{
return m_functionHintAssistProvider
? m_functionHintAssistProvider : TextDocument::functionHintAssistProvider();
}
TextEditor::IAssistProvider *CppEditorDocument::quickFixAssistProvider() const TextEditor::IAssistProvider *CppEditorDocument::quickFixAssistProvider() const
{ {
if (const auto baseProvider = TextDocument::quickFixAssistProvider()) if (const auto baseProvider = TextDocument::quickFixAssistProvider())
@@ -223,7 +205,6 @@ void CppEditorDocument::onMimeTypeChanged()
m_isObjCEnabled = (mt == QLatin1String(Constants::OBJECTIVE_C_SOURCE_MIMETYPE) m_isObjCEnabled = (mt == QLatin1String(Constants::OBJECTIVE_C_SOURCE_MIMETYPE)
|| mt == QLatin1String(Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE)); || mt == QLatin1String(Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE));
m_completionAssistProvider = mm()->completionAssistProvider(); m_completionAssistProvider = mm()->completionAssistProvider();
m_functionHintAssistProvider = mm()->functionHintAssistProvider();
initializeTimer(); initializeTimer();
} }
@@ -258,14 +239,13 @@ void CppEditorDocument::reparseWithPreferredParseContext(const QString &parseCon
scheduleProcessDocument(); scheduleProcessDocument();
} }
void CppEditorDocument::onFilePathChanged(const Utils::FilePath &oldPath, void CppEditorDocument::onFilePathChanged(const FilePath &oldPath, const FilePath &newPath)
const Utils::FilePath &newPath)
{ {
Q_UNUSED(oldPath) Q_UNUSED(oldPath)
if (!newPath.isEmpty()) { if (!newPath.isEmpty()) {
indenter()->setFileName(newPath); indenter()->setFileName(newPath);
setMimeType(Utils::mimeTypeForFile(newPath.toFileInfo()).name()); setMimeType(mimeTypeForFile(newPath).name());
connect(this, &Core::IDocument::contentsChanged, connect(this, &Core::IDocument::contentsChanged,
this, &CppEditorDocument::scheduleProcessDocument, this, &CppEditorDocument::scheduleProcessDocument,
@@ -376,13 +356,13 @@ void CppEditorDocument::releaseResources()
void CppEditorDocument::showHideInfoBarAboutMultipleParseContexts(bool show) void CppEditorDocument::showHideInfoBarAboutMultipleParseContexts(bool show)
{ {
const Utils::Id id = Constants::MULTIPLE_PARSE_CONTEXTS_AVAILABLE; const Id id = Constants::MULTIPLE_PARSE_CONTEXTS_AVAILABLE;
if (show) { if (show) {
Utils::InfoBarEntry info(id, InfoBarEntry info(id,
tr("Note: Multiple parse contexts are available for this file. " tr("Note: Multiple parse contexts are available for this file. "
"Choose the preferred one from the editor toolbar."), "Choose the preferred one from the editor toolbar."),
Utils::InfoBarEntry::GlobalSuppression::Enabled); InfoBarEntry::GlobalSuppression::Enabled);
info.removeCancelButton(); info.removeCancelButton();
if (infoBar()->canInfoBeAdded(id)) if (infoBar()->canInfoBeAdded(id))
infoBar()->addInfo(info); infoBar()->addInfo(info);
@@ -457,9 +437,9 @@ TextEditor::TabSettings CppEditorDocument::tabSettings() const
return indenter()->tabSettings().value_or(TextEditor::TextDocument::tabSettings()); return indenter()->tabSettings().value_or(TextEditor::TextDocument::tabSettings());
} }
bool CppEditorDocument::save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) bool CppEditorDocument::save(QString *errorString, const FilePath &filePath, bool autoSave)
{ {
Utils::ExecuteOnDestruction resetSettingsOnScopeExit; ExecuteOnDestruction resetSettingsOnScopeExit;
if (indenter()->formatOnSave() && !autoSave) { if (indenter()->formatOnSave() && !autoSave) {
auto *layout = qobject_cast<TextEditor::TextDocumentLayout *>(document()->documentLayout()); auto *layout = qobject_cast<TextEditor::TextDocumentLayout *>(document()->documentLayout());

View File

@@ -51,9 +51,7 @@ public:
bool isObjCEnabled() const; bool isObjCEnabled() const;
void setCompletionAssistProvider(TextEditor::CompletionAssistProvider *provider) override; void setCompletionAssistProvider(TextEditor::CompletionAssistProvider *provider) override;
void setFunctionHintAssistProvider(TextEditor::CompletionAssistProvider *provider) override;
TextEditor::CompletionAssistProvider *completionAssistProvider() const override; TextEditor::CompletionAssistProvider *completionAssistProvider() const override;
TextEditor::CompletionAssistProvider *functionHintAssistProvider() const override;
TextEditor::IAssistProvider *quickFixAssistProvider() const override; TextEditor::IAssistProvider *quickFixAssistProvider() const override;
void recalculateSemanticInfoDetached(); void recalculateSemanticInfoDetached();
@@ -128,7 +126,6 @@ private:
QScopedPointer<BaseEditorDocumentProcessor> m_processor; QScopedPointer<BaseEditorDocumentProcessor> m_processor;
CppCompletionAssistProvider *m_completionAssistProvider = nullptr; CppCompletionAssistProvider *m_completionAssistProvider = nullptr;
CppCompletionAssistProvider *m_functionHintAssistProvider = nullptr;
// (Un)Registration in CppModelManager // (Un)Registration in CppModelManager
QScopedPointer<CppEditorDocumentHandle> m_editorDocumentHandle; QScopedPointer<CppEditorDocumentHandle> m_editorDocumentHandle;

View File

@@ -632,25 +632,6 @@ CPlusPlus::Symbol *CppFindReferences::findSymbol(const CppFindReferencesParamete
return nullptr; return nullptr;
} }
Utils::optional<QString> getContainingFunctionName(const Utils::FilePath &fileName,
int line,
int column)
{
const CPlusPlus::Snapshot snapshot = CppModelManager::instance()->snapshot();
auto document = snapshot.document(fileName);
// context properties need lookup inside function scope, and thus require a full check
CPlusPlus::Document::Ptr localDoc = document;
if (document->checkMode() != CPlusPlus::Document::FullCheck) {
localDoc = snapshot.documentFromSource(document->utf8Source(), document->fileName());
localDoc->check();
}
auto funcName = localDoc->functionAt(line, column);
return funcName.size() ? Utils::make_optional(funcName) : Utils::nullopt;
}
static void displayResults(SearchResult *search, static void displayResults(SearchResult *search,
QFutureWatcher<CPlusPlus::Usage> *watcher, QFutureWatcher<CPlusPlus::Usage> *watcher,
int first, int first,
@@ -665,24 +646,11 @@ static void displayResults(SearchResult *search,
item.setMainRange(result.line, result.col, result.len); item.setMainRange(result.line, result.col, result.len);
item.setLineText(result.lineText); item.setLineText(result.lineText);
item.setUserData(int(result.type)); item.setUserData(int(result.type));
item.setContainingFunctionName(result.containingFunction);
item.setStyle(colorStyleForUsageType(result.type)); item.setStyle(colorStyleForUsageType(result.type));
item.setUseTextEditorFont(true); item.setUseTextEditorFont(true);
if (search->supportsReplace()) if (search->supportsReplace())
item.setSelectForReplacement(SessionManager::projectForFile(result.path)); item.setSelectForReplacement(SessionManager::projectForFile(result.path));
// In case we're looking for a function, we need to look at the symbol near the end. This
// is needed to avoid following corner-cases:
// 1) if we're looking at the beginning of the function declaration, we can get the
// declaration of the previous function
// 2) if we're looking somewhere at the middle of the function declaration, we can still
// get the declaration of the previous function if the cursor is located at the
// namespace declaration, i.e. CppReference>|<s::findUsages
const auto containingFunctionName = getContainingFunctionName(result.path,
result.line,
(result.col + result.len) - 1);
item.setContainingFunctionName(containingFunctionName);
search->addResult(item); search->addResult(item);
if (parameters.prettySymbolName.isEmpty()) if (parameters.prettySymbolName.isEmpty())
@@ -777,7 +745,7 @@ restart_search:
if (macro.name() == useMacro.name()) { if (macro.name() == useMacro.name()) {
unsigned column; unsigned column;
const QString &lineSource = matchingLine(use.bytesBegin(), source, &column); const QString &lineSource = matchingLine(use.bytesBegin(), source, &column);
usages.append(CPlusPlus::Usage(fileName, lineSource, usages.append(CPlusPlus::Usage(fileName, lineSource, {},
CPlusPlus::Usage::Type::Other, use.beginLine(), CPlusPlus::Usage::Type::Other, use.beginLine(),
column, useMacro.nameToQString().size())); column, useMacro.nameToQString().size()));
} }

View File

@@ -1620,11 +1620,6 @@ CppCompletionAssistProvider *CppModelManager::completionAssistProvider() const
return d->m_builtinModelManagerSupport->completionAssistProvider(); return d->m_builtinModelManagerSupport->completionAssistProvider();
} }
CppCompletionAssistProvider *CppModelManager::functionHintAssistProvider() const
{
return d->m_builtinModelManagerSupport->functionHintAssistProvider();
}
TextEditor::BaseHoverHandler *CppModelManager::createHoverHandler() const TextEditor::BaseHoverHandler *CppModelManager::createHoverHandler() const
{ {
return d->m_builtinModelManagerSupport->createHoverHandler(); return d->m_builtinModelManagerSupport->createHoverHandler();

View File

@@ -162,7 +162,6 @@ public:
void activateClangCodeModel(ModelManagerSupportProvider *modelManagerSupportProvider); void activateClangCodeModel(ModelManagerSupportProvider *modelManagerSupportProvider);
CppCompletionAssistProvider *completionAssistProvider() const; CppCompletionAssistProvider *completionAssistProvider() const;
CppCompletionAssistProvider *functionHintAssistProvider() const;
BaseEditorDocumentProcessor *createEditorDocumentProcessor( BaseEditorDocumentProcessor *createEditorDocumentProcessor(
TextEditor::TextDocument *baseTextDocument) const; TextEditor::TextDocument *baseTextDocument) const;
TextEditor::BaseHoverHandler *createHoverHandler() const; TextEditor::BaseHoverHandler *createHoverHandler() const;

View File

@@ -57,7 +57,6 @@ public:
virtual ~ModelManagerSupport() = 0; virtual ~ModelManagerSupport() = 0;
virtual CppCompletionAssistProvider *completionAssistProvider() = 0; virtual CppCompletionAssistProvider *completionAssistProvider() = 0;
virtual CppCompletionAssistProvider *functionHintAssistProvider() = 0;
virtual TextEditor::BaseHoverHandler *createHoverHandler() = 0; virtual TextEditor::BaseHoverHandler *createHoverHandler() = 0;
virtual BaseEditorDocumentProcessor *createEditorDocumentProcessor( virtual BaseEditorDocumentProcessor *createEditorDocumentProcessor(
TextEditor::TextDocument *baseTextDocument) = 0; TextEditor::TextDocument *baseTextDocument) = 0;

View File

@@ -1745,6 +1745,16 @@ void QuickfixTest::testGeneric_data()
<< CppQuickFixFactoryPtr(new EscapeStringLiteral) << CppQuickFixFactoryPtr(new EscapeStringLiteral)
<< _(R"(const char *str = @"\xc3\xa0""f23\xd0\xb1g\xd0\xb1""1";)") << _(R"(const char *str = @"\xc3\xa0""f23\xd0\xb1g\xd0\xb1""1";)")
<< _(R"(const char *str = "àf23бgб1";)"); << _(R"(const char *str = "àf23бgб1";)");
QTest::newRow("AddLocalDeclaration_QTCREATORBUG-26004")
<< CppQuickFixFactoryPtr(new AddLocalDeclaration)
<< _("void func() {\n"
" QStringList list;\n"
" @it = list.cbegin();\n"
"}\n")
<< _("void func() {\n"
" QStringList list;\n"
" auto it = list.cbegin();\n"
"}\n");
} }
void QuickfixTest::testGeneric() void QuickfixTest::testGeneric()

Some files were not shown because too many files have changed in this diff Show More