Merge remote-tracking branch 'origin/4.5'

Conflicts:
	src/plugins/debugger/debuggerruncontrol.cpp
	src/plugins/projectexplorer/gcctoolchain.cpp

Change-Id: Iaad0659293681cce4266fc3e4ba2a4f2068de911
This commit is contained in:
Eike Ziller
2017-10-09 12:09:27 +02:00
256 changed files with 4735 additions and 4046 deletions
+66
View File
@@ -0,0 +1,66 @@
Qt Creator version 4.4.1 contains bug fixes.
The most important changes are listed in this document. For a complete
list of changes, see the Git log for the Qt Creator sources that
you can check out from the public Git repository. For example:
git clone git://code.qt.io/qt-creator/qt-creator.git
git log --cherry-pick --pretty=oneline v4.4.0..v4.4.1
FakeVim
* Fixed recognition of shortened `tabnext` and `tabprevious` commands
(QTCREATORBUG-18843)
All Projects
* Fixed `Add Existing Files` for top-level project nodes (QTCREATORBUG-18896)
C++ Support
* Improved handling of parsing failures (QTCREATORBUG-18864)
* Fixed crash with invalid raw string literal (QTCREATORBUG-18941)
* Fixed that code model did not use sysroot as reported from the build system
(QTCREATORBUG-18633)
* Fixed highlighting of `float` in C files (QTCREATORBUG-18879)
* Fixed `Convert to Camel Case` (QTCREATORBUG-18947)
Debugging
* Fixed that custom `solib-search-path` startup commands were ignored
(QTCREATORBUG-18812)
* Fixed `Run in terminal` when debugging external application
(QTCREATORBUG-18912)
* Fixed pretty printing of `CHAR` and `WCHAR`
Clang Static Analyzer
* Fixed options passed to analyzer on Windows
Qt Quick Designer
* Fixed usage of `shift` modifier when reparenting layouts
SCXML Editor
* Fixed eventless transitions (QTCREATORBUG-18345)
Test Integration
* Fixed test result output when debugging
Platform Specific
Windows
* Fixed auto-detection of CMake 3.9 and later
Android
* Fixed issues with new Android SDK (26.1.1) (QTCREATORBUG-18962)
* Fixed search path for QML modules when debugging
QNX
* Fixed debugging (QTCREATORBUG-18804, QTCREATORBUG-17901)
* Fixed QML profiler startup (QTCREATORBUG-18954)
+154
View File
@@ -0,0 +1,154 @@
Qt Creator version 4.5 contains bug fixes and new features.
The most important changes are listed in this document. For a complete
list of changes, see the Git log for the Qt Creator sources that
you can check out from the public Git repository. For example:
git clone git://code.qt.io/qt-creator/qt-creator.git
git log --cherry-pick --pretty=oneline origin/4.4..v4.5.0
General
* Implemented "fuzzy" camel case lookup similar to code completion for locator
(QTCREATORBUG-3111)
* Changed `File System` pane to tree view with top level directory selectable
from `Computer`, `Home`, `Projects`, and individual project root directories
(QTCREATORBUG-8305)
Editing
* Added shortcut for sorting selected lines
All Projects
* Added progress indicator to project tree while project is parsed
* Added support for changing the maximum number of lines shown in compile output
(QTCREATORBUG-2200)
CMake Projects
* Added groups to CMake configuration UI
* Added option to change configuration variable types
* Fixed that value was removed when renaming configuration variable
(QTCREATORBUG-17926)
C++ Support
* Fixed lookup of functions that differ only in const-ness of arguments
(QTCREATORBUG-18475)
* Fixed detection of macros defined by tool chain for `C`
* Fixed that `Refactoring` context menu blocked UI while checking for available
actions
* Clang Code Model
* Added sanity check to `Clang Code Model Warnings` option
(QTCREATORBUG-18864)
* Fixed completion in `std::make_unique` and `std::make_shared` constructors
(QTCREATORBUG-18615)
* Fixed that function argument completion switched selected overload back to
default after typing comma (QTCREATORBUG-11688)
* GCC
* Improved auto-detection to include versioned binaries and cross-compilers
QML Support
* Added wizards with different starting UI layouts
Python Support
* Added simple code folding
Debugging
* Changed pretty printing of `QFlags` and bitfields to hexadecimal
* Fixed `Run in terminal` for debugging external application
(QTCREATORBUG-18912)
* LLDB / macOS
* Added pretty printing of Core Foundation and Foundation string-like types
(QTCREATORBUG-18638)
QML Profiler
* Improved robustness when faced with invalid data
Qt Quick Designer
* Added option to only show visible items in navigator
Version Control Systems
* Added query for saving modified files before opening commit editor
(QTCREATORBUG-3857)
Beautifier
* Clang Format
* Added action `Disable Formatting for Selected Text`
* Changed formatting without selection to format the syntactic entity
around the cursor
Model Editor
* Added support for custom relations
SCXML Editor
* Fixed crash after warnings are removed
Platform Specific
Windows
* Fixed that environment variable keys were converted to upper case in build
and run configurations (QTCREATORBUG-18915)
macOS
* Fixed several issues when using case sensitive file systems while `File system
case sensitivity` is set to `Case Insensitive` (QTCREATORBUG-17929,
QTCREATORBUG-18672, QTCREATORBUG-18678)
Android
* Removed support for local deployment (QTBUG-62995)
* Removed support for Ant
* Improved checks for minimum requirements of Android tools (QTCREATORBUG-18837)
Universal Windows Platform
* Fixed deployment on Windows 10 Phone emulator
Credits for these changes go to:
Alessandro Portale
Alexander Volkov
Andre Hartmann
André Pönitz
Christian Kandeler
Christian Stenger
Claus Steuer
Daniel Trevitz
David Schulz
Eike Ziller
Friedemann Kleint
Ivan Donchevskii
Jake Petroules
Jaroslaw Kobus
Jochen Becher
Knud Dollereder
Laurent Montel
Marco Benelli
Marco Bubke
Mitch Curtis
Nikita Baryshnikov
Nikolai Kosjar
Oliver Wolff
Orgad Shaneh
Robert Löhning
Ryuji Kakemizu
Samuel Gaist
Serhii Moroz
Thiago Macieira
Thomas Hartmann
Tim Jenssen
Tobias Hunger
Ulf Hermann
Vikas Pachdha
+4 -4
View File
@@ -1,8 +1,8 @@
var Environment = loadExtension("qbs.Environment")
var File = loadExtension("qbs.File")
var FileInfo = loadExtension("qbs.FileInfo")
var Environment = require("qbs.Environment")
var File = require("qbs.File")
var FileInfo = require("qbs.FileInfo")
var MinimumLLVMVersion = "3.9.0"
var Process = loadExtension("qbs.Process")
var Process = require("qbs.Process")
function readOutput(executable, args)
{
@@ -4,6 +4,8 @@ import qbs.FileInfo
Module {
Depends { name: "qtc" }
property bool priority: 1 // TODO: Remove declaration after 1.11 is out.
property bool enableUnitTests: false
property bool enableProjectFileUpdates: true
property bool installApiHeaders: false
+3 -3
View File
@@ -1,6 +1,6 @@
var File = loadExtension("qbs.File");
var FileInfo = loadExtension("qbs.FileInfo");
var TextFile = loadExtension("qbs.TextFile");
var File = require("qbs.File");
var FileInfo = require("qbs.FileInfo");
var TextFile = require("qbs.TextFile");
function getExportBlock(productFile)
{
+1 -1
View File
@@ -4,7 +4,7 @@ import qbs.FileInfo
Project {
name: "Qt Creator"
minimumQbsVersion: "1.7.0"
minimumQbsVersion: "1.8.0"
property string minimumMacosVersion: "10.8"
property bool withAutotests: qbs.buildVariant === "debug"
property path ide_source_tree: path
+1
View File
@@ -67,6 +67,7 @@ source_include_patterns = [
r"^doc/.*$", # include everything under doc/
r"^.*\.pri$", # .pri files in all directories that are looked into
r"^.*\.h$", # .h files in all directories that are looked into
r"^.*\.hpp$" # .hpp files in all directories that are looked into
]
build_include_patterns = [
+25 -10
View File
@@ -321,7 +321,7 @@ private:
inline int consumeToken() {
if (_index < int(_tokens.size()))
return _index++;
return _tokens.size() - 1;
return static_cast<int>(_tokens.size()) - 1;
}
inline const Token &tokenAt(int index) const {
if (index == 0)
@@ -468,30 +468,30 @@ Parser::Parser(Engine *engine, const char *source, unsigned size, int variant)
switch (tk.kind) {
case T_LEFT_PAREN:
parenStack.push(_tokens.size());
parenStack.push(static_cast<int>(_tokens.size()));
break;
case T_LEFT_BRACKET:
bracketStack.push(_tokens.size());
bracketStack.push(static_cast<int>(_tokens.size()));
break;
case T_LEFT_BRACE:
braceStack.push(_tokens.size());
braceStack.push(static_cast<int>(_tokens.size()));
break;
case T_RIGHT_PAREN:
if (! parenStack.empty()) {
_tokens[parenStack.top()].matchingBrace = _tokens.size();
_tokens[parenStack.top()].matchingBrace = static_cast<int>(_tokens.size());
parenStack.pop();
}
break;
case T_RIGHT_BRACKET:
if (! bracketStack.empty()) {
_tokens[bracketStack.top()].matchingBrace = _tokens.size();
_tokens[bracketStack.top()].matchingBrace = static_cast<int>(_tokens.size());
bracketStack.pop();
}
break;
case T_RIGHT_BRACE:
if (! braceStack.empty()) {
_tokens[braceStack.top()].matchingBrace = _tokens.size();
_tokens[braceStack.top()].matchingBrace = static_cast<int>(_tokens.size());
braceStack.pop();
}
break;
@@ -519,9 +519,13 @@ AST *Parser::parse(int startToken)
_recovered = false;
_tos = -1;
_startToken.kind = startToken;
int recoveryAttempts = 0;
do {
again:
recoveryAttempts = 0;
againAfterRecovery:
if (unsigned(++_tos) == _stateStack.size()) {
_stateStack.resize(_tos * 2);
_locationStack.resize(_tos * 2);
@@ -564,6 +568,7 @@ AST *Parser::parse(int startToken)
reduce(ruleno);
action = nt_action(_stateStack[_tos], lhs[ruleno] - TERMINAL_COUNT);
} else if (action == 0) {
++recoveryAttempts;
const int line = _tokens[yyloc].line + 1;
QString message = QLatin1String("Syntax error");
if (yytoken != -1) {
@@ -574,7 +579,7 @@ AST *Parser::parse(int startToken)
for (; _tos; --_tos) {
const int state = _stateStack[_tos];
static int tks[] = {
static int tks1[] = {
T_RIGHT_BRACE, T_RIGHT_PAREN, T_RIGHT_BRACKET,
T_SEMICOLON, T_COLON, T_COMMA,
T_NUMBER, T_TYPE_NAME, T_IDENTIFIER,
@@ -582,6 +587,16 @@ AST *Parser::parse(int startToken)
T_WHILE,
0
};
static int tks2[] = {
T_RIGHT_BRACE, T_RIGHT_PAREN, T_RIGHT_BRACKET,
T_SEMICOLON, T_COLON, T_COMMA,
0
};
int *tks;
if (recoveryAttempts < 2)
tks = tks1;
else
tks = tks2; // Avoid running into an endless loop for e.g.: for(int x=0; x y
for (int *tptr = tks; *tptr; ++tptr) {
const int next = t_action(state, *tptr);
@@ -604,7 +619,7 @@ AST *Parser::parse(int startToken)
yytoken = -1;
action = next;
goto again;
goto againAfterRecovery;
}
}
}
+19 -4
View File
@@ -1,5 +1,5 @@
#line 423 "./glsl.g"
#line 413 "./glsl.g"
/****************************************************************************
**
@@ -109,9 +109,13 @@ AST *Parser::parse(int startToken)
_recovered = false;
_tos = -1;
_startToken.kind = startToken;
int recoveryAttempts = 0;
do {
again:
recoveryAttempts = 0;
againAfterRecovery:
if (unsigned(++_tos) == _stateStack.size()) {
_stateStack.resize(_tos * 2);
_locationStack.resize(_tos * 2);
@@ -154,6 +158,7 @@ AST *Parser::parse(int startToken)
reduce(ruleno);
action = nt_action(_stateStack[_tos], lhs[ruleno] - TERMINAL_COUNT);
} else if (action == 0) {
++recoveryAttempts;
const int line = _tokens[yyloc].line + 1;
QString message = QLatin1String("Syntax error");
if (yytoken != -1) {
@@ -164,7 +169,7 @@ AST *Parser::parse(int startToken)
for (; _tos; --_tos) {
const int state = _stateStack[_tos];
static int tks[] = {
static int tks1[] = {
T_RIGHT_BRACE, T_RIGHT_PAREN, T_RIGHT_BRACKET,
T_SEMICOLON, T_COLON, T_COMMA,
T_NUMBER, T_TYPE_NAME, T_IDENTIFIER,
@@ -172,6 +177,16 @@ AST *Parser::parse(int startToken)
T_WHILE,
0
};
static int tks2[] = {
T_RIGHT_BRACE, T_RIGHT_PAREN, T_RIGHT_BRACKET,
T_SEMICOLON, T_COLON, T_COMMA,
0
};
int *tks;
if (recoveryAttempts < 2)
tks = tks1;
else
tks = tks2; // Avoid running into an endless loop for e.g.: for(int x=0; x y
for (int *tptr = tks; *tptr; ++tptr) {
const int next = t_action(state, *tptr);
@@ -194,7 +209,7 @@ AST *Parser::parse(int startToken)
yytoken = -1;
action = next;
goto again;
goto againAfterRecovery;
}
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
#line 215 "./glsl.g"
#line 210 "./glsl.g"
/****************************************************************************
**
File diff suppressed because it is too large Load Diff
+19 -13
View File
@@ -3,8 +3,9 @@
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -21,6 +22,8 @@
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
//
@@ -35,9 +38,10 @@
//
// This file was generated by qlalr - DO NOT EDIT!
#pragma once
#ifndef GLSLPARSERTABLE_P_H
#define GLSLPARSERTABLE_P_H
#include <qglobal.h>
#include <QtCore/qglobal.h>
QT_BEGIN_NAMESPACE
@@ -228,18 +232,18 @@ public:
NON_TERMINAL_COUNT = 85,
GOTO_INDEX_OFFSET = 463,
GOTO_INFO_OFFSET = 4681,
GOTO_CHECK_OFFSET = 4681
GOTO_INFO_OFFSET = 4708,
GOTO_CHECK_OFFSET = 4708
};
static const char *const spell [];
static const short lhs [];
static const short rhs [];
static const short goto_default [];
static const short action_default [];
static const short action_index [];
static const short action_info [];
static const short action_check [];
static const char *const spell[];
static const short lhs[];
static const short rhs[];
static const short goto_default[];
static const short action_default[];
static const short action_index[];
static const short action_info[];
static const short action_check[];
static inline int nt_action (int state, int nt)
{
@@ -263,3 +267,5 @@ public:
QT_END_NAMESPACE
#endif // GLSLPARSERTABLE_P_H
+17 -4
View File
@@ -33,6 +33,13 @@ namespace Utils {
Benchmarker::Benchmarker(const QString &testsuite, const QString &testcase,
const QString &tagData) :
Benchmarker(benchmarksLog(), testsuite, testcase, tagData)
{ }
Benchmarker::Benchmarker(const QLoggingCategory &cat,
const QString &testsuite, const QString &testcase,
const QString &tagData) :
m_category(cat),
m_tagData(tagData),
m_testsuite(testsuite),
m_testcase(testcase)
@@ -49,17 +56,23 @@ Benchmarker::~Benchmarker()
void Benchmarker::report(qint64 ms)
{
m_timer.invalidate();
report(m_testsuite, m_testcase, ms, m_tagData);
report(m_category, m_testsuite, m_testcase, ms, m_tagData);
}
void Benchmarker::report(const QString &testsuite, const QString &testcase, qint64 ms,
const QString &tags)
void Benchmarker::report(const QString &testsuite,
const QString &testcase, qint64 ms, const QString &tags)
{
report(benchmarksLog(), testsuite, testcase, ms, tags);
}
void Benchmarker::report(const QLoggingCategory &cat, const QString &testsuite, const QString &testcase,
qint64 ms, const QString &tags)
{
QString t = "unit=ms";
if (!tags.isEmpty())
t += "," + tags;
qCDebug(benchmarksLog, "%s::%s: %lld { %s }",
qCDebug(cat, "%s::%s: %lld { %s }",
testsuite.toUtf8().data(), testcase.toUtf8().data(), ms, t.toUtf8().data());
}
+13 -3
View File
@@ -30,20 +30,30 @@
#include <QString>
#include <QElapsedTimer>
QT_BEGIN_NAMESPACE
class QLoggingCategory;
QT_END_NAMESPACE
namespace Utils {
class QTCREATOR_UTILS_EXPORT Benchmarker
{
public:
Benchmarker(const QString &testsuite, const QString &testcase,
const QString &tags = QString());
const QString &tagData = QString());
Benchmarker(const QLoggingCategory &cat, const QString &testsuite, const QString &testcase,
const QString &tagData = QString());
~Benchmarker();
void report(qint64 ms);
static void report(const QString &testsuite, const QString &testcase, qint64 ms,
const QString &tags = QString());
static void report(const QString &testsuite, const QString &testcase,
qint64 ms, const QString &tags = QString());
static void report(const QLoggingCategory &cat,
const QString &testsuite, const QString &testcase,
qint64 ms, const QString &tags = QString());
private:
const QLoggingCategory &m_category;
QElapsedTimer m_timer;
QString m_tagData;
QString m_testsuite;
+21 -12
View File
@@ -65,6 +65,7 @@ QRegularExpression CamelHumpMatcher::createCamelHumpRegExp(
*/
QString keyRegExp;
QString plainRegExp;
bool first = true;
const QChar asterisk = '*';
const QChar question = '?';
@@ -76,27 +77,33 @@ QRegularExpression CamelHumpMatcher::createCamelHumpRegExp(
keyRegExp += "(?:";
for (const QChar &c : pattern) {
if (!c.isLetter()) {
if (c == question)
if (c == question) {
keyRegExp += '.';
else if (c == asterisk)
plainRegExp += '.';
} else if (c == asterisk) {
keyRegExp += ".*";
else
keyRegExp += '(' + QRegularExpression::escape(c) + ')';
plainRegExp += ".*";
} else {
const QString escaped = QRegularExpression::escape(c);
keyRegExp += '(' + escaped + ')';
plainRegExp += escaped;
}
} else if (caseSensitivity == CaseSensitivity::CaseInsensitive ||
(caseSensitivity == CaseSensitivity::FirstLetterCaseSensitive && !first)) {
const QString upper = QRegularExpression::escape(c.toUpper());
const QString lower = QRegularExpression::escape(c.toLower());
keyRegExp += "(?:";
keyRegExp += first ? uppercaseWordFirst : uppercaseWordContinuation;
keyRegExp += '(' + QRegularExpression::escape(c.toUpper());
keyRegExp += '(' + upper + ')';
if (first) {
keyRegExp += '|' + lowercaseWordFirst + QRegularExpression::escape(c.toLower()) + ')';
keyRegExp += '|' + lowercaseWordFirst + '(' + lower + ')';
} else {
keyRegExp += ")|" + lowercaseWordContinuation;
keyRegExp += '(' + QRegularExpression::escape(c.toLower()) + ")|";
keyRegExp += upperSnakeWordContinuation;
keyRegExp += '(' + QRegularExpression::escape(c.toUpper()) + ')';
keyRegExp += '|' + lowercaseWordContinuation + '(' + lower + ')';
keyRegExp += '|' + upperSnakeWordContinuation + '(' + upper + ')';
}
keyRegExp += ')';
plainRegExp += '[' + upper + lower + ']';
} else {
if (!first) {
if (c.isUpper())
@@ -104,12 +111,14 @@ QRegularExpression CamelHumpMatcher::createCamelHumpRegExp(
else
keyRegExp += lowercaseWordContinuation;
}
keyRegExp += QRegularExpression::escape(c);
const QString escaped = QRegularExpression::escape(c);
keyRegExp += escaped;
plainRegExp += escaped;
}
first = false;
}
keyRegExp += ")|(" + QRegularExpression::escape(pattern) + ')';
keyRegExp += ")|(" + plainRegExp + ')';
return QRegularExpression(keyRegExp);
}
+2
View File
@@ -423,6 +423,8 @@ SynchronousProcessResponse ShellCommand::runSynchronous(const FileName &binary,
connect(&process, &Utils::SynchronousProcess::stdErrBuffered,
this, [this, proxy](const QString &text)
{
if (d->m_progressParser)
d->m_progressParser->parseProgress(text);
if (!(d->m_flags & SuppressStdErr))
proxy->appendError(text);
if (d->m_progressiveOutput)
+4 -2
View File
@@ -33,6 +33,7 @@
#include "utils/environment.h"
#include <QLoggingCategory>
#include <QRegularExpression>
#include <QSettings>
namespace {
@@ -172,8 +173,9 @@ void SdkManagerOutputParser::parsePackageListing(const QString &output)
}
};
foreach (QString outputLine, output.split('\n')) {
MarkerTag marker = parseMarkers(outputLine);
QRegularExpression delimiters("[\n\r]");
foreach (QString outputLine, output.split(delimiters)) {
MarkerTag marker = parseMarkers(outputLine.trimmed());
if (marker & SectionMarkers) {
// Section marker found. Update the current section being parsed.
@@ -77,7 +77,7 @@ void GTestOutputReader::processOutput(const QByteArray &outputLine)
TestResultPtr testResult = TestResultPtr(new GTestResult(m_projectFile));
testResult->setResult(Result::MessageInternal);
testResult->setDescription(m_description);
m_futureInterface.reportResult(testResult);
reportResult(testResult);
m_description.clear();
} else if (disabledTests.exactMatch(line)) {
TestResultPtr testResult = TestResultPtr(new GTestResult(m_projectFile));
@@ -85,7 +85,7 @@ void GTestOutputReader::processOutput(const QByteArray &outputLine)
int disabled = disabledTests.cap(1).toInt();
testResult->setDescription(tr("You have %n disabled test(s).", 0, disabled));
testResult->setLine(disabled); // misuse line property to hold number of disabled
m_futureInterface.reportResult(testResult);
reportResult(testResult);
m_description.clear();
}
return;
@@ -95,7 +95,7 @@ void GTestOutputReader::processOutput(const QByteArray &outputLine)
GTestResult *testResult = createDefaultResult();
testResult->setResult(Result::MessageTestCaseEnd);
testResult->setDescription(tr("Test execution took %1").arg(testEnds.cap(2)));
m_futureInterface.reportResult(TestResultPtr(testResult));
reportResult(TestResultPtr(testResult));
m_currentTestName.clear();
m_currentTestSet.clear();
} else if (newTestStarts.exactMatch(line)) {
@@ -108,24 +108,24 @@ void GTestOutputReader::processOutput(const QByteArray &outputLine)
} else {
testResult->setDescription(tr("Executing test case %1").arg(m_currentTestName));
}
m_futureInterface.reportResult(testResult);
reportResult(testResult);
} else if (newTestSetStarts.exactMatch(line)) {
setCurrentTestSet(newTestSetStarts.cap(1));
TestResultPtr testResult = TestResultPtr(new GTestResult(m_projectFile));
testResult->setResult(Result::MessageCurrentTest);
testResult->setDescription(tr("Entering test set %1").arg(m_currentTestSet));
m_futureInterface.reportResult(testResult);
reportResult(testResult);
m_description.clear();
} else if (testSetSuccess.exactMatch(line)) {
GTestResult *testResult = createDefaultResult();
testResult->setResult(Result::Pass);
testResult->setDescription(m_description);
m_futureInterface.reportResult(TestResultPtr(testResult));
reportResult(TestResultPtr(testResult));
m_description.clear();
testResult = createDefaultResult();
testResult->setResult(Result::MessageInternal);
testResult->setDescription(tr("Execution took %1.").arg(testSetSuccess.cap(2)));
m_futureInterface.reportResult(TestResultPtr(testResult));
reportResult(TestResultPtr(testResult));
m_futureInterface.setProgressValue(m_futureInterface.progressValue() + 1);
} else if (testSetFail.exactMatch(line)) {
GTestResult *testResult = createDefaultResult();
@@ -149,12 +149,12 @@ void GTestOutputReader::processOutput(const QByteArray &outputLine)
}
}
}
m_futureInterface.reportResult(TestResultPtr(testResult));
reportResult(TestResultPtr(testResult));
m_description.clear();
testResult = createDefaultResult();
testResult->setResult(Result::MessageInternal);
testResult->setDescription(tr("Execution took %1.").arg(testSetFail.cap(2)));
m_futureInterface.reportResult(TestResultPtr(testResult));
reportResult(TestResultPtr(testResult));
m_futureInterface.setProgressValue(m_futureInterface.progressValue() + 1);
}
}
@@ -46,9 +46,9 @@ TestOutputReader *QtTestConfiguration::outputReader(const QFutureInterface<TestR
return nullptr;
if (qtSettings->useXMLOutput)
return new QtTestOutputReader(fi, app, buildDirectory(), QtTestOutputReader::XML);
return new QtTestOutputReader(fi, app, buildDirectory(), projectFile(), QtTestOutputReader::XML);
else
return new QtTestOutputReader(fi, app, buildDirectory(), QtTestOutputReader::PlainText);
return new QtTestOutputReader(fi, app, buildDirectory(), projectFile(), QtTestOutputReader::PlainText);
}
QStringList QtTestConfiguration::argumentsForTestRunner(QStringList *omitted) const
@@ -25,6 +25,7 @@
#include "qttestoutputreader.h"
#include "qttestresult.h"
#include "../testtreeitem.h"
#include <utils/qtcassert.h>
@@ -130,9 +131,10 @@ static QString constructSourceFilePath(const QString &path, const QString &fileP
QtTestOutputReader::QtTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
QProcess *testApplication, const QString &buildDirectory,
OutputMode mode)
const QString &projectFile, OutputMode mode)
: TestOutputReader(futureInterface, testApplication, buildDirectory)
, m_executable(testApplication ? testApplication->program() : QString())
, m_projectFile(projectFile)
, m_mode(mode)
{
}
@@ -269,12 +271,7 @@ void QtTestOutputReader::processXMLOutput(const QByteArray &outputLine)
} else if (currentTag == QStringLiteral("TestCase")) {
sendFinishMessage(false);
} else if (validEndTags.contains(currentTag.toString())) {
QtTestResult *testResult = createDefaultResult();
testResult->setResult(m_result);
testResult->setFileName(m_file);
testResult->setLine(m_lineNumber);
testResult->setDescription(m_description);
m_futureInterface.reportResult(TestResultPtr(testResult));
sendCompleteInformation();
if (currentTag == QStringLiteral("Incident"))
m_dataTag.clear();
}
@@ -420,7 +417,7 @@ void QtTestOutputReader::processSummaryFinishOutput()
QtTestResult *QtTestOutputReader::createDefaultResult() const
{
QtTestResult *result = new QtTestResult(m_executable, m_className);
QtTestResult *result = new QtTestResult(m_executable, m_projectFile, m_className);
result->setFunctionName(m_testCase);
result->setDataTag(m_dataTag);
return result;
@@ -430,18 +427,27 @@ void QtTestOutputReader::sendCompleteInformation()
{
TestResultPtr testResult = TestResultPtr(createDefaultResult());
testResult->setResult(m_result);
if (m_lineNumber) {
testResult->setFileName(m_file);
testResult->setLine(m_lineNumber);
} else {
const TestTreeItem *testItem = testResult->findTestTreeItem();
if (testItem && testItem->line()) {
testResult->setFileName(testItem->filePath());
testResult->setLine(static_cast<int>(testItem->line()));
}
}
testResult->setDescription(m_description);
m_futureInterface.reportResult(testResult);
reportResult(testResult);
}
void QtTestOutputReader::sendMessageCurrentTest()
{
TestResultPtr testResult = TestResultPtr(new QtTestResult);
TestResultPtr testResult = TestResultPtr(new QtTestResult(m_projectFile));
testResult->setResult(Result::MessageCurrentTest);
testResult->setDescription(tr("Entering test function %1::%2").arg(m_className, m_testCase));
m_futureInterface.reportResult(testResult);
reportResult(testResult);
}
void QtTestOutputReader::sendStartMessage(bool isFunction)
@@ -450,7 +456,12 @@ void QtTestOutputReader::sendStartMessage(bool isFunction)
testResult->setResult(Result::MessageTestCaseStart);
testResult->setDescription(isFunction ? tr("Executing test function %1").arg(m_testCase)
: tr("Executing test case %1").arg(m_className));
m_futureInterface.reportResult(testResult);
const TestTreeItem *testItem = testResult->findTestTreeItem();
if (testItem && testItem->line()) {
testResult->setFileName(testItem->filePath());
testResult->setLine(static_cast<int>(testItem->line()));
}
reportResult(testResult);
}
void QtTestOutputReader::sendFinishMessage(bool isFunction)
@@ -464,7 +475,7 @@ void QtTestOutputReader::sendFinishMessage(bool isFunction)
testResult->setDescription(isFunction ? tr("Test function finished.")
: tr("Test finished."));
}
m_futureInterface.reportResult(testResult);
reportResult(testResult);
}
// TODO factor out tr() strings to avoid duplication (see XML processing of Characters)
@@ -473,15 +484,15 @@ void QtTestOutputReader::handleAndSendConfigMessage(const QRegExp &config)
QtTestResult *testResult = createDefaultResult();
testResult->setResult(Result::MessageInternal);
testResult->setDescription(tr("Qt version: %1").arg(config.cap(3)));
m_futureInterface.reportResult(TestResultPtr(testResult));
reportResult(TestResultPtr(testResult));
testResult = createDefaultResult();
testResult->setResult(Result::MessageInternal);
testResult->setDescription(tr("Qt build: %1").arg(config.cap(2)));
m_futureInterface.reportResult(TestResultPtr(testResult));
reportResult(TestResultPtr(testResult));
testResult = createDefaultResult();
testResult->setResult(Result::MessageInternal);
testResult->setDescription(tr("QTest version: %1").arg(config.cap(1)));
m_futureInterface.reportResult(TestResultPtr(testResult));
reportResult(TestResultPtr(testResult));
}
} // namespace Internal
@@ -48,7 +48,7 @@ public:
QtTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
QProcess *testApplication, const QString &buildDirectory,
OutputMode mode);
const QString &projectFile, OutputMode mode);
protected:
void processOutput(const QByteArray &outputLine) override;
@@ -79,6 +79,7 @@ private:
CDATAMode m_cdataMode = None;
QString m_executable;
QString m_projectFile;
QString m_className;
QString m_testCase;
QString m_formerTestCase;
+84 -6
View File
@@ -24,19 +24,21 @@
****************************************************************************/
#include "qttestresult.h"
#include "../testtreemodel.h"
#include <utils/qtcassert.h>
namespace Autotest {
namespace Internal {
QtTestResult::QtTestResult(const QString &className)
: TestResult(className)
QtTestResult::QtTestResult(const QString &projectFile, const QString &className)
: TestResult(className), m_projectFile(projectFile)
{
}
QtTestResult::QtTestResult(const QString &executable, const QString &className)
: TestResult(executable, className)
QtTestResult::QtTestResult(const QString &executable, const QString &projectFile,
const QString &className)
: TestResult(executable, className), m_projectFile(projectFile)
{
}
@@ -106,20 +108,96 @@ bool QtTestResult::isIntermediateFor(const TestResult *other) const
QTC_ASSERT(other, return false);
const QtTestResult *qtOther = static_cast<const QtTestResult *>(other);
return m_dataTag == qtOther->m_dataTag && m_function == qtOther->m_function
&& name() == qtOther->name() && executable() == qtOther->executable();
&& name() == qtOther->name() && executable() == qtOther->executable()
&& m_projectFile == qtOther->m_projectFile;
}
TestResult *QtTestResult::createIntermediateResultFor(const TestResult *other)
{
QTC_ASSERT(other, return nullptr);
const QtTestResult *qtOther = static_cast<const QtTestResult *>(other);
QtTestResult *intermediate = new QtTestResult(qtOther->executable(), qtOther->name());
QtTestResult *intermediate = new QtTestResult(qtOther->executable(), qtOther->m_projectFile, qtOther->name());
intermediate->m_function = qtOther->m_function;
intermediate->m_dataTag = qtOther->m_dataTag;
// intermediates will be needed only for data tags
intermediate->setDescription("Data tag: " + qtOther->m_dataTag);
const auto correspondingItem = intermediate->findTestTreeItem();
if (correspondingItem && correspondingItem->line()) {
intermediate->setFileName(correspondingItem->filePath());
intermediate->setLine(static_cast<int>(correspondingItem->line()));
}
return intermediate;
}
const TestTreeItem *QtTestResult::findTestTreeItem() const
{
const auto item = TestTreeModel::instance()->findNonRootItem([this](const Utils::TreeItem *item) {
const TestTreeItem *treeItem = static_cast<const TestTreeItem *>(item);
return matches(treeItem);
});
return static_cast<const TestTreeItem *>(item);
}
bool QtTestResult::matches(const TestTreeItem *item) const
{
QTC_ASSERT(item, return false);
TestTreeItem *parentItem = item->parentItem();
QTC_ASSERT(parentItem, return false);
TestTreeItem::Type type = item->type();
switch (type) {
case TestTreeItem::TestCase:
if (!isTestCase())
return false;
if (item->proFile() != m_projectFile)
return false;
return matchesTestCase(item);
case TestTreeItem::TestFunctionOrSet:
case TestTreeItem::TestSpecialFunction:
if (!isTestFunction())
return false;
if (parentItem->proFile() != m_projectFile)
return false;
return matchesTestFunction(item);
case TestTreeItem::TestDataTag: {
if (!isDataTag())
return false;
TestTreeItem *grandParentItem = parentItem->parentItem();
QTC_ASSERT(grandParentItem, return false);
if (grandParentItem->proFile() != m_projectFile)
return false;
return matchesTestFunction(item);
}
default:
break;
}
return false;
}
bool QtTestResult::matchesTestCase(const TestTreeItem *item) const
{
// FIXME this will never work for Quick Tests
if (item->name() == name())
return true;
return false;
}
bool QtTestResult::matchesTestFunction(const TestTreeItem *item) const
{
TestTreeItem *parentItem = item->parentItem();
TestTreeItem::Type type = item->type();
if (m_function.contains("::")) { // Quick tests have slightly different layout // BAD/WRONG!
const QStringList tmp = m_function.split("::");
QTC_ASSERT(tmp.size() == 2, return false);
return item->name() == tmp.last() && parentItem->name() == tmp.first();
}
if (type == TestTreeItem::TestDataTag) {
TestTreeItem *grandParentItem = parentItem->parentItem();
return parentItem->name() == m_function && grandParentItem->name() == name();
}
return item->name() == m_function && parentItem->name() == name();
}
} // namespace Internal
} // namespace Autotest
+8 -2
View File
@@ -33,8 +33,8 @@ namespace Internal {
class QtTestResult : public TestResult
{
public:
explicit QtTestResult(const QString &className = QString());
QtTestResult(const QString &executable, const QString &className);
explicit QtTestResult(const QString &projectFile, const QString &className = QString());
QtTestResult(const QString &executable, const QString &projectFile, const QString &className);
const QString outputString(bool selected) const override;
void setFunctionName(const QString &functionName) { m_function = functionName; }
@@ -43,13 +43,19 @@ public:
bool isDirectParentOf(const TestResult *other, bool *needsIntermediate) const override;
bool isIntermediateFor(const TestResult *other) const override;
TestResult *createIntermediateResultFor(const TestResult *other) override;
const TestTreeItem *findTestTreeItem() const override;
private:
bool isTestCase() const { return m_function.isEmpty() && m_dataTag.isEmpty(); }
bool isTestFunction() const { return !m_function.isEmpty() && m_dataTag.isEmpty(); }
bool isDataTag() const { return !m_function.isEmpty() && !m_dataTag.isEmpty(); }
bool matches(const TestTreeItem *item) const;
bool matchesTestCase(const TestTreeItem *item) const;
bool matchesTestFunction(const TestTreeItem *item) const;
QString m_function;
QString m_dataTag;
QString m_projectFile;
};
} // namespace Internal
@@ -45,9 +45,9 @@ TestOutputReader *QuickTestConfiguration::outputReader(const QFutureInterface<Te
if (qtSettings.isNull())
return nullptr;
if (qtSettings->useXMLOutput)
return new QtTestOutputReader(fi, app, buildDirectory(), QtTestOutputReader::XML);
return new QtTestOutputReader(fi, app, buildDirectory(), projectFile(), QtTestOutputReader::XML);
else
return new QtTestOutputReader(fi, app, buildDirectory(), QtTestOutputReader::PlainText);
return new QtTestOutputReader(fi, app, buildDirectory(), projectFile(), QtTestOutputReader::PlainText);
}
QStringList QuickTestConfiguration::argumentsForTestRunner(QStringList *omitted) const
@@ -76,6 +76,10 @@ void TestConfiguration::completeTestInformation(ProjectExplorer::RunConfiguratio
TestRunMode runMode)
{
QTC_ASSERT(rc, return);
if (hasExecutable()) {
qCDebug(LOG) << "Executable has been set already - not completing configuration again.";
return;
}
Project *project = SessionManager::startupProject();
if (!project)
return;
@@ -66,5 +66,11 @@ void TestOutputReader::processStdError(const QByteArray &output)
qWarning() << "AutoTest.Run: Ignored plain output:" << output;
}
void TestOutputReader::reportResult(const TestResultPtr &result)
{
m_futureInterface.reportResult(result);
m_hadValidOutput = true;
}
} // namespace Internal
} // namespace Autotest
+4
View File
@@ -44,13 +44,17 @@ public:
virtual void processOutput(const QByteArray &outputLine) = 0;
virtual void processStdError(const QByteArray &output);
bool hadValidOutput() const { return m_hadValidOutput; }
signals:
void newOutputAvailable(const QByteArray &output);
protected:
void reportResult(const TestResultPtr &result);
QFutureInterface<TestResultPtr> m_futureInterface;
QProcess *m_testApplication; // not owned
QString m_buildDir;
private:
bool m_hadValidOutput = false;
};
} // namespace Internal
+3 -2
View File
@@ -583,15 +583,16 @@ void TestResultsPane::onCustomContextMenuRequested(const QPoint &pos)
connect(action, &QAction::triggered, this, &TestResultsPane::onSaveWholeTriggered);
menu.addAction(action);
const auto correlatingItem = clicked ? clicked->findTestTreeItem() : nullptr;
action = new QAction(tr("Run This Test"), &menu);
action->setEnabled(clicked && clicked->findTestTreeItem());
action->setEnabled(correlatingItem && correlatingItem->canProvideTestConfiguration());
connect(action, &QAction::triggered, this, [this, clicked] {
onRunThisTestTriggered(TestRunMode::Run, clicked);
});
menu.addAction(action);
action = new QAction(tr("Debug This Test"), &menu);
action->setEnabled(clicked && clicked->findTestTreeItem());
action->setEnabled(correlatingItem && correlatingItem->canProvideDebugConfiguration());
connect(action, &QAction::triggered, this, [this, clicked] {
onRunThisTestTriggered(TestRunMode::Debug, clicked);
});
+19 -2
View File
@@ -257,6 +257,11 @@ static void performTestRun(QFutureInterface<TestResultPtr> &futureInterface,
TestRunner::tr("Test for project \"%1\" crashed.")
.arg(testConfiguration->displayName()) + processInformation(testProcess)
+ rcInfo(testConfiguration))));
} else if (!outputReader->hadValidOutput()) {
futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
TestRunner::tr("Test for project \"%1\" did not produce any expected output.")
.arg(testConfiguration->displayName()) + processInformation(testProcess)
+ rcInfo(testConfiguration))));
}
if (canceledByTimeout) {
@@ -362,12 +367,24 @@ static bool askUserForRunConfiguration(TestConfiguration *config)
void TestRunner::runTests()
{
QList<TestConfiguration *> toBeRemoved;
for (TestConfiguration *config : m_selectedTests) {
config->completeTestInformation(TestRunMode::Run);
if (!config->hasExecutable())
if (askUserForRunConfiguration(config))
config->completeTestInformation(config->originalRunConfiguration(), TestRunMode::Run);
if (!askUserForRunConfiguration(config))
toBeRemoved.append(config);
}
for (TestConfiguration *config : toBeRemoved)
m_selectedTests.removeOne(config);
qDeleteAll(toBeRemoved);
toBeRemoved.clear();
if (m_selectedTests.isEmpty()) {
emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageWarn,
tr("No test cases left for execution. Canceling test run."))));
onFinished();
return;
}
QFuture<TestResultPtr> future = Utils::runAsync(&performTestRun, m_selectedTests,
*AutotestPlugin::instance()->settings());
m_futureWatcher.setFuture(future);
@@ -112,17 +112,15 @@ QString BareMetalRunConfiguration::defaultDisplayName()
{
if (!m_projectFilePath.isEmpty())
//: %1 is the name of the project run via hardware debugger
return tr("%1 (via GDB server or hardware debugger)").arg(QFileInfo(m_projectFilePath).completeBaseName());
return tr("%1 (via GDB server or hardware debugger)").arg(QFileInfo(m_projectFilePath).fileName());
//: Bare Metal run configuration default run name
return tr("Run on GDB server or hardware debugger");
}
QString BareMetalRunConfiguration::localExecutableFilePath() const
{
const QString targetName = QFileInfo(m_projectFilePath).completeBaseName();
return target()->applicationTargets()
.targetFilePath(FileName::fromString(targetName).toString()).toString();
const QString targetName = QFileInfo(m_projectFilePath).fileName();
return target()->applicationTargets().targetFilePath(targetName).toString();
}
QString BareMetalRunConfiguration::arguments() const
@@ -149,7 +147,7 @@ QString BareMetalRunConfiguration::buildSystemTarget() const
{
const BuildTargetInfoList targets = target()->applicationTargets();
const Utils::FileName projectFilePath = Utils::FileName::fromString(QFileInfo(m_projectFilePath).path());
const QString targetName = QFileInfo(m_projectFilePath).completeBaseName();
const QString targetName = QFileInfo(m_projectFilePath).fileName();
auto bst = std::find_if(targets.list.constBegin(), targets.list.constEnd(),
[&projectFilePath,&targetName](const BuildTargetInfo &bti) { return bti.projectFilePath == projectFilePath && bti.targetName == targetName; });
return (bst == targets.list.constEnd()) ? QString() : bst->targetName;
@@ -60,7 +60,7 @@ bool BareMetalRunConfigurationFactory::canCreate(Target *parent, Core::Id id) co
{
if (!canHandle(parent))
return false;
const QString targetName = QFileInfo(pathFromId(id)).completeBaseName();
const QString targetName = QFileInfo(pathFromId(id)).fileName();
return id == BareMetalCustomRunConfiguration::runConfigId()
|| !parent->applicationTargets().targetFilePath(targetName).isEmpty();
}
@@ -100,7 +100,7 @@ QString BareMetalRunConfigurationFactory::displayNameForId(Core::Id id) const
if (id == BareMetalCustomRunConfiguration::runConfigId())
return BareMetalCustomRunConfiguration::runConfigDefaultDisplayName();
return tr("%1 (on GDB server or hardware debugger)")
.arg(QFileInfo(pathFromId(id)).completeBaseName());
.arg(QFileInfo(pathFromId(id)).fileName());
}
RunConfiguration *BareMetalRunConfigurationFactory::doCreate(Target *parent, Core::Id id)
@@ -0,0 +1,581 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangbackendcommunicator.h"
#include "clangbackendlogging.h"
#include "clangcompletionassistprocessor.h"
#include "clangmodelmanagersupport.h"
#include "clangutils.h"
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h>
#include <cpptools/abstracteditorsupport.h>
#include <cpptools/baseeditordocumentprocessor.h>
#include <cpptools/cppmodelmanager.h>
#include <cpptools/editordocumenthandle.h>
#include <cpptools/projectinfo.h>
#include <cpptools/cpptoolsbridge.h>
#include <texteditor/codeassist/functionhintproposal.h>
#include <texteditor/codeassist/iassistprocessor.h>
#include <texteditor/texteditor.h>
#include <clangsupport/filecontainer.h>
#include <clangsupport/clangcodemodelservermessages.h>
#include <utils/qtcassert.h>
#include <QDateTime>
#include <QDir>
#include <QTextBlock>
using namespace CPlusPlus;
using namespace ClangBackEnd;
using namespace TextEditor;
enum { backEndStartTimeOutInMs = 10000 };
static QString backendProcessPath()
{
return Core::ICore::libexecPath()
+ QStringLiteral("/clangbackend")
+ QStringLiteral(QTC_HOST_EXE_SUFFIX);
}
namespace ClangCodeModel {
namespace Internal {
class DummyBackendSender : public BackendSender
{
public:
DummyBackendSender() : BackendSender(nullptr) {}
void end() override {}
void registerTranslationUnitsForEditor(const RegisterTranslationUnitForEditorMessage &) override {}
void updateTranslationUnitsForEditor(const UpdateTranslationUnitsForEditorMessage &) override {}
void unregisterTranslationUnitsForEditor(const UnregisterTranslationUnitsForEditorMessage &) override {}
void registerProjectPartsForEditor(const RegisterProjectPartsForEditorMessage &) override {}
void unregisterProjectPartsForEditor(const UnregisterProjectPartsForEditorMessage &) override {}
void registerUnsavedFilesForEditor(const RegisterUnsavedFilesForEditorMessage &) override {}
void unregisterUnsavedFilesForEditor(const UnregisterUnsavedFilesForEditorMessage &) override {}
void completeCode(const CompleteCodeMessage &) override {}
void requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &) override {}
void requestReferences(const RequestReferencesMessage &) override {}
void requestFollowSymbol(const RequestFollowSymbolMessage &) override {}
void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &) override {}
};
BackendCommunicator::BackendCommunicator()
: m_connection(&m_receiver)
, m_sender(new DummyBackendSender())
{
m_backendStartTimeOut.setSingleShot(true);
connect(&m_backendStartTimeOut, &QTimer::timeout,
this, &BackendCommunicator::logStartTimeOut);
m_receiver.setAliveHandler([this]() { m_connection.resetProcessAliveTimer(); });
connect(Core::EditorManager::instance(), &Core::EditorManager::editorAboutToClose,
this, &BackendCommunicator::onEditorAboutToClose);
connect(Core::ICore::instance(), &Core::ICore::coreAboutToClose,
this, &BackendCommunicator::setupDummySender);
initializeBackend();
}
BackendCommunicator::~BackendCommunicator()
{
disconnect(&m_connection, 0, this, 0);
}
void BackendCommunicator::initializeBackend()
{
const QString clangBackEndProcessPath = backendProcessPath();
if (!QFileInfo(clangBackEndProcessPath).exists()) {
logExecutableDoesNotExist();
return;
}
qCDebug(ipcLog) << "Starting" << clangBackEndProcessPath;
m_connection.setProcessAliveTimerInterval(30 * 1000);
m_connection.setProcessPath(clangBackEndProcessPath);
connect(&m_connection, &ConnectionClient::connectedToLocalSocket,
this, &BackendCommunicator::onConnectedToBackend);
connect(&m_connection, &ConnectionClient::disconnectedFromLocalSocket,
this, &BackendCommunicator::setupDummySender);
m_connection.startProcessAndConnectToServerAsynchronously();
m_backendStartTimeOut.start(backEndStartTimeOutInMs);
}
static QStringList projectPartOptions(const CppTools::ProjectPart::Ptr &projectPart)
{
const QStringList options = ClangCodeModel::Utils::createClangOptions(projectPart,
CppTools::ProjectFile::Unsupported); // No language option
return options;
}
static ProjectPartContainer toProjectPartContainer(
const CppTools::ProjectPart::Ptr &projectPart)
{
const QStringList options = projectPartOptions(projectPart);
return ProjectPartContainer(projectPart->id(), Utf8StringVector(options));
}
static QVector<ProjectPartContainer> toProjectPartContainers(
const QVector<CppTools::ProjectPart::Ptr> projectParts)
{
QVector<ProjectPartContainer> projectPartContainers;
projectPartContainers.reserve(projectParts.size());
foreach (const CppTools::ProjectPart::Ptr &projectPart, projectParts)
projectPartContainers << toProjectPartContainer(projectPart);
return projectPartContainers;
}
void BackendCommunicator::registerFallbackProjectPart()
{
const auto projectPart = CppTools::CppModelManager::instance()->fallbackProjectPart();
const auto projectPartContainer = toProjectPartContainer(projectPart);
registerProjectPartsForEditor({projectPartContainer});
}
namespace {
Utf8String currentCppEditorDocumentFilePath()
{
Utf8String currentCppEditorDocumentFilePath;
const auto currentEditor = Core::EditorManager::currentEditor();
if (currentEditor && CppTools::CppModelManager::isCppEditor(currentEditor)) {
const auto currentDocument = currentEditor->document();
if (currentDocument)
currentCppEditorDocumentFilePath = currentDocument->filePath().toString();
}
return currentCppEditorDocumentFilePath;
}
void removeDuplicates(Utf8StringVector &visibleEditorDocumentsFilePaths)
{
std::sort(visibleEditorDocumentsFilePaths.begin(),
visibleEditorDocumentsFilePaths.end());
const auto end = std::unique(visibleEditorDocumentsFilePaths.begin(),
visibleEditorDocumentsFilePaths.end());
visibleEditorDocumentsFilePaths.erase(end,
visibleEditorDocumentsFilePaths.end());
}
void removeNonCppEditors(QList<Core::IEditor*> &visibleEditors)
{
const auto isNotCppEditor = [] (Core::IEditor *editor) {
return !CppTools::CppModelManager::isCppEditor(editor);
};
const auto end = std::remove_if(visibleEditors.begin(),
visibleEditors.end(),
isNotCppEditor);
visibleEditors.erase(end, visibleEditors.end());
}
Utf8StringVector visibleCppEditorDocumentsFilePaths()
{
auto visibleEditors = CppTools::CppToolsBridge::visibleEditors();
removeNonCppEditors(visibleEditors);
Utf8StringVector visibleCppEditorDocumentsFilePaths;
visibleCppEditorDocumentsFilePaths.reserve(visibleEditors.size());
const auto editorFilePaths = [] (Core::IEditor *editor) {
return Utf8String(editor->document()->filePath().toString());
};
std::transform(visibleEditors.begin(),
visibleEditors.end(),
std::back_inserter(visibleCppEditorDocumentsFilePaths),
editorFilePaths);
removeDuplicates(visibleCppEditorDocumentsFilePaths);
return visibleCppEditorDocumentsFilePaths;
}
}
void BackendCommunicator::updateTranslationUnitVisiblity()
{
updateTranslationUnitVisiblity(currentCppEditorDocumentFilePath(), visibleCppEditorDocumentsFilePaths());
}
bool BackendCommunicator::isNotWaitingForCompletion() const
{
return !m_receiver.isExpectingCodeCompletedMessage();
}
void BackendCommunicator::updateTranslationUnitVisiblity(const Utf8String &currentEditorFilePath,
const Utf8StringVector &visibleEditorsFilePaths)
{
const UpdateVisibleTranslationUnitsMessage message(currentEditorFilePath, visibleEditorsFilePaths);
m_sender->updateVisibleTranslationUnits(message);
}
void BackendCommunicator::registerCurrentProjectParts()
{
using namespace CppTools;
const QList<ProjectInfo> projectInfos = CppModelManager::instance()->projectInfos();
foreach (const ProjectInfo &projectInfo, projectInfos)
registerProjectsParts(projectInfo.projectParts());
}
void BackendCommunicator::restoreCppEditorDocuments()
{
resetCppEditorDocumentProcessors();
registerVisibleCppEditorDocumentAndMarkInvisibleDirty();
}
void BackendCommunicator::resetCppEditorDocumentProcessors()
{
using namespace CppTools;
const auto cppEditorDocuments = CppModelManager::instance()->cppEditorDocuments();
foreach (CppEditorDocumentHandle *cppEditorDocument, cppEditorDocuments)
cppEditorDocument->resetProcessor();
}
void BackendCommunicator::registerVisibleCppEditorDocumentAndMarkInvisibleDirty()
{
CppTools::CppModelManager::instance()->updateCppEditorDocuments();
}
void BackendCommunicator::registerCurrentCodeModelUiHeaders()
{
using namespace CppTools;
const auto editorSupports = CppModelManager::instance()->abstractEditorSupports();
foreach (const AbstractEditorSupport *es, editorSupports) {
const QString mappedPath
= ModelManagerSupportClang::instance()->dummyUiHeaderOnDiskPath(es->fileName());
updateUnsavedFile(mappedPath, es->contents(), es->revision());
}
}
void BackendCommunicator::registerProjectsParts(const QVector<CppTools::ProjectPart::Ptr> projectParts)
{
const auto projectPartContainers = toProjectPartContainers(projectParts);
registerProjectPartsForEditor(projectPartContainers);
}
void BackendCommunicator::updateTranslationUnitFromCppEditorDocument(const QString &filePath)
{
const CppTools::CppEditorDocumentHandle *document = ClangCodeModel::Utils::cppDocument(filePath);
updateTranslationUnit(filePath, document->contents(), document->revision());
}
void BackendCommunicator::updateUnsavedFileFromCppEditorDocument(const QString &filePath)
{
const CppTools::CppEditorDocumentHandle *document = ClangCodeModel::Utils::cppDocument(filePath);
updateUnsavedFile(filePath, document->contents(), document->revision());
}
void BackendCommunicator::updateTranslationUnit(const QString &filePath,
const QByteArray &contents,
uint documentRevision)
{
const bool hasUnsavedContent = true;
updateTranslationUnitsForEditor({{filePath,
Utf8String(),
Utf8String::fromByteArray(contents),
hasUnsavedContent,
documentRevision}});
}
void BackendCommunicator::updateUnsavedFile(const QString &filePath, const QByteArray &contents, uint documentRevision)
{
const bool hasUnsavedContent = true;
// TODO: Send new only if changed
registerUnsavedFilesForEditor({{filePath,
Utf8String(),
Utf8String::fromByteArray(contents),
hasUnsavedContent,
documentRevision}});
}
static bool documentHasChanged(const QString &filePath, uint revision)
{
if (CppTools::CppEditorDocumentHandle *document = ClangCodeModel::Utils::cppDocument(filePath))
return document->sendTracker().shouldSendRevision(revision);
return true;
}
static void setLastSentDocumentRevision(const QString &filePath, uint revision)
{
if (CppTools::CppEditorDocumentHandle *document = ClangCodeModel::Utils::cppDocument(filePath))
document->sendTracker().setLastSentRevision(int(revision));
}
void BackendCommunicator::updateTranslationUnitWithRevisionCheck(const FileContainer &fileContainer)
{
if (documentHasChanged(fileContainer.filePath(), fileContainer.documentRevision())) {
updateTranslationUnitsForEditor({fileContainer});
setLastSentDocumentRevision(fileContainer.filePath(),
fileContainer.documentRevision());
}
}
void BackendCommunicator::requestDocumentAnnotations(const FileContainer &fileContainer)
{
const RequestDocumentAnnotationsMessage message(fileContainer);
m_sender->requestDocumentAnnotations(message);
}
QFuture<CppTools::CursorInfo> BackendCommunicator::requestReferences(
const FileContainer &fileContainer,
quint32 line,
quint32 column,
QTextDocument *textDocument,
const CppTools::SemanticInfo::LocalUseMap &localUses)
{
const RequestReferencesMessage message(fileContainer, line, column);
m_sender->requestReferences(message);
return m_receiver.addExpectedReferencesMessage(message.ticketNumber(), textDocument,
localUses);
}
QFuture<CppTools::SymbolInfo> BackendCommunicator::requestFollowSymbol(
const FileContainer &curFileContainer,
const QVector<Utf8String> &dependentFiles,
quint32 line,
quint32 column)
{
const RequestFollowSymbolMessage message(curFileContainer,
dependentFiles,
line,
column);
m_sender->requestFollowSymbol(message);
return m_receiver.addExpectedRequestFollowSymbolMessage(message.ticketNumber());
}
void BackendCommunicator::updateTranslationUnitWithRevisionCheck(Core::IDocument *document)
{
const auto textDocument = qobject_cast<TextDocument*>(document);
const auto filePath = textDocument->filePath().toString();
const QString projectPartId = CppTools::CppToolsBridge::projectPartIdForFile(filePath);
updateTranslationUnitWithRevisionCheck(FileContainer(filePath,
projectPartId,
Utf8StringVector(),
textDocument->document()->revision()));
}
void BackendCommunicator::updateChangeContentStartPosition(const QString &filePath, int position)
{
if (CppTools::CppEditorDocumentHandle *document = ClangCodeModel::Utils::cppDocument(filePath))
document->sendTracker().applyContentChange(position);
}
void BackendCommunicator::updateTranslationUnitIfNotCurrentDocument(Core::IDocument *document)
{
QTC_ASSERT(document, return);
if (Core::EditorManager::currentDocument() != document)
updateTranslationUnit(document);
}
void BackendCommunicator::updateTranslationUnit(Core::IDocument *document)
{
updateTranslationUnitFromCppEditorDocument(document->filePath().toString());
}
void BackendCommunicator::updateUnsavedFile(Core::IDocument *document)
{
QTC_ASSERT(document, return);
updateUnsavedFileFromCppEditorDocument(document->filePath().toString());
}
void BackendCommunicator::onConnectedToBackend()
{
m_backendStartTimeOut.stop();
++m_connectedCount;
if (m_connectedCount > 1)
logRestartedDueToUnexpectedFinish();
m_receiver.reset();
m_sender.reset(new BackendSender(&m_connection));
initializeBackendWithCurrentData();
}
void BackendCommunicator::onEditorAboutToClose(Core::IEditor *editor)
{
if (auto *textEditor = qobject_cast<TextEditor::BaseTextEditor *>(editor))
m_receiver.deleteProcessorsOfEditorWidget(textEditor->editorWidget());
}
void BackendCommunicator::setupDummySender()
{
m_sender.reset(new DummyBackendSender);
}
void BackendCommunicator::logExecutableDoesNotExist()
{
const QString msg
= tr("Clang Code Model: Error: "
"The clangbackend executable \"%1\" does not exist.")
.arg(QDir::toNativeSeparators(backendProcessPath()));
logError(msg);
}
void BackendCommunicator::logStartTimeOut()
{
const QString msg
= tr("Clang Code Model: Error: "
"The clangbackend executable \"%1\" could not be started (timeout after %2ms).")
.arg(QDir::toNativeSeparators(backendProcessPath()))
.arg(backEndStartTimeOutInMs);
logError(msg);
}
void BackendCommunicator::logRestartedDueToUnexpectedFinish()
{
const QString msg
= tr("Clang Code Model: Error: "
"The clangbackend process has finished unexpectedly and was restarted.");
logError(msg);
}
void BackendCommunicator::logError(const QString &text)
{
const QString textWithTimestamp = QDateTime::currentDateTime().toString(Qt::ISODate)
+ ' ' + text;
Core::MessageManager::write(textWithTimestamp, Core::MessageManager::Flash);
qWarning("%s", qPrintable(textWithTimestamp));
}
void BackendCommunicator::initializeBackendWithCurrentData()
{
registerFallbackProjectPart();
registerCurrentProjectParts();
registerCurrentCodeModelUiHeaders();
restoreCppEditorDocuments();
updateTranslationUnitVisiblity();
emit backendReinitialized();
}
BackendSender *BackendCommunicator::setBackendSender(BackendSender *sender)
{
BackendSender *previousSender = m_sender.take();
m_sender.reset(sender);
return previousSender;
}
void BackendCommunicator::killBackendProcess()
{
m_connection.processForTestOnly()->kill();
}
void BackendCommunicator::registerTranslationUnitsForEditor(const FileContainers &fileContainers)
{
const RegisterTranslationUnitForEditorMessage message(fileContainers,
currentCppEditorDocumentFilePath(),
visibleCppEditorDocumentsFilePaths());
m_sender->registerTranslationUnitsForEditor(message);
}
void BackendCommunicator::updateTranslationUnitsForEditor(const FileContainers &fileContainers)
{
const UpdateTranslationUnitsForEditorMessage message(fileContainers);
m_sender->updateTranslationUnitsForEditor(message);
}
void BackendCommunicator::unregisterTranslationUnitsForEditor(const FileContainers &fileContainers)
{
const UnregisterTranslationUnitsForEditorMessage message(fileContainers);
m_sender->unregisterTranslationUnitsForEditor(message);
}
void BackendCommunicator::registerProjectPartsForEditor(
const ProjectPartContainers &projectPartContainers)
{
const RegisterProjectPartsForEditorMessage message(projectPartContainers);
m_sender->registerProjectPartsForEditor(message);
}
void BackendCommunicator::unregisterProjectPartsForEditor(const QStringList &projectPartIds)
{
const UnregisterProjectPartsForEditorMessage message((Utf8StringVector(projectPartIds)));
m_sender->unregisterProjectPartsForEditor(message);
}
void BackendCommunicator::registerUnsavedFilesForEditor(const FileContainers &fileContainers)
{
const RegisterUnsavedFilesForEditorMessage message(fileContainers);
m_sender->registerUnsavedFilesForEditor(message);
}
void BackendCommunicator::unregisterUnsavedFilesForEditor(const FileContainers &fileContainers)
{
const UnregisterUnsavedFilesForEditorMessage message(fileContainers);
m_sender->unregisterUnsavedFilesForEditor(message);
}
void BackendCommunicator::completeCode(ClangCompletionAssistProcessor *assistProcessor,
const QString &filePath,
quint32 line,
quint32 column,
const QString &projectFilePath,
qint32 funcNameStartLine,
qint32 funcNameStartColumn)
{
const CompleteCodeMessage message(filePath, line, column, projectFilePath, funcNameStartLine,
funcNameStartColumn);
m_sender->completeCode(message);
m_receiver.addExpectedCodeCompletedMessage(message.ticketNumber(), assistProcessor);
}
} // namespace Internal
} // namespace ClangCodeModel
@@ -25,135 +25,42 @@
#pragma once
#include "clangbackendreceiver.h"
#include "clangbackendsender.h"
#include <cpptools/projectpart.h>
#include <cpptools/cppcursorinfo.h>
#include <cpptools/cppsymbolinfo.h>
#include <clangsupport/clangcodemodelconnectionclient.h>
#include <clangsupport/filecontainer.h>
#include <clangsupport/clangcodemodelclientinterface.h>
#include <clangsupport/projectpartcontainer.h>
#include <QFuture>
#include <QObject>
#include <QPointer>
#include <QSharedPointer>
#include <QTextDocument>
#include <QVector>
#include <functional>
#include <QTimer>
namespace Core {
class IEditor;
class IDocument;
}
namespace ClangBackEnd {
class DocumentAnnotationsChangedMessage;
}
namespace TextEditor {
class TextEditorWidget;
class TextDocument;
}
namespace ClangCodeModel {
namespace Internal {
class ModelManagerSupportClang;
class ClangCompletionAssistProcessor;
class IpcReceiver : public ClangBackEnd::ClangCodeModelClientInterface
{
public:
IpcReceiver();
~IpcReceiver();
using AliveHandler = std::function<void ()>;
void setAliveHandler(const AliveHandler &handler);
void addExpectedCodeCompletedMessage(quint64 ticket, ClangCompletionAssistProcessor *processor);
void deleteProcessorsOfEditorWidget(TextEditor::TextEditorWidget *textEditorWidget);
QFuture<CppTools::CursorInfo>
addExpectedReferencesMessage(quint64 ticket,
QTextDocument *textDocument,
const CppTools::SemanticInfo::LocalUseMap &localUses);
QFuture<CppTools::SymbolInfo> addExpectedRequestFollowSymbolMessage(quint64 ticket);
bool isExpectingCodeCompletedMessage() const;
void reset();
private:
void alive() override;
void echo(const ClangBackEnd::EchoMessage &message) override;
void codeCompleted(const ClangBackEnd::CodeCompletedMessage &message) override;
void documentAnnotationsChanged(const ClangBackEnd::DocumentAnnotationsChangedMessage &message) override;
void references(const ClangBackEnd::ReferencesMessage &message) override;
void followSymbol(const ClangBackEnd::FollowSymbolMessage &message) override;
private:
AliveHandler m_aliveHandler;
QHash<quint64, ClangCompletionAssistProcessor *> m_assistProcessorsTable;
struct ReferencesEntry {
ReferencesEntry() = default;
ReferencesEntry(QFutureInterface<CppTools::CursorInfo> futureInterface,
QTextDocument *textDocument,
const CppTools::SemanticInfo::LocalUseMap &localUses)
: futureInterface(futureInterface)
, textDocument(textDocument)
, localUses(localUses) {}
QFutureInterface<CppTools::CursorInfo> futureInterface;
QPointer<QTextDocument> textDocument;
CppTools::SemanticInfo::LocalUseMap localUses;
};
QHash<quint64, ReferencesEntry> m_referencesTable;
QHash<quint64, QFutureInterface<CppTools::SymbolInfo>> m_followTable;
};
class IpcSender : public ClangBackEnd::ClangCodeModelServerInterface
{
public:
IpcSender(ClangBackEnd::ClangCodeModelConnectionClient *connectionClient);
void end() override;
void registerTranslationUnitsForEditor(const ClangBackEnd::RegisterTranslationUnitForEditorMessage &message) override;
void updateTranslationUnitsForEditor(const ClangBackEnd::UpdateTranslationUnitsForEditorMessage &message) override;
void unregisterTranslationUnitsForEditor(const ClangBackEnd::UnregisterTranslationUnitsForEditorMessage &message) override;
void registerProjectPartsForEditor(const ClangBackEnd::RegisterProjectPartsForEditorMessage &message) override;
void unregisterProjectPartsForEditor(const ClangBackEnd::UnregisterProjectPartsForEditorMessage &message) override;
void registerUnsavedFilesForEditor(const ClangBackEnd::RegisterUnsavedFilesForEditorMessage &message) override;
void unregisterUnsavedFilesForEditor(const ClangBackEnd::UnregisterUnsavedFilesForEditorMessage &message) override;
void completeCode(const ClangBackEnd::CompleteCodeMessage &message) override;
void requestDocumentAnnotations(const ClangBackEnd::RequestDocumentAnnotationsMessage &message) override;
void requestReferences(const ClangBackEnd::RequestReferencesMessage &message) override;
void requestFollowSymbol(const ClangBackEnd::RequestFollowSymbolMessage &message) override;
void updateVisibleTranslationUnits(const ClangBackEnd::UpdateVisibleTranslationUnitsMessage &message) override;
private:
bool isConnected() const;
private:
ClangBackEnd::ClangCodeModelConnectionClient *m_connection = nullptr;
};
class IpcCommunicator : public QObject
class BackendCommunicator : public QObject
{
Q_OBJECT
public:
using Ptr = QSharedPointer<IpcCommunicator>;
using FileContainer = ClangBackEnd::FileContainer;
using FileContainers = QVector<ClangBackEnd::FileContainer>;
using ProjectPartContainers = QVector<ClangBackEnd::ProjectPartContainer>;
public:
IpcCommunicator();
~IpcCommunicator();
BackendCommunicator();
~BackendCommunicator();
void registerTranslationUnitsForEditor(const FileContainers &fileContainers);
void updateTranslationUnitsForEditor(const FileContainers &fileContainers);
@@ -199,7 +106,7 @@ public:
bool isNotWaitingForCompletion() const;
public: // for tests
IpcSender *setIpcSender(IpcSender *ipcSender);
BackendSender *setBackendSender(BackendSender *sender);
void killBackendProcess();
signals: // for tests
@@ -229,10 +136,10 @@ private:
const Utf8StringVector &visibleEditorsFilePaths);
private:
IpcReceiver m_ipcReceiver;
BackendReceiver m_receiver;
ClangBackEnd::ClangCodeModelConnectionClient m_connection;
QTimer m_backendStartTimeOut;
QScopedPointer<IpcSender> m_ipcSender;
QScopedPointer<BackendSender> m_sender;
int m_connectedCount = 0;
};
@@ -1,927 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangbackendipcintegration.h"
#include "clangcompletionassistprocessor.h"
#include "clangeditordocumentprocessor.h"
#include "clangmodelmanagersupport.h"
#include "clangutils.h"
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h>
#include <cpptools/abstracteditorsupport.h>
#include <cpptools/baseeditordocumentprocessor.h>
#include <cpptools/cppmodelmanager.h>
#include <cpptools/cpptoolsbridge.h>
#include <cpptools/editordocumenthandle.h>
#include <cpptools/projectinfo.h>
#include <texteditor/codeassist/functionhintproposal.h>
#include <texteditor/codeassist/iassistprocessor.h>
#include <texteditor/texteditor.h>
#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <clangsupport/clangcodemodelservermessages.h>
#include <clangsupport/clangcodemodelclientmessages.h>
#include <clangsupport/filecontainer.h>
#include <cplusplus/Icons.h>
#include <QDateTime>
#include <QDir>
#include <QElapsedTimer>
#include <QLoggingCategory>
#include <QProcess>
#include <QTextBlock>
static Q_LOGGING_CATEGORY(log, "qtc.clangcodemodel.ipc")
using namespace CPlusPlus;
using namespace ClangCodeModel;
using namespace ClangCodeModel::Internal;
using namespace ClangBackEnd;
using namespace TextEditor;
static QString backendProcessPath()
{
return Core::ICore::libexecPath()
+ QStringLiteral("/clangbackend")
+ QStringLiteral(QTC_HOST_EXE_SUFFIX);
}
static bool printAliveMessageHelper()
{
const bool print = qEnvironmentVariableIntValue("QTC_CLANG_FORCE_VERBOSE_ALIVE");
if (!print) {
qCDebug(log) << "Hint: AliveMessage will not be printed. "
"Force it by setting QTC_CLANG_FORCE_VERBOSE_ALIVE=1.";
}
return print;
}
static bool printAliveMessage()
{
static bool print = log().isDebugEnabled() ? printAliveMessageHelper() : false;
return print;
}
IpcReceiver::IpcReceiver()
{
}
IpcReceiver::~IpcReceiver()
{
reset();
}
void IpcReceiver::setAliveHandler(const IpcReceiver::AliveHandler &handler)
{
m_aliveHandler = handler;
}
void IpcReceiver::addExpectedCodeCompletedMessage(
quint64 ticket,
ClangCompletionAssistProcessor *processor)
{
QTC_ASSERT(processor, return);
QTC_CHECK(!m_assistProcessorsTable.contains(ticket));
m_assistProcessorsTable.insert(ticket, processor);
}
void IpcReceiver::deleteProcessorsOfEditorWidget(TextEditor::TextEditorWidget *textEditorWidget)
{
QMutableHashIterator<quint64, ClangCompletionAssistProcessor *> it(m_assistProcessorsTable);
while (it.hasNext()) {
it.next();
ClangCompletionAssistProcessor *assistProcessor = it.value();
if (assistProcessor->textEditorWidget() == textEditorWidget) {
delete assistProcessor;
it.remove();
}
}
}
QFuture<CppTools::CursorInfo> IpcReceiver::addExpectedReferencesMessage(
quint64 ticket,
QTextDocument *textDocument,
const CppTools::SemanticInfo::LocalUseMap &localUses)
{
QTC_CHECK(textDocument);
QTC_CHECK(!m_referencesTable.contains(ticket));
QFutureInterface<CppTools::CursorInfo> futureInterface;
futureInterface.reportStarted();
const ReferencesEntry entry{futureInterface, textDocument, localUses};
m_referencesTable.insert(ticket, entry);
return futureInterface.future();
}
QFuture<CppTools::SymbolInfo> IpcReceiver::addExpectedRequestFollowSymbolMessage(quint64 ticket)
{
QTC_CHECK(!m_followTable.contains(ticket));
QFutureInterface<CppTools::SymbolInfo> futureInterface;
futureInterface.reportStarted();
m_followTable.insert(ticket, futureInterface);
return futureInterface.future();
}
bool IpcReceiver::isExpectingCodeCompletedMessage() const
{
return !m_assistProcessorsTable.isEmpty();
}
void IpcReceiver::reset()
{
// Clean up waiting assist processors
qDeleteAll(m_assistProcessorsTable.begin(), m_assistProcessorsTable.end());
m_assistProcessorsTable.clear();
// Clean up futures for references
for (ReferencesEntry &entry : m_referencesTable)
entry.futureInterface.cancel();
m_referencesTable.clear();
for (QFutureInterface<CppTools::SymbolInfo> &futureInterface : m_followTable)
futureInterface.cancel();
m_followTable.clear();
}
void IpcReceiver::alive()
{
if (printAliveMessage())
qCDebug(log) << "<<< AliveMessage";
QTC_ASSERT(m_aliveHandler, return);
m_aliveHandler();
}
void IpcReceiver::echo(const EchoMessage &message)
{
qCDebug(log) << "<<<" << message;
}
void IpcReceiver::codeCompleted(const CodeCompletedMessage &message)
{
qCDebug(log) << "<<< CodeCompletedMessage with" << message.codeCompletions().size() << "items";
const quint64 ticket = message.ticketNumber();
QScopedPointer<ClangCompletionAssistProcessor> processor(m_assistProcessorsTable.take(ticket));
if (processor) {
processor->handleAvailableCompletions(message.codeCompletions(),
message.neededCorrection());
}
}
void IpcReceiver::documentAnnotationsChanged(const DocumentAnnotationsChangedMessage &message)
{
qCDebug(log) << "<<< DocumentAnnotationsChangedMessage with"
<< message.diagnostics().size() << "diagnostics"
<< message.highlightingMarks().size() << "highlighting marks"
<< message.skippedPreprocessorRanges().size() << "skipped preprocessor ranges";
auto processor = ClangEditorDocumentProcessor::get(message.fileContainer().filePath());
if (processor) {
const QString projectPartId = message.fileContainer().projectPartId();
const QString filePath = message.fileContainer().filePath();
const QString documentProjectPartId = CppTools::CppToolsBridge::projectPartIdForFile(filePath);
if (projectPartId == documentProjectPartId) {
const quint32 documentRevision = message.fileContainer().documentRevision();
processor->updateCodeWarnings(message.diagnostics(),
message.firstHeaderErrorDiagnostic(),
documentRevision);
processor->updateHighlighting(message.highlightingMarks(),
message.skippedPreprocessorRanges(),
documentRevision);
}
}
}
static
CppTools::CursorInfo::Range toCursorInfoRange(const QTextDocument &textDocument,
const SourceRangeContainer &sourceRange)
{
const SourceLocationContainer start = sourceRange.start();
const SourceLocationContainer end = sourceRange.end();
const unsigned length = end.column() - start.column();
const QTextBlock block = textDocument.findBlockByNumber(static_cast<int>(start.line()) - 1);
const int shift = ClangCodeModel::Utils::extraUtf8CharsShift(block.text(),
static_cast<int>(start.column()));
const uint column = start.column() - static_cast<uint>(shift);
return CppTools::CursorInfo::Range(start.line(), column, length);
}
static
CppTools::CursorInfo toCursorInfo(const QTextDocument &textDocument,
const CppTools::SemanticInfo::LocalUseMap &localUses,
const ReferencesMessage &message)
{
CppTools::CursorInfo result;
const QVector<SourceRangeContainer> references = message.references();
result.areUseRangesForLocalVariable = message.isLocalVariable();
for (const SourceRangeContainer &reference : references)
result.useRanges.append(toCursorInfoRange(textDocument, reference));
result.useRanges.reserve(references.size());
result.localUses = localUses;
return result;
}
static
CppTools::SymbolInfo toSymbolInfo(const FollowSymbolMessage &message)
{
CppTools::SymbolInfo result;
const SourceRangeContainer &range = message.sourceRange();
const SourceLocationContainer start = range.start();
const SourceLocationContainer end = range.end();
result.startLine = static_cast<int>(start.line());
result.startColumn = static_cast<int>(start.column());
result.endLine = static_cast<int>(end.line());
result.endColumn = static_cast<int>(end.column());
result.fileName = start.filePath();
return result;
}
void IpcReceiver::references(const ReferencesMessage &message)
{
qCDebug(log) << "<<< ReferencesMessage with"
<< message.references().size() << "references";
const quint64 ticket = message.ticketNumber();
const ReferencesEntry entry = m_referencesTable.take(ticket);
QFutureInterface<CppTools::CursorInfo> futureInterface = entry.futureInterface;
QTC_CHECK(futureInterface != QFutureInterface<CppTools::CursorInfo>());
if (futureInterface.isCanceled())
return; // Editor document closed or a new request was issued making this result outdated.
QTC_ASSERT(entry.textDocument, return);
futureInterface.reportResult(toCursorInfo(*entry.textDocument, entry.localUses, message));
futureInterface.reportFinished();
}
void IpcReceiver::followSymbol(const ClangBackEnd::FollowSymbolMessage &message)
{
qCDebug(log) << "<<< FollowSymbolMessage with"
<< message.sourceRange() << "range";
const quint64 ticket = message.ticketNumber();
QFutureInterface<CppTools::SymbolInfo> futureInterface = m_followTable.take(ticket);
QTC_CHECK(futureInterface != QFutureInterface<CppTools::SymbolInfo>());
if (futureInterface.isCanceled())
return; // Editor document closed or a new request was issued making this result outdated.
futureInterface.reportResult(toSymbolInfo(message));
futureInterface.reportFinished();
}
IpcSender::IpcSender(ClangCodeModelConnectionClient *connectionClient)
: m_connection(connectionClient)
{}
void IpcSender::end()
{
QTC_CHECK(m_connection->isConnected());
qCDebug(log) << ">>>" << ClangBackEnd::EndMessage();
m_connection->sendEndMessage();
}
void IpcSender::registerTranslationUnitsForEditor(const RegisterTranslationUnitForEditorMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(log) << ">>>" << message;
m_connection->serverProxy().registerTranslationUnitsForEditor(message);
}
void IpcSender::updateTranslationUnitsForEditor(const UpdateTranslationUnitsForEditorMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(log) << ">>>" << message;
m_connection->serverProxy().updateTranslationUnitsForEditor(message);
}
void IpcSender::unregisterTranslationUnitsForEditor(const UnregisterTranslationUnitsForEditorMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(log) << ">>>" << message;
m_connection->serverProxy().unregisterTranslationUnitsForEditor(message);
}
void IpcSender::registerProjectPartsForEditor(const RegisterProjectPartsForEditorMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(log) << ">>>" << message;
m_connection->serverProxy().registerProjectPartsForEditor(message);
}
void IpcSender::unregisterProjectPartsForEditor(const UnregisterProjectPartsForEditorMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(log) << ">>>" << message;
m_connection->serverProxy().unregisterProjectPartsForEditor(message);
}
void IpcSender::registerUnsavedFilesForEditor(const RegisterUnsavedFilesForEditorMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(log) << ">>>" << message;
m_connection->serverProxy().registerUnsavedFilesForEditor(message);
}
void IpcSender::unregisterUnsavedFilesForEditor(const UnregisterUnsavedFilesForEditorMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(log) << ">>>" << message;
m_connection->serverProxy().unregisterUnsavedFilesForEditor(message);
}
void IpcSender::completeCode(const CompleteCodeMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(log) << ">>>" << message;
m_connection->serverProxy().completeCode(message);
}
void IpcSender::requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(log) << ">>>" << message;
m_connection->serverProxy().requestDocumentAnnotations(message);
}
void IpcSender::requestReferences(const RequestReferencesMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(log) << ">>>" << message;
m_connection->serverProxy().requestReferences(message);
}
void IpcSender::requestFollowSymbol(const RequestFollowSymbolMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(log) << ">>>" << message;
m_connection->serverProxy().requestFollowSymbol(message);
}
void IpcSender::updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(log) << ">>>" << message;
m_connection->serverProxy().updateVisibleTranslationUnits(message);
}
bool IpcSender::isConnected() const
{
return m_connection && m_connection->isConnected();
}
class DummyIpcSender : public IpcSender
{
public:
DummyIpcSender() : IpcSender(nullptr) {}
void end() override {}
void registerTranslationUnitsForEditor(const ClangBackEnd::RegisterTranslationUnitForEditorMessage &) override {}
void updateTranslationUnitsForEditor(const ClangBackEnd::UpdateTranslationUnitsForEditorMessage &) override {}
void unregisterTranslationUnitsForEditor(const ClangBackEnd::UnregisterTranslationUnitsForEditorMessage &) override {}
void registerProjectPartsForEditor(const ClangBackEnd::RegisterProjectPartsForEditorMessage &) override {}
void unregisterProjectPartsForEditor(const ClangBackEnd::UnregisterProjectPartsForEditorMessage &) override {}
void registerUnsavedFilesForEditor(const ClangBackEnd::RegisterUnsavedFilesForEditorMessage &) override {}
void unregisterUnsavedFilesForEditor(const ClangBackEnd::UnregisterUnsavedFilesForEditorMessage &) override {}
void completeCode(const ClangBackEnd::CompleteCodeMessage &) override {}
void requestDocumentAnnotations(const ClangBackEnd::RequestDocumentAnnotationsMessage &) override {}
void requestReferences(const ClangBackEnd::RequestReferencesMessage &) override {}
void requestFollowSymbol(const RequestFollowSymbolMessage &) override {}
void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &) override {}
};
enum { backEndStartTimeOutInMs = 10000 };
IpcCommunicator::IpcCommunicator()
: m_connection(&m_ipcReceiver)
, m_ipcSender(new DummyIpcSender())
{
m_backendStartTimeOut.setSingleShot(true);
connect(&m_backendStartTimeOut, &QTimer::timeout,
this, &IpcCommunicator::logStartTimeOut);
m_ipcReceiver.setAliveHandler([this]() { m_connection.resetProcessAliveTimer(); });
connect(Core::EditorManager::instance(), &Core::EditorManager::editorAboutToClose,
this, &IpcCommunicator::onEditorAboutToClose);
connect(Core::ICore::instance(), &Core::ICore::coreAboutToClose,
this, &IpcCommunicator::setupDummySender);
initializeBackend();
}
IpcCommunicator::~IpcCommunicator()
{
disconnect(&m_connection, 0, this, 0);
}
void IpcCommunicator::initializeBackend()
{
const QString clangBackEndProcessPath = backendProcessPath();
if (!QFileInfo(clangBackEndProcessPath).exists()) {
logExecutableDoesNotExist();
return;
}
qCDebug(log) << "Starting" << clangBackEndProcessPath;
m_connection.setProcessAliveTimerInterval(30 * 1000);
m_connection.setProcessPath(clangBackEndProcessPath);
connect(&m_connection, &ConnectionClient::connectedToLocalSocket,
this, &IpcCommunicator::onConnectedToBackend);
connect(&m_connection, &ConnectionClient::disconnectedFromLocalSocket,
this, &IpcCommunicator::setupDummySender);
m_connection.startProcessAndConnectToServerAsynchronously();
m_backendStartTimeOut.start(backEndStartTimeOutInMs);
}
static QStringList projectPartOptions(const CppTools::ProjectPart::Ptr &projectPart)
{
const QStringList options = ClangCodeModel::Utils::createClangOptions(projectPart,
CppTools::ProjectFile::Unsupported); // No language option
return options;
}
static ClangBackEnd::ProjectPartContainer toProjectPartContainer(
const CppTools::ProjectPart::Ptr &projectPart)
{
const QStringList options = projectPartOptions(projectPart);
return ClangBackEnd::ProjectPartContainer(projectPart->id(), Utf8StringVector(options));
}
static QVector<ClangBackEnd::ProjectPartContainer> toProjectPartContainers(
const QVector<CppTools::ProjectPart::Ptr> projectParts)
{
QVector<ClangBackEnd::ProjectPartContainer> projectPartContainers;
projectPartContainers.reserve(projectParts.size());
foreach (const CppTools::ProjectPart::Ptr &projectPart, projectParts)
projectPartContainers << toProjectPartContainer(projectPart);
return projectPartContainers;
}
void IpcCommunicator::registerFallbackProjectPart()
{
const auto projectPart = CppTools::CppModelManager::instance()->fallbackProjectPart();
const auto projectPartContainer = toProjectPartContainer(projectPart);
registerProjectPartsForEditor({projectPartContainer});
}
namespace {
Utf8String currentCppEditorDocumentFilePath()
{
Utf8String currentCppEditorDocumentFilePath;
const auto currentEditor = Core::EditorManager::currentEditor();
if (currentEditor && CppTools::CppModelManager::isCppEditor(currentEditor)) {
const auto currentDocument = currentEditor->document();
if (currentDocument)
currentCppEditorDocumentFilePath = currentDocument->filePath().toString();
}
return currentCppEditorDocumentFilePath;
}
void removeDuplicates(Utf8StringVector &visibleEditorDocumentsFilePaths)
{
std::sort(visibleEditorDocumentsFilePaths.begin(),
visibleEditorDocumentsFilePaths.end());
const auto end = std::unique(visibleEditorDocumentsFilePaths.begin(),
visibleEditorDocumentsFilePaths.end());
visibleEditorDocumentsFilePaths.erase(end,
visibleEditorDocumentsFilePaths.end());
}
void removeNonCppEditors(QList<Core::IEditor*> &visibleEditors)
{
const auto isNotCppEditor = [] (Core::IEditor *editor) {
return !CppTools::CppModelManager::isCppEditor(editor);
};
const auto end = std::remove_if(visibleEditors.begin(),
visibleEditors.end(),
isNotCppEditor);
visibleEditors.erase(end, visibleEditors.end());
}
Utf8StringVector visibleCppEditorDocumentsFilePaths()
{
auto visibleEditors = CppTools::CppToolsBridge::visibleEditors();
removeNonCppEditors(visibleEditors);
Utf8StringVector visibleCppEditorDocumentsFilePaths;
visibleCppEditorDocumentsFilePaths.reserve(visibleEditors.size());
const auto editorFilePaths = [] (Core::IEditor *editor) {
return Utf8String(editor->document()->filePath().toString());
};
std::transform(visibleEditors.begin(),
visibleEditors.end(),
std::back_inserter(visibleCppEditorDocumentsFilePaths),
editorFilePaths);
removeDuplicates(visibleCppEditorDocumentsFilePaths);
return visibleCppEditorDocumentsFilePaths;
}
}
void IpcCommunicator::updateTranslationUnitVisiblity()
{
updateTranslationUnitVisiblity(currentCppEditorDocumentFilePath(), visibleCppEditorDocumentsFilePaths());
}
bool IpcCommunicator::isNotWaitingForCompletion() const
{
return !m_ipcReceiver.isExpectingCodeCompletedMessage();
}
void IpcCommunicator::updateTranslationUnitVisiblity(const Utf8String &currentEditorFilePath,
const Utf8StringVector &visibleEditorsFilePaths)
{
const UpdateVisibleTranslationUnitsMessage message(currentEditorFilePath, visibleEditorsFilePaths);
m_ipcSender->updateVisibleTranslationUnits(message);
}
void IpcCommunicator::registerCurrentProjectParts()
{
using namespace CppTools;
const QList<ProjectInfo> projectInfos = CppModelManager::instance()->projectInfos();
foreach (const ProjectInfo &projectInfo, projectInfos)
registerProjectsParts(projectInfo.projectParts());
}
void IpcCommunicator::restoreCppEditorDocuments()
{
resetCppEditorDocumentProcessors();
registerVisibleCppEditorDocumentAndMarkInvisibleDirty();
}
void IpcCommunicator::resetCppEditorDocumentProcessors()
{
using namespace CppTools;
const auto cppEditorDocuments = CppModelManager::instance()->cppEditorDocuments();
foreach (CppEditorDocumentHandle *cppEditorDocument, cppEditorDocuments)
cppEditorDocument->resetProcessor();
}
void IpcCommunicator::registerVisibleCppEditorDocumentAndMarkInvisibleDirty()
{
CppTools::CppModelManager::instance()->updateCppEditorDocuments();
}
void IpcCommunicator::registerCurrentCodeModelUiHeaders()
{
using namespace CppTools;
const auto editorSupports = CppModelManager::instance()->abstractEditorSupports();
foreach (const AbstractEditorSupport *es, editorSupports) {
const QString mappedPath
= ModelManagerSupportClang::instance()->dummyUiHeaderOnDiskPath(es->fileName());
updateUnsavedFile(mappedPath, es->contents(), es->revision());
}
}
void IpcCommunicator::registerProjectsParts(const QVector<CppTools::ProjectPart::Ptr> projectParts)
{
const auto projectPartContainers = toProjectPartContainers(projectParts);
registerProjectPartsForEditor(projectPartContainers);
}
void IpcCommunicator::updateTranslationUnitFromCppEditorDocument(const QString &filePath)
{
const CppTools::CppEditorDocumentHandle *document = ClangCodeModel::Utils::cppDocument(filePath);
updateTranslationUnit(filePath, document->contents(), document->revision());
}
void IpcCommunicator::updateUnsavedFileFromCppEditorDocument(const QString &filePath)
{
const CppTools::CppEditorDocumentHandle *document = ClangCodeModel::Utils::cppDocument(filePath);
updateUnsavedFile(filePath, document->contents(), document->revision());
}
namespace {
}
void IpcCommunicator::updateTranslationUnit(const QString &filePath,
const QByteArray &contents,
uint documentRevision)
{
const bool hasUnsavedContent = true;
updateTranslationUnitsForEditor({{filePath,
Utf8String(),
Utf8String::fromByteArray(contents),
hasUnsavedContent,
documentRevision}});
}
void IpcCommunicator::updateUnsavedFile(const QString &filePath, const QByteArray &contents, uint documentRevision)
{
const bool hasUnsavedContent = true;
// TODO: Send new only if changed
registerUnsavedFilesForEditor({{filePath,
Utf8String(),
Utf8String::fromByteArray(contents),
hasUnsavedContent,
documentRevision}});
}
static bool documentHasChanged(const QString &filePath, uint revision)
{
if (CppTools::CppEditorDocumentHandle *document = ClangCodeModel::Utils::cppDocument(filePath))
return document->sendTracker().shouldSendRevision(revision);
return true;
}
static void setLastSentDocumentRevision(const QString &filePath, uint revision)
{
if (CppTools::CppEditorDocumentHandle *document = ClangCodeModel::Utils::cppDocument(filePath))
document->sendTracker().setLastSentRevision(int(revision));
}
void IpcCommunicator::updateTranslationUnitWithRevisionCheck(const FileContainer &fileContainer)
{
if (documentHasChanged(fileContainer.filePath(), fileContainer.documentRevision())) {
updateTranslationUnitsForEditor({fileContainer});
setLastSentDocumentRevision(fileContainer.filePath(),
fileContainer.documentRevision());
}
}
void IpcCommunicator::requestDocumentAnnotations(const FileContainer &fileContainer)
{
const RequestDocumentAnnotationsMessage message(fileContainer);
m_ipcSender->requestDocumentAnnotations(message);
}
QFuture<CppTools::CursorInfo> IpcCommunicator::requestReferences(
const FileContainer &fileContainer,
quint32 line,
quint32 column,
QTextDocument *textDocument,
const CppTools::SemanticInfo::LocalUseMap &localUses)
{
const RequestReferencesMessage message(fileContainer, line, column);
m_ipcSender->requestReferences(message);
return m_ipcReceiver.addExpectedReferencesMessage(message.ticketNumber(), textDocument,
localUses);
}
QFuture<CppTools::SymbolInfo> IpcCommunicator::requestFollowSymbol(
const FileContainer &curFileContainer,
const QVector<Utf8String> &dependentFiles,
quint32 line,
quint32 column)
{
const RequestFollowSymbolMessage message(curFileContainer,
dependentFiles,
line,
column);
m_ipcSender->requestFollowSymbol(message);
return m_ipcReceiver.addExpectedRequestFollowSymbolMessage(message.ticketNumber());
}
void IpcCommunicator::updateTranslationUnitWithRevisionCheck(Core::IDocument *document)
{
const auto textDocument = qobject_cast<TextDocument*>(document);
const auto filePath = textDocument->filePath().toString();
const QString projectPartId = CppTools::CppToolsBridge::projectPartIdForFile(filePath);
updateTranslationUnitWithRevisionCheck(FileContainer(filePath,
projectPartId,
Utf8StringVector(),
textDocument->document()->revision()));
}
void IpcCommunicator::updateChangeContentStartPosition(const QString &filePath, int position)
{
if (CppTools::CppEditorDocumentHandle *document = ClangCodeModel::Utils::cppDocument(filePath))
document->sendTracker().applyContentChange(position);
}
void IpcCommunicator::updateTranslationUnitIfNotCurrentDocument(Core::IDocument *document)
{
QTC_ASSERT(document, return);
if (Core::EditorManager::currentDocument() != document)
updateTranslationUnit(document);
}
void IpcCommunicator::updateTranslationUnit(Core::IDocument *document)
{
updateTranslationUnitFromCppEditorDocument(document->filePath().toString());
}
void IpcCommunicator::updateUnsavedFile(Core::IDocument *document)
{
QTC_ASSERT(document, return);
updateUnsavedFileFromCppEditorDocument(document->filePath().toString());
}
void IpcCommunicator::onConnectedToBackend()
{
m_backendStartTimeOut.stop();
++m_connectedCount;
if (m_connectedCount > 1)
logRestartedDueToUnexpectedFinish();
m_ipcReceiver.reset();
m_ipcSender.reset(new IpcSender(&m_connection));
initializeBackendWithCurrentData();
}
void IpcCommunicator::onEditorAboutToClose(Core::IEditor *editor)
{
if (auto *textEditor = qobject_cast<TextEditor::BaseTextEditor *>(editor))
m_ipcReceiver.deleteProcessorsOfEditorWidget(textEditor->editorWidget());
}
void IpcCommunicator::setupDummySender()
{
m_ipcSender.reset(new DummyIpcSender);
}
void IpcCommunicator::logExecutableDoesNotExist()
{
const QString msg
= tr("Clang Code Model: Error: "
"The clangbackend executable \"%1\" does not exist.")
.arg(QDir::toNativeSeparators(backendProcessPath()));
logError(msg);
}
void IpcCommunicator::logStartTimeOut()
{
const QString msg
= tr("Clang Code Model: Error: "
"The clangbackend executable \"%1\" could not be started (timeout after %2ms).")
.arg(QDir::toNativeSeparators(backendProcessPath()))
.arg(backEndStartTimeOutInMs);
logError(msg);
}
void IpcCommunicator::logRestartedDueToUnexpectedFinish()
{
const QString msg
= tr("Clang Code Model: Error: "
"The clangbackend process has finished unexpectedly and was restarted.");
logError(msg);
}
void IpcCommunicator::logError(const QString &text)
{
const QString textWithTimestamp = QDateTime::currentDateTime().toString(Qt::ISODate)
+ ' ' + text;
Core::MessageManager::write(textWithTimestamp, Core::MessageManager::Flash);
qWarning("%s", qPrintable(textWithTimestamp));
}
void IpcCommunicator::initializeBackendWithCurrentData()
{
registerFallbackProjectPart();
registerCurrentProjectParts();
registerCurrentCodeModelUiHeaders();
restoreCppEditorDocuments();
updateTranslationUnitVisiblity();
emit backendReinitialized();
}
IpcSender *IpcCommunicator::setIpcSender(IpcSender *ipcSender)
{
IpcSender *previousMessageSender = m_ipcSender.take();
m_ipcSender.reset(ipcSender);
return previousMessageSender;
}
void IpcCommunicator::killBackendProcess()
{
m_connection.processForTestOnly()->kill();
}
void IpcCommunicator::registerTranslationUnitsForEditor(const FileContainers &fileContainers)
{
const RegisterTranslationUnitForEditorMessage message(fileContainers,
currentCppEditorDocumentFilePath(),
visibleCppEditorDocumentsFilePaths());
m_ipcSender->registerTranslationUnitsForEditor(message);
}
void IpcCommunicator::updateTranslationUnitsForEditor(const IpcCommunicator::FileContainers &fileContainers)
{
const UpdateTranslationUnitsForEditorMessage message(fileContainers);
m_ipcSender->updateTranslationUnitsForEditor(message);
}
void IpcCommunicator::unregisterTranslationUnitsForEditor(const FileContainers &fileContainers)
{
const UnregisterTranslationUnitsForEditorMessage message(fileContainers);
m_ipcSender->unregisterTranslationUnitsForEditor(message);
}
void IpcCommunicator::registerProjectPartsForEditor(
const ProjectPartContainers &projectPartContainers)
{
const RegisterProjectPartsForEditorMessage message(projectPartContainers);
m_ipcSender->registerProjectPartsForEditor(message);
}
void IpcCommunicator::unregisterProjectPartsForEditor(const QStringList &projectPartIds)
{
const UnregisterProjectPartsForEditorMessage message((Utf8StringVector(projectPartIds)));
m_ipcSender->unregisterProjectPartsForEditor(message);
}
void IpcCommunicator::registerUnsavedFilesForEditor(const IpcCommunicator::FileContainers &fileContainers)
{
const RegisterUnsavedFilesForEditorMessage message(fileContainers);
m_ipcSender->registerUnsavedFilesForEditor(message);
}
void IpcCommunicator::unregisterUnsavedFilesForEditor(const IpcCommunicator::FileContainers &fileContainers)
{
const UnregisterUnsavedFilesForEditorMessage message(fileContainers);
m_ipcSender->unregisterUnsavedFilesForEditor(message);
}
void IpcCommunicator::completeCode(ClangCompletionAssistProcessor *assistProcessor,
const QString &filePath,
quint32 line,
quint32 column,
const QString &projectFilePath,
qint32 funcNameStartLine,
qint32 funcNameStartColumn)
{
const CompleteCodeMessage message(filePath, line, column, projectFilePath, funcNameStartLine,
funcNameStartColumn);
m_ipcSender->completeCode(message);
m_ipcReceiver.addExpectedCodeCompletedMessage(message.ticketNumber(), assistProcessor);
}
@@ -0,0 +1,34 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangbackendlogging.h"
namespace ClangCodeModel {
namespace Internal {
Q_LOGGING_CATEGORY(ipcLog, "qtc.clangcodemodel.ipc")
} // namespace Internal
} // namespace ClangCodeModel
@@ -0,0 +1,35 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QLoggingCategory>
namespace ClangCodeModel { namespace Internal {
Q_DECLARE_LOGGING_CATEGORY(ipcLog)
} // namespace Internal
} // namespace ClangCodeModel
@@ -0,0 +1,287 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangbackendreceiver.h"
#include "clangbackendlogging.h"
#include "clangcompletionassistprocessor.h"
#include "clangeditordocumentprocessor.h"
#include <cpptools/cpptoolsbridge.h>
#include <clangsupport/clangcodemodelclientmessages.h>
#include <QLoggingCategory>
#include <QTextBlock>
#include <utils/qtcassert.h>
static Q_LOGGING_CATEGORY(log, "qtc.clangcodemodel.ipc")
using namespace ClangBackEnd;
namespace ClangCodeModel {
namespace Internal {
static bool printAliveMessageHelper()
{
const bool print = qEnvironmentVariableIntValue("QTC_CLANG_FORCE_VERBOSE_ALIVE");
if (!print) {
qCDebug(log) << "Hint: AliveMessage will not be printed. "
"Force it by setting QTC_CLANG_FORCE_VERBOSE_ALIVE=1.";
}
return print;
}
static bool printAliveMessage()
{
static bool print = log().isDebugEnabled() ? printAliveMessageHelper() : false;
return print;
}
BackendReceiver::BackendReceiver()
{
}
BackendReceiver::~BackendReceiver()
{
reset();
}
void BackendReceiver::setAliveHandler(const BackendReceiver::AliveHandler &handler)
{
m_aliveHandler = handler;
}
void BackendReceiver::addExpectedCodeCompletedMessage(
quint64 ticket,
ClangCompletionAssistProcessor *processor)
{
QTC_ASSERT(processor, return);
QTC_CHECK(!m_assistProcessorsTable.contains(ticket));
m_assistProcessorsTable.insert(ticket, processor);
}
void BackendReceiver::deleteProcessorsOfEditorWidget(TextEditor::TextEditorWidget *textEditorWidget)
{
QMutableHashIterator<quint64, ClangCompletionAssistProcessor *> it(m_assistProcessorsTable);
while (it.hasNext()) {
it.next();
ClangCompletionAssistProcessor *assistProcessor = it.value();
if (assistProcessor->textEditorWidget() == textEditorWidget) {
delete assistProcessor;
it.remove();
}
}
}
QFuture<CppTools::CursorInfo> BackendReceiver::addExpectedReferencesMessage(
quint64 ticket,
QTextDocument *textDocument,
const CppTools::SemanticInfo::LocalUseMap &localUses)
{
QTC_CHECK(textDocument);
QTC_CHECK(!m_referencesTable.contains(ticket));
QFutureInterface<CppTools::CursorInfo> futureInterface;
futureInterface.reportStarted();
const ReferencesEntry entry{futureInterface, textDocument, localUses};
m_referencesTable.insert(ticket, entry);
return futureInterface.future();
}
QFuture<CppTools::SymbolInfo> BackendReceiver::addExpectedRequestFollowSymbolMessage(quint64 ticket)
{
QTC_CHECK(!m_followTable.contains(ticket));
QFutureInterface<CppTools::SymbolInfo> futureInterface;
futureInterface.reportStarted();
m_followTable.insert(ticket, futureInterface);
return futureInterface.future();
}
bool BackendReceiver::isExpectingCodeCompletedMessage() const
{
return !m_assistProcessorsTable.isEmpty();
}
void BackendReceiver::reset()
{
// Clean up waiting assist processors
qDeleteAll(m_assistProcessorsTable.begin(), m_assistProcessorsTable.end());
m_assistProcessorsTable.clear();
// Clean up futures for references
for (ReferencesEntry &entry : m_referencesTable)
entry.futureInterface.cancel();
m_referencesTable.clear();
for (QFutureInterface<CppTools::SymbolInfo> &futureInterface : m_followTable)
futureInterface.cancel();
m_followTable.clear();
}
void BackendReceiver::alive()
{
if (printAliveMessage())
qCDebug(log) << "<<< AliveMessage";
QTC_ASSERT(m_aliveHandler, return);
m_aliveHandler();
}
void BackendReceiver::echo(const EchoMessage &message)
{
qCDebug(log) << "<<<" << message;
}
void BackendReceiver::codeCompleted(const CodeCompletedMessage &message)
{
qCDebug(log) << "<<< CodeCompletedMessage with" << message.codeCompletions().size() << "items";
const quint64 ticket = message.ticketNumber();
QScopedPointer<ClangCompletionAssistProcessor> processor(m_assistProcessorsTable.take(ticket));
if (processor) {
processor->handleAvailableCompletions(message.codeCompletions(),
message.neededCorrection());
}
}
void BackendReceiver::documentAnnotationsChanged(const DocumentAnnotationsChangedMessage &message)
{
qCDebug(log) << "<<< DocumentAnnotationsChangedMessage with"
<< message.diagnostics().size() << "diagnostics"
<< message.highlightingMarks().size() << "highlighting marks"
<< message.skippedPreprocessorRanges().size() << "skipped preprocessor ranges";
auto processor = ClangEditorDocumentProcessor::get(message.fileContainer().filePath());
if (processor) {
const QString projectPartId = message.fileContainer().projectPartId();
const QString filePath = message.fileContainer().filePath();
const QString documentProjectPartId = CppTools::CppToolsBridge::projectPartIdForFile(filePath);
if (projectPartId == documentProjectPartId) {
const quint32 documentRevision = message.fileContainer().documentRevision();
processor->updateCodeWarnings(message.diagnostics(),
message.firstHeaderErrorDiagnostic(),
documentRevision);
processor->updateHighlighting(message.highlightingMarks(),
message.skippedPreprocessorRanges(),
documentRevision);
}
}
}
static
CppTools::CursorInfo::Range toCursorInfoRange(const QTextDocument &textDocument,
const SourceRangeContainer &sourceRange)
{
const SourceLocationContainer start = sourceRange.start();
const SourceLocationContainer end = sourceRange.end();
const unsigned length = end.column() - start.column();
const QTextBlock block = textDocument.findBlockByNumber(static_cast<int>(start.line()) - 1);
const int shift = ClangCodeModel::Utils::extraUtf8CharsShift(block.text(),
static_cast<int>(start.column()));
const uint column = start.column() - static_cast<uint>(shift);
return CppTools::CursorInfo::Range(start.line(), column, length);
}
static
CppTools::CursorInfo toCursorInfo(const QTextDocument &textDocument,
const CppTools::SemanticInfo::LocalUseMap &localUses,
const ReferencesMessage &message)
{
CppTools::CursorInfo result;
const QVector<SourceRangeContainer> references = message.references();
result.areUseRangesForLocalVariable = message.isLocalVariable();
for (const SourceRangeContainer &reference : references)
result.useRanges.append(toCursorInfoRange(textDocument, reference));
result.useRanges.reserve(references.size());
result.localUses = localUses;
return result;
}
static
CppTools::SymbolInfo toSymbolInfo(const FollowSymbolMessage &message)
{
CppTools::SymbolInfo result;
const SourceRangeContainer &range = message.sourceRange();
const SourceLocationContainer start = range.start();
const SourceLocationContainer end = range.end();
result.startLine = static_cast<int>(start.line());
result.startColumn = static_cast<int>(start.column());
result.endLine = static_cast<int>(end.line());
result.endColumn = static_cast<int>(end.column());
result.fileName = start.filePath();
return result;
}
void BackendReceiver::references(const ReferencesMessage &message)
{
qCDebug(log) << "<<< ReferencesMessage with"
<< message.references().size() << "references";
const quint64 ticket = message.ticketNumber();
const ReferencesEntry entry = m_referencesTable.take(ticket);
QFutureInterface<CppTools::CursorInfo> futureInterface = entry.futureInterface;
QTC_CHECK(futureInterface != QFutureInterface<CppTools::CursorInfo>());
if (futureInterface.isCanceled())
return; // Editor document closed or a new request was issued making this result outdated.
QTC_ASSERT(entry.textDocument, return);
futureInterface.reportResult(toCursorInfo(*entry.textDocument, entry.localUses, message));
futureInterface.reportFinished();
}
void BackendReceiver::followSymbol(const ClangBackEnd::FollowSymbolMessage &message)
{
qCDebug(log) << "<<< FollowSymbolMessage with"
<< message.sourceRange() << "range";
const quint64 ticket = message.ticketNumber();
QFutureInterface<CppTools::SymbolInfo> futureInterface = m_followTable.take(ticket);
QTC_CHECK(futureInterface != QFutureInterface<CppTools::SymbolInfo>());
if (futureInterface.isCanceled())
return; // Editor document closed or a new request was issued making this result outdated.
futureInterface.reportResult(toSymbolInfo(message));
futureInterface.reportFinished();
}
} // namespace Internal
} // namespace ClangCodeModel
@@ -0,0 +1,96 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <cpptools/cppcursorinfo.h>
#include <cpptools/cppsymbolinfo.h>
#include <clangsupport/clangcodemodelclientinterface.h>
#include <QFuture>
#include <QPointer>
#include <QTextDocument>
namespace TextEditor { class TextEditorWidget; }
namespace ClangCodeModel {
namespace Internal {
class ClangCompletionAssistProcessor;
class BackendReceiver : public ClangBackEnd::ClangCodeModelClientInterface
{
public:
BackendReceiver();
~BackendReceiver() override;
using AliveHandler = std::function<void ()>;
void setAliveHandler(const AliveHandler &handler);
void addExpectedCodeCompletedMessage(quint64 ticket, ClangCompletionAssistProcessor *processor);
void deleteProcessorsOfEditorWidget(TextEditor::TextEditorWidget *textEditorWidget);
QFuture<CppTools::CursorInfo>
addExpectedReferencesMessage(quint64 ticket,
QTextDocument *textDocument,
const CppTools::SemanticInfo::LocalUseMap &localUses);
QFuture<CppTools::SymbolInfo> addExpectedRequestFollowSymbolMessage(quint64 ticket);
bool isExpectingCodeCompletedMessage() const;
void reset();
private:
void alive() override;
void echo(const ClangBackEnd::EchoMessage &message) override;
void codeCompleted(const ClangBackEnd::CodeCompletedMessage &message) override;
void documentAnnotationsChanged(const ClangBackEnd::DocumentAnnotationsChangedMessage &message) override;
void references(const ClangBackEnd::ReferencesMessage &message) override;
void followSymbol(const ClangBackEnd::FollowSymbolMessage &message) override;
private:
AliveHandler m_aliveHandler;
QHash<quint64, ClangCompletionAssistProcessor *> m_assistProcessorsTable;
struct ReferencesEntry {
ReferencesEntry() = default;
ReferencesEntry(QFutureInterface<CppTools::CursorInfo> futureInterface,
QTextDocument *textDocument,
const CppTools::SemanticInfo::LocalUseMap &localUses)
: futureInterface(futureInterface)
, textDocument(textDocument)
, localUses(localUses) {}
QFutureInterface<CppTools::CursorInfo> futureInterface;
QPointer<QTextDocument> textDocument;
CppTools::SemanticInfo::LocalUseMap localUses;
};
QHash<quint64, ReferencesEntry> m_referencesTable;
QHash<quint64, QFutureInterface<CppTools::SymbolInfo>> m_followTable;
};
} // namespace Internal
} // namespace ClangCodeModel
@@ -0,0 +1,141 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangbackendsender.h"
#include "clangbackendlogging.h"
#include <clangsupport/clangcodemodelconnectionclient.h>
#include <clangsupport/clangcodemodelservermessages.h>
#include <utils/qtcassert.h>
using namespace ClangBackEnd;
namespace ClangCodeModel {
namespace Internal {
BackendSender::BackendSender(ClangCodeModelConnectionClient *connectionClient)
: m_connection(connectionClient)
{}
void BackendSender::end()
{
QTC_CHECK(m_connection->isConnected());
qCDebug(ipcLog) << ">>>" << ClangBackEnd::EndMessage();
m_connection->sendEndMessage();
}
void BackendSender::registerTranslationUnitsForEditor(const RegisterTranslationUnitForEditorMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(ipcLog) << ">>>" << message;
m_connection->serverProxy().registerTranslationUnitsForEditor(message);
}
void BackendSender::updateTranslationUnitsForEditor(const UpdateTranslationUnitsForEditorMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(ipcLog) << ">>>" << message;
m_connection->serverProxy().updateTranslationUnitsForEditor(message);
}
void BackendSender::unregisterTranslationUnitsForEditor(const UnregisterTranslationUnitsForEditorMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(ipcLog) << ">>>" << message;
m_connection->serverProxy().unregisterTranslationUnitsForEditor(message);
}
void BackendSender::registerProjectPartsForEditor(const RegisterProjectPartsForEditorMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(ipcLog) << ">>>" << message;
m_connection->serverProxy().registerProjectPartsForEditor(message);
}
void BackendSender::unregisterProjectPartsForEditor(const UnregisterProjectPartsForEditorMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(ipcLog) << ">>>" << message;
m_connection->serverProxy().unregisterProjectPartsForEditor(message);
}
void BackendSender::registerUnsavedFilesForEditor(const RegisterUnsavedFilesForEditorMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(ipcLog) << ">>>" << message;
m_connection->serverProxy().registerUnsavedFilesForEditor(message);
}
void BackendSender::unregisterUnsavedFilesForEditor(const UnregisterUnsavedFilesForEditorMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(ipcLog) << ">>>" << message;
m_connection->serverProxy().unregisterUnsavedFilesForEditor(message);
}
void BackendSender::completeCode(const CompleteCodeMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(ipcLog) << ">>>" << message;
m_connection->serverProxy().completeCode(message);
}
void BackendSender::requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(ipcLog) << ">>>" << message;
m_connection->serverProxy().requestDocumentAnnotations(message);
}
void BackendSender::requestReferences(const RequestReferencesMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(ipcLog) << ">>>" << message;
m_connection->serverProxy().requestReferences(message);
}
void BackendSender::requestFollowSymbol(const RequestFollowSymbolMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(ipcLog) << ">>>" << message;
m_connection->serverProxy().requestFollowSymbol(message);
}
void BackendSender::updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message)
{
QTC_CHECK(m_connection->isConnected());
qCDebug(ipcLog) << ">>>" << message;
m_connection->serverProxy().updateVisibleTranslationUnits(message);
}
bool BackendSender::isConnected() const
{
return m_connection && m_connection->isConnected();
}
} // namespace Internal
} // namespace ClangCodeModel
@@ -0,0 +1,62 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <clangsupport/clangcodemodelserverinterface.h>
namespace ClangBackEnd { class ClangCodeModelConnectionClient; }
namespace ClangCodeModel {
namespace Internal {
class BackendSender : public ClangBackEnd::ClangCodeModelServerInterface
{
public:
BackendSender(ClangBackEnd::ClangCodeModelConnectionClient *connectionClient);
void end() override;
void registerTranslationUnitsForEditor(const ClangBackEnd::RegisterTranslationUnitForEditorMessage &message) override;
void updateTranslationUnitsForEditor(const ClangBackEnd::UpdateTranslationUnitsForEditorMessage &message) override;
void unregisterTranslationUnitsForEditor(const ClangBackEnd::UnregisterTranslationUnitsForEditorMessage &message) override;
void registerProjectPartsForEditor(const ClangBackEnd::RegisterProjectPartsForEditorMessage &message) override;
void unregisterProjectPartsForEditor(const ClangBackEnd::UnregisterProjectPartsForEditorMessage &message) override;
void registerUnsavedFilesForEditor(const ClangBackEnd::RegisterUnsavedFilesForEditorMessage &message) override;
void unregisterUnsavedFilesForEditor(const ClangBackEnd::UnregisterUnsavedFilesForEditorMessage &message) override;
void completeCode(const ClangBackEnd::CompleteCodeMessage &message) override;
void requestDocumentAnnotations(const ClangBackEnd::RequestDocumentAnnotationsMessage &message) override;
void requestReferences(const ClangBackEnd::RequestReferencesMessage &message) override;
void requestFollowSymbol(const ClangBackEnd::RequestFollowSymbolMessage &message) override;
void updateVisibleTranslationUnits(const ClangBackEnd::UpdateVisibleTranslationUnitsMessage &message) override;
private:
bool isConnected() const;
private:
ClangBackEnd::ClangCodeModelConnectionClient *m_connection = nullptr;
};
} // namespace Internal
} // namespace ClangCodeModel
@@ -9,7 +9,10 @@ SOURCES += \
clangassistproposal.cpp \
clangassistproposalitem.cpp \
clangassistproposalmodel.cpp \
clangbackendipcintegration.cpp \
clangbackendcommunicator.cpp \
clangbackendlogging.cpp \
clangbackendreceiver.cpp \
clangbackendsender.cpp \
clangcodemodelplugin.cpp \
clangcompletionassistinterface.cpp \
clangcompletionassistprocessor.cpp \
@@ -40,7 +43,10 @@ HEADERS += \
clangassistproposal.h \
clangassistproposalitem.h \
clangassistproposalmodel.h \
clangbackendipcintegration.h \
clangbackendcommunicator.h \
clangbackendlogging.h \
clangbackendreceiver.h \
clangbackendsender.h \
clangcodemodelplugin.h \
clangcompletionassistinterface.h \
clangcompletionassistprocessor.h \
@@ -41,8 +41,14 @@ QtcPlugin {
"clangassistproposalitem.h",
"clangassistproposalmodel.cpp",
"clangassistproposalmodel.h",
"clangbackendipcintegration.cpp",
"clangbackendipcintegration.h",
"clangbackendcommunicator.cpp",
"clangbackendcommunicator.h",
"clangbackendlogging.cpp",
"clangbackendlogging.h",
"clangbackendreceiver.cpp",
"clangbackendreceiver.h",
"clangbackendsender.cpp",
"clangbackendsender.h",
"clangcodemodelplugin.cpp",
"clangcodemodelplugin.h",
"clangcodemodel.qrc",
@@ -31,7 +31,7 @@ namespace ClangCodeModel {
namespace Internal {
ClangCompletionAssistInterface::ClangCompletionAssistInterface(
IpcCommunicator &ipcCommunicator,
BackendCommunicator &communicator,
const TextEditor::TextEditorWidget *textEditorWidget,
int position,
const QString &fileName,
@@ -39,7 +39,7 @@ ClangCompletionAssistInterface::ClangCompletionAssistInterface(
const CppTools::ProjectPartHeaderPaths &headerPaths,
const CPlusPlus::LanguageFeatures &features)
: AssistInterface(textEditorWidget->document(), position, fileName, reason)
, m_ipcCommunicator(ipcCommunicator)
, m_communicator(communicator)
, m_headerPaths(headerPaths)
, m_languageFeatures(features)
, m_textEditorWidget(textEditorWidget)
@@ -71,9 +71,9 @@ const TextEditor::TextEditorWidget *ClangCompletionAssistInterface::textEditorWi
return m_textEditorWidget;
}
IpcCommunicator &ClangCompletionAssistInterface::ipcCommunicator() const
BackendCommunicator &ClangCompletionAssistInterface::communicator() const
{
return m_ipcCommunicator;
return m_communicator;
}
} // namespace Internal
@@ -25,7 +25,7 @@
#pragma once
#include "clangbackendipcintegration.h"
#include "clangbackendcommunicator.h"
#include "clangutils.h"
#include <texteditor/codeassist/assistinterface.h>
@@ -36,7 +36,7 @@ namespace Internal {
class ClangCompletionAssistInterface: public TextEditor::AssistInterface
{
public:
ClangCompletionAssistInterface(IpcCommunicator &ipcCommunicator,
ClangCompletionAssistInterface(BackendCommunicator &communicator,
const TextEditor::TextEditorWidget *textEditorWidget,
int position,
const QString &fileName,
@@ -44,7 +44,7 @@ public:
const CppTools::ProjectPartHeaderPaths &headerPaths,
const CPlusPlus::LanguageFeatures &features);
IpcCommunicator &ipcCommunicator() const;
BackendCommunicator &communicator() const;
bool objcEnabled() const;
const CppTools::ProjectPartHeaderPaths &headerPaths() const;
CPlusPlus::LanguageFeatures languageFeatures() const;
@@ -53,7 +53,7 @@ public:
void setHeaderPaths(const CppTools::ProjectPartHeaderPaths &headerPaths); // For tests
private:
IpcCommunicator &m_ipcCommunicator;
BackendCommunicator &m_communicator;
QStringList m_options;
CppTools::ProjectPartHeaderPaths m_headerPaths;
CPlusPlus::LanguageFeatures m_languageFeatures;
@@ -495,8 +495,8 @@ void ClangCompletionAssistProcessor::sendFileContent(const QByteArray &customFil
// TODO: Revert custom modification after the completions
const UnsavedFileContentInfo info = unsavedFileContent(customFileContent);
IpcCommunicator &ipcCommunicator = m_interface->ipcCommunicator();
ipcCommunicator.updateTranslationUnitsForEditor({{m_interface->fileName(),
BackendCommunicator &communicator = m_interface->communicator();
communicator.updateTranslationUnitsForEditor({{m_interface->fileName(),
Utf8String(),
Utf8String::fromByteArray(info.unsavedContent),
info.isDocumentModified,
@@ -568,10 +568,9 @@ bool ClangCompletionAssistProcessor::sendCompletionRequest(int position,
{
const QString filePath = m_interface->fileName();
auto &ipcCommunicator = m_interface->ipcCommunicator();
auto &communicator = m_interface->communicator();
if (shouldSendCodeCompletion(filePath, position)
|| ipcCommunicator.isNotWaitingForCompletion()) {
if (shouldSendCodeCompletion(filePath, position) || communicator.isNotWaitingForCompletion()) {
if (shouldSendDocumentForCompletion(filePath, position)) {
sendFileContent(customFileContent);
setLastDocumentRevision(filePath);
@@ -580,7 +579,7 @@ bool ClangCompletionAssistProcessor::sendCompletionRequest(int position,
const Position cursorPosition = extractLineColumn(position);
const Position functionNameStart = extractLineColumn(functionNameStartPosition);
const QString projectPartId = CppTools::CppToolsBridge::projectPartIdForFile(filePath);
ipcCommunicator.completeCode(this, filePath, uint(cursorPosition.line),
communicator.completeCode(this, filePath, uint(cursorPosition.line),
uint(cursorPosition.column), projectPartId,
functionNameStart.line, functionNameStart.column);
setLastCompletionPosition(filePath, position);
@@ -43,8 +43,8 @@
namespace ClangCodeModel {
namespace Internal {
ClangCompletionAssistProvider::ClangCompletionAssistProvider(IpcCommunicator &ipcCommunicator)
: m_ipcCommunicator(ipcCommunicator)
ClangCompletionAssistProvider::ClangCompletionAssistProvider(BackendCommunicator &communicator)
: m_communicator(communicator)
{
}
@@ -67,7 +67,7 @@ TextEditor::AssistInterface *ClangCompletionAssistProvider::createAssistInterfac
{
const CppTools::ProjectPart::Ptr projectPart = Utils::projectPartForFileBasedOnProcessor(filePath);
if (projectPart) {
return new ClangCompletionAssistInterface(m_ipcCommunicator,
return new ClangCompletionAssistInterface(m_communicator,
textEditorWidget,
position,
filePath,
@@ -25,7 +25,7 @@
#pragma once
#include "clangbackendipcintegration.h"
#include "clangbackendcommunicator.h"
#include <cpptools/cppcompletionassistprovider.h>
@@ -39,7 +39,7 @@ class ClangCompletionAssistProvider : public CppTools::CppCompletionAssistProvid
Q_OBJECT
public:
ClangCompletionAssistProvider(IpcCommunicator &ipcCommunicator);
ClangCompletionAssistProvider(BackendCommunicator &communicator);
IAssistProvider::RunType runType() const override;
@@ -52,7 +52,7 @@ public:
TextEditor::AssistReason reason) const override;
private:
IpcCommunicator &m_ipcCommunicator;
BackendCommunicator &m_communicator;
};
} // namespace Internal
@@ -25,7 +25,7 @@
#include "clangeditordocumentprocessor.h"
#include "clangbackendipcintegration.h"
#include "clangbackendcommunicator.h"
#include "clangdiagnostictooltipwidget.h"
#include "clangfixitoperation.h"
#include "clangfixitoperationsextractor.h"
@@ -67,12 +67,12 @@ namespace ClangCodeModel {
namespace Internal {
ClangEditorDocumentProcessor::ClangEditorDocumentProcessor(
IpcCommunicator &ipcCommunicator,
BackendCommunicator &communicator,
TextEditor::TextDocument *document)
: BaseEditorDocumentProcessor(document->document(), document->filePath().toString())
, m_document(*document)
, m_diagnosticManager(document)
, m_ipcCommunicator(ipcCommunicator)
, m_communicator(communicator)
, m_parser(new ClangEditorDocumentParser(document->filePath().toString()))
, m_parserRevision(0)
, m_semanticHighlighter(document)
@@ -102,7 +102,7 @@ ClangEditorDocumentProcessor::~ClangEditorDocumentProcessor()
m_parserWatcher.waitForFinished();
if (m_projectPart) {
m_ipcCommunicator.unregisterTranslationUnitsForEditor(
m_communicator.unregisterTranslationUnitsForEditor(
{ClangBackEnd::FileContainer(filePath(), m_projectPart->id())});
}
}
@@ -343,7 +343,7 @@ ClangEditorDocumentProcessor::cursorInfo(const CppTools::CursorInfoParams &param
const CppTools::SemanticInfo::LocalUseMap localUses
= CppTools::BuiltinCursorInfo::findLocalUses(params.semanticInfo.doc, line, column);
return m_ipcCommunicator.requestReferences(simpleFileContainer(),
return m_communicator.requestReferences(simpleFileContainer(),
static_cast<quint32>(line),
static_cast<quint32>(column),
textDocument(),
@@ -392,7 +392,7 @@ ClangEditorDocumentProcessor::requestFollowSymbol(int line, int column)
dependentFiles = prioritizeByBaseName(filePath(), fileDeps);
}
return m_ipcCommunicator.requestFollowSymbol(simpleFileContainer(),
return m_communicator.requestFollowSymbol(simpleFileContainer(),
dependentFiles,
static_cast<quint32>(line),
static_cast<quint32>(column));
@@ -456,10 +456,10 @@ void ClangEditorDocumentProcessor::registerTranslationUnitForEditor(CppTools::Pr
if (m_projectPart) {
if (projectPart->id() == m_projectPart->id())
return;
m_ipcCommunicator.unregisterTranslationUnitsForEditor({fileContainerWithArguments()});
m_communicator.unregisterTranslationUnitsForEditor({fileContainerWithArguments()});
}
m_ipcCommunicator.registerTranslationUnitsForEditor(
m_communicator.registerTranslationUnitsForEditor(
{fileContainerWithArgumentsAndDocumentContent(projectPart)});
ClangCodeModel::Utils::setLastSentDocumentRevision(filePath(), revision());
}
@@ -469,7 +469,7 @@ void ClangEditorDocumentProcessor::updateTranslationUnitIfProjectPartExists()
if (m_projectPart) {
const ClangBackEnd::FileContainer fileContainer = fileContainerWithDocumentContent(m_projectPart->id());
m_ipcCommunicator.updateTranslationUnitWithRevisionCheck(fileContainer);
m_communicator.updateTranslationUnitWithRevisionCheck(fileContainer);
}
}
@@ -477,7 +477,7 @@ void ClangEditorDocumentProcessor::requestDocumentAnnotations(const QString &pro
{
const auto fileContainer = fileContainerWithDocumentContent(projectpartId);
m_ipcCommunicator.requestDocumentAnnotations(fileContainer);
m_communicator.requestDocumentAnnotations(fileContainer);
}
CppTools::BaseEditorDocumentProcessor::HeaderErrorDiagnosticWidgetCreator
@@ -43,14 +43,14 @@ class FileContainer;
namespace ClangCodeModel {
namespace Internal {
class IpcCommunicator;
class BackendCommunicator;
class ClangEditorDocumentProcessor : public CppTools::BaseEditorDocumentProcessor
{
Q_OBJECT
public:
ClangEditorDocumentProcessor(IpcCommunicator &ipcCommunicator,
ClangEditorDocumentProcessor(BackendCommunicator &communicator,
TextEditor::TextDocument *document);
~ClangEditorDocumentProcessor();
@@ -114,7 +114,7 @@ private:
private:
TextEditor::TextDocument &m_document;
ClangDiagnosticManager m_diagnosticManager;
IpcCommunicator &m_ipcCommunicator;
BackendCommunicator &m_communicator;
QSharedPointer<ClangEditorDocumentParser> m_parser;
CppTools::ProjectPart::Ptr m_projectPart;
bool m_isProjectFile = false;
@@ -66,7 +66,7 @@ static CppTools::CppModelManager *cppModelManager()
}
ModelManagerSupportClang::ModelManagerSupportClang()
: m_completionAssistProvider(m_ipcCommunicator)
: m_completionAssistProvider(m_communicator)
{
QTC_CHECK(!m_instance);
m_instance = this;
@@ -96,7 +96,7 @@ ModelManagerSupportClang::ModelManagerSupportClang()
connect(modelManager, &CppTools::CppModelManager::projectPartsRemoved,
this, &ModelManagerSupportClang::onProjectPartsRemoved);
m_ipcCommunicator.registerFallbackProjectPart();
m_communicator.registerFallbackProjectPart();
}
ModelManagerSupportClang::~ModelManagerSupportClang()
@@ -117,12 +117,12 @@ CppTools::FollowSymbolInterface &ModelManagerSupportClang::followSymbolInterface
CppTools::BaseEditorDocumentProcessor *ModelManagerSupportClang::editorDocumentProcessor(
TextEditor::TextDocument *baseTextDocument)
{
return new ClangEditorDocumentProcessor(m_ipcCommunicator, baseTextDocument);
return new ClangEditorDocumentProcessor(m_communicator, baseTextDocument);
}
void ModelManagerSupportClang::onCurrentEditorChanged(Core::IEditor *)
{
m_ipcCommunicator.updateTranslationUnitVisiblity();
m_communicator.updateTranslationUnitVisiblity();
}
void ModelManagerSupportClang::connectTextDocumentToTranslationUnit(TextEditor::TextDocument *textDocument)
@@ -195,7 +195,7 @@ void ModelManagerSupportClang::onEditorOpened(Core::IEditor *editor)
void ModelManagerSupportClang::onEditorClosed(const QList<Core::IEditor *> &)
{
m_ipcCommunicator.updateTranslationUnitVisiblity();
m_communicator.updateTranslationUnitVisiblity();
}
void ModelManagerSupportClang::onCppDocumentAboutToReloadOnTranslationUnit()
@@ -210,7 +210,7 @@ void ModelManagerSupportClang::onCppDocumentReloadFinishedOnTranslationUnit(bool
if (success) {
TextEditor::TextDocument *textDocument = qobject_cast<TextEditor::TextDocument *>(sender());
connectToTextDocumentContentsChangedForTranslationUnit(textDocument);
m_ipcCommunicator.updateTranslationUnitWithRevisionCheck(textDocument);
m_communicator.updateTranslationUnitWithRevisionCheck(textDocument);
}
}
@@ -229,9 +229,9 @@ void ModelManagerSupportClang::onCppDocumentContentsChangedOnTranslationUnit(int
{
Core::IDocument *document = qobject_cast<Core::IDocument *>(sender());
m_ipcCommunicator.updateChangeContentStartPosition(document->filePath().toString(),
m_communicator.updateChangeContentStartPosition(document->filePath().toString(),
position);
m_ipcCommunicator.updateTranslationUnitIfNotCurrentDocument(document);
m_communicator.updateTranslationUnitIfNotCurrentDocument(document);
clearDiagnosticFixIts(document->filePath().toString());
}
@@ -248,14 +248,14 @@ void ModelManagerSupportClang::onCppDocumentReloadFinishedOnUnsavedFile(bool suc
if (success) {
TextEditor::TextDocument *textDocument = qobject_cast<TextEditor::TextDocument *>(sender());
connectToTextDocumentContentsChangedForUnsavedFile(textDocument);
m_ipcCommunicator.updateUnsavedFile(textDocument);
m_communicator.updateUnsavedFile(textDocument);
}
}
void ModelManagerSupportClang::onCppDocumentContentsChangedOnUnsavedFile()
{
Core::IDocument *document = qobject_cast<Core::IDocument *>(sender());
m_ipcCommunicator.updateUnsavedFile(document);
m_communicator.updateUnsavedFile(document);
}
void ModelManagerSupportClang::onAbstractEditorSupportContentsUpdated(const QString &filePath,
@@ -264,7 +264,7 @@ void ModelManagerSupportClang::onAbstractEditorSupportContentsUpdated(const QStr
QTC_ASSERT(!filePath.isEmpty(), return);
const QString mappedPath = m_uiHeaderOnDiskManager.createIfNeeded(filePath);
m_ipcCommunicator.updateUnsavedFile(mappedPath, content, 0);
m_communicator.updateUnsavedFile(mappedPath, content, 0);
}
void ModelManagerSupportClang::onAbstractEditorSupportRemoved(const QString &filePath)
@@ -274,7 +274,7 @@ void ModelManagerSupportClang::onAbstractEditorSupportRemoved(const QString &fil
if (!cppModelManager()->cppEditorDocument(filePath)) {
const QString mappedPath = m_uiHeaderOnDiskManager.remove(filePath);
const QString projectPartId = Utils::projectPartIdForFile(filePath);
m_ipcCommunicator.unregisterUnsavedFilesForEditor({{mappedPath, projectPartId}});
m_communicator.unregisterUnsavedFilesForEditor({{mappedPath, projectPartId}});
}
}
@@ -328,16 +328,16 @@ void ModelManagerSupportClang::onProjectPartsUpdated(ProjectExplorer::Project *p
const CppTools::ProjectInfo projectInfo = cppModelManager()->projectInfo(project);
QTC_ASSERT(projectInfo.isValid(), return);
m_ipcCommunicator.registerProjectsParts(projectInfo.projectParts());
m_ipcCommunicator.registerFallbackProjectPart();
m_communicator.registerProjectsParts(projectInfo.projectParts());
m_communicator.registerFallbackProjectPart();
}
void ModelManagerSupportClang::onProjectPartsRemoved(const QStringList &projectPartIds)
{
if (!projectPartIds.isEmpty()) {
unregisterTranslationUnitsWithProjectParts(projectPartIds);
m_ipcCommunicator.unregisterProjectPartsForEditor(projectPartIds);
m_ipcCommunicator.registerFallbackProjectPart();
m_communicator.unregisterProjectPartsForEditor(projectPartIds);
m_communicator.registerFallbackProjectPart();
}
}
@@ -363,7 +363,7 @@ void ModelManagerSupportClang::unregisterTranslationUnitsWithProjectParts(
{
const auto processors = clangProcessorsWithProjectParts(projectPartIds);
foreach (ClangEditorDocumentProcessor *processor, processors) {
m_ipcCommunicator.unregisterTranslationUnitsForEditor({processor->fileContainerWithArguments()});
m_communicator.unregisterTranslationUnitsForEditor({processor->fileContainerWithArguments()});
processor->clearProjectPart();
processor->run();
}
@@ -374,9 +374,9 @@ ModelManagerSupportClang *ModelManagerSupportClang::instance()
return m_instance;
}
IpcCommunicator &ModelManagerSupportClang::ipcCommunicator()
BackendCommunicator &ModelManagerSupportClang::communicator()
{
return m_ipcCommunicator;
return m_communicator;
}
QString ModelManagerSupportClang::dummyUiHeaderOnDiskPath(const QString &filePath) const
@@ -62,7 +62,7 @@ public:
TextEditor::TextDocument *baseTextDocument) override;
CppTools::FollowSymbolInterface &followSymbolInterface() override;
IpcCommunicator &ipcCommunicator();
BackendCommunicator &communicator();
QString dummyUiHeaderOnDiskDirPath() const;
QString dummyUiHeaderOnDiskPath(const QString &filePath) const;
@@ -102,7 +102,7 @@ private:
private:
UiHeaderOnDiskManager m_uiHeaderOnDiskManager;
IpcCommunicator m_ipcCommunicator;
BackendCommunicator m_communicator;
ClangCompletionAssistProvider m_completionAssistProvider;
std::unique_ptr<CppTools::FollowSymbolInterface> m_followSymbol;
};
@@ -170,7 +170,7 @@ void ClangStaticAnalyzerTool::startTool()
auto clangTool = new ClangStaticAnalyzerToolRunner(runControl, project->activeTarget());
m_stopAction->disconnect();
connect(m_stopAction, &QAction::triggered, runControl, [this, runControl] {
connect(m_stopAction, &QAction::triggered, runControl, [runControl] {
runControl->appendMessage(tr("Clang Static Analyzer stopped by user."),
NormalMessageFormat);
runControl->initiateStop();
@@ -58,18 +58,13 @@ namespace Internal {
// BuildDirManager:
// --------------------------------------------------------------------
BuildDirManager::BuildDirManager(CMakeBuildConfiguration *bc) :
m_buildConfiguration(bc)
{
QTC_ASSERT(bc, return);
}
BuildDirManager::BuildDirManager() = default;
BuildDirManager::~BuildDirManager() = default;
const Utils::FileName BuildDirManager::workDirectory() const
Utils::FileName BuildDirManager::workDirectory(const BuildDirParameters &parameters) const
{
const Utils::FileName bdir = m_buildConfiguration->buildDirectory();
const CMakeTool *cmake = CMakeKitInformation::cmakeTool(m_buildConfiguration->target()->kit());
const Utils::FileName bdir = parameters.buildDirectory;
const CMakeTool *cmake = parameters.cmakeTool;
if (bdir.exists()) {
return bdir;
} else {
@@ -102,21 +97,21 @@ void BuildDirManager::emitErrorOccured(const QString &message) const
m_isHandlingError = false;
}
void BuildDirManager::updateReaderType(std::function<void()> todo)
void BuildDirManager::updateReaderType(const BuildDirParameters &p,
std::function<void()> todo)
{
BuildDirReader::Parameters p(m_buildConfiguration);
p.buildDirectory = workDirectory();
if (!m_reader || !m_reader->isCompatible(p)) {
m_reader.reset(BuildDirReader::createReader(p));
connect(m_reader.get(), &BuildDirReader::configurationStarted,
this, &BuildDirManager::configurationStarted);
this, &BuildDirManager::parsingStarted);
connect(m_reader.get(), &BuildDirReader::dataAvailable,
this, &BuildDirManager::emitDataAvailable);
connect(m_reader.get(), &BuildDirReader::errorOccured,
this, &BuildDirManager::emitErrorOccured);
connect(m_reader.get(), &BuildDirReader::dirty, this, &BuildDirManager::becameDirty);
}
QTC_ASSERT(m_reader, return);
m_reader->setParameters(p);
if (m_reader->isReady())
@@ -125,27 +120,7 @@ void BuildDirManager::updateReaderType(std::function<void()> todo)
connect(m_reader.get(), &BuildDirReader::isReadyNow, this, todo);
}
void BuildDirManager::updateReaderData()
{
BuildDirReader::Parameters p(m_buildConfiguration);
p.buildDirectory = workDirectory();
m_reader->setParameters(p);
}
void BuildDirManager::parseOnceReaderReady(bool force, bool checkForChanges)
{
TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
m_buildTargets.clear();
m_cmakeCache.clear();
if (checkForChanges)
checkConfiguration();
m_reader->stop();
m_reader->parse(force);
}
void BuildDirManager::maybeForceReparseOnceReaderReady()
bool BuildDirManager::hasConfigChanged()
{
checkConfiguration();
@@ -158,14 +133,13 @@ void BuildDirManager::maybeForceReparseOnceReaderReady()
const QByteArrayList criticalKeys
= {GENERATOR_KEY, CMAKE_COMMAND_KEY, CMAKE_C_COMPILER_KEY, CMAKE_CXX_COMPILER_KEY};
const CMakeConfig currentConfig = parsedConfiguration();
const CMakeConfig currentConfig = takeCMakeConfiguration();
Kit *k = m_buildConfiguration->target()->kit();
const CMakeTool *tool = CMakeKitInformation::cmakeTool(k);
QTC_ASSERT(tool, return); // No cmake... we should not have ended up here in the first place
const QString extraKitGenerator = CMakeGeneratorKitInformation::extraGenerator(k);
const QString mainKitGenerator = CMakeGeneratorKitInformation::generator(k);
CMakeConfig targetConfig = m_buildConfiguration->cmakeConfiguration();
const CMakeTool *tool = m_parameters.cmakeTool;
QTC_ASSERT(tool, return false); // No cmake... we should not have ended up here in the first place
const QString extraKitGenerator = m_parameters.extraGenerator;
const QString mainKitGenerator = m_parameters.generator;
CMakeConfig targetConfig = m_parameters.configuration;
targetConfig.append(CMakeConfigItem(GENERATOR_KEY, CMakeConfigItem::INTERNAL,
QByteArray(), mainKitGenerator.toUtf8()));
if (!extraKitGenerator.isEmpty())
@@ -184,7 +158,7 @@ void BuildDirManager::maybeForceReparseOnceReaderReady()
if (ccit->value != kcit->value) {
if (criticalKeys.contains(kcit->key)) {
clearCache();
return;
return false; // no need to trigger a new reader, clearCache will do that
}
mustReparse = true;
}
@@ -204,8 +178,7 @@ void BuildDirManager::maybeForceReparseOnceReaderReady()
//
// The critical keys *must* be set in cmake configuration, so those were already
// handled above.
if (mustReparse || kcit != targetConfig.constEnd())
emit requestReparse(true);
return mustReparse || kcit != targetConfig.constEnd();
}
bool BuildDirManager::isParsing() const
@@ -213,83 +186,96 @@ bool BuildDirManager::isParsing() const
return m_reader && m_reader->isParsing();
}
void BuildDirManager::setParametersAndRequestParse(const BuildDirParameters &parameters,
int newReaderReparseOptions,
int existingReaderReparseOptions)
{
QTC_ASSERT(parameters.isValid(), return);
if (m_reader)
m_reader->stop();
BuildDirReader *old = m_reader.get();
m_parameters = parameters;
m_parameters.buildDirectory = workDirectory(parameters);
updateReaderType(m_parameters,
[this, old, newReaderReparseOptions, existingReaderReparseOptions]() {
if (old != m_reader.get())
emit requestReparse(newReaderReparseOptions);
else
emit requestReparse(existingReaderReparseOptions);
});
}
CMakeBuildConfiguration *BuildDirManager::buildConfiguration() const
{
return m_parameters.buildConfiguration;
}
void BuildDirManager::becameDirty()
{
if (isParsing())
return;
Target *t = m_buildConfiguration->target()->project()->activeTarget();
BuildConfiguration *bc = t ? t->activeBuildConfiguration() : nullptr;
if (bc != m_buildConfiguration)
if (!m_parameters.buildConfiguration || !m_parameters.buildConfiguration->isActive())
return;
const CMakeTool *tool = CMakeKitInformation::cmakeTool(m_buildConfiguration->target()->kit());
const CMakeTool *tool = m_parameters.cmakeTool;
if (!tool->isAutoRun())
return;
emit requestReparse(false);
}
void BuildDirManager::forceReparse()
{
forceReparseImpl(true);
}
void BuildDirManager::forceReparseWithoutCheckingForChanges()
{
forceReparseImpl(false);
}
void BuildDirManager::forceReparseImpl(bool checkForChanges)
{
QTC_ASSERT(!m_isHandlingError, return);
if (m_buildConfiguration->target()->activeBuildConfiguration() != m_buildConfiguration)
return;
CMakeTool *tool = CMakeKitInformation::cmakeTool(m_buildConfiguration->target()->kit());
QTC_ASSERT(tool, return);
m_reader.reset(); // Force reparse by forcing in a new reader
updateReaderType([this, checkForChanges]() { parseOnceReaderReady(true, checkForChanges); });
emit requestReparse(REPARSE_CHECK_CONFIGURATION);
}
void BuildDirManager::resetData()
{
QTC_ASSERT(!m_isHandlingError, return);
if (m_reader)
m_reader->resetData();
m_cmakeCache.clear();
m_reader.reset();
m_buildTargets.clear();
}
bool BuildDirManager::persistCMakeState()
{
QTC_ASSERT(m_parameters.isValid(), return false);
if (!m_tempDir)
return false;
const QString buildDir = m_buildConfiguration->buildDirectory().toString();
QDir dir(buildDir);
dir.mkpath(buildDir);
const Utils::FileName buildDir = m_parameters.buildDirectory;
QDir dir(buildDir.toString());
dir.mkpath(buildDir.toString());
m_tempDir.reset(nullptr);
QTimer::singleShot(0, this, &BuildDirManager::parse); // make sure signals only happen afterwards!
emit requestReparse(REPARSE_URGENT | REPARSE_FORCE_CONFIGURATION | REPARSE_CHECK_CONFIGURATION);
return true;
}
void BuildDirManager::generateProjectTree(CMakeProjectNode *root, const QList<const FileNode *> &allFiles)
void BuildDirManager::parse(int reparseParameters)
{
QTC_ASSERT(m_parameters.isValid(), return);
QTC_ASSERT(m_reader, return);
QTC_ASSERT((reparseParameters & REPARSE_FAIL) == 0, return);
QTC_ASSERT((reparseParameters & REPARSE_IGNORE) == 0, return);
m_reader->stop();
TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
if (reparseParameters & REPARSE_CHECK_CONFIGURATION) {
if (checkConfiguration())
reparseParameters |= REPARSE_FORCE_CONFIGURATION;
}
m_reader->parse(reparseParameters & REPARSE_FORCE_CONFIGURATION);
}
void BuildDirManager::generateProjectTree(CMakeProjectNode *root, const QList<const FileNode *> &allFiles) const
{
QTC_ASSERT(!m_isHandlingError, return);
QTC_ASSERT(m_reader, return);
const Utils::FileName projectFile = m_buildConfiguration->target()->project()->projectFilePath();
m_reader->generateProjectTree(root, allFiles);
}
@@ -300,17 +286,13 @@ void BuildDirManager::updateCodeModel(CppTools::RawProjectParts &rpps)
return m_reader->updateCodeModel(rpps);
}
void BuildDirManager::parse()
{
updateReaderType([this]() { parseOnceReaderReady(false); });
}
void BuildDirManager::clearCache()
{
QTC_ASSERT(m_parameters.isValid(), return);
QTC_ASSERT(!m_isHandlingError, return);
auto cmakeCache = Utils::FileName(workDirectory()).appendPath(QLatin1String("CMakeCache.txt"));
auto cmakeFiles = Utils::FileName(workDirectory()).appendPath(QLatin1String("CMakeFiles"));
auto cmakeCache = workDirectory(m_parameters).appendPath("CMakeCache.txt");
auto cmakeFiles = workDirectory(m_parameters).appendPath("CMakeFiles");
const bool mustCleanUp = cmakeCache.exists() || cmakeFiles.exists();
if (!mustCleanUp)
@@ -319,7 +301,7 @@ void BuildDirManager::clearCache()
Utils::FileUtils::removeRecursively(cmakeCache);
Utils::FileUtils::removeRecursively(cmakeFiles);
forceReparse();
m_reader.reset();
}
static CMakeBuildTarget utilityTarget(const QString &title, const BuildDirManager *bdm)
@@ -334,44 +316,41 @@ static CMakeBuildTarget utilityTarget(const QString &title, const BuildDirManage
return target;
}
QList<CMakeBuildTarget> BuildDirManager::buildTargets() const
QList<CMakeBuildTarget> BuildDirManager::takeBuildTargets() const
{
QTC_ASSERT(!m_isHandlingError, return {});
QList<CMakeBuildTarget> result = { utilityTarget(CMakeBuildStep::allTarget(), this),
utilityTarget(CMakeBuildStep::cleanTarget(), this),
utilityTarget(CMakeBuildStep::installTarget(), this),
utilityTarget(CMakeBuildStep::testTarget(), this) };
QTC_ASSERT(!m_isHandlingError, return result);
if (!m_reader)
return QList<CMakeBuildTarget>();
if (m_buildTargets.isEmpty()) {
m_buildTargets.append(utilityTarget(CMakeBuildStep::allTarget(), this));
m_buildTargets.append(utilityTarget(CMakeBuildStep::cleanTarget(), this));
m_buildTargets.append(utilityTarget(CMakeBuildStep::installTarget(), this));
m_buildTargets.append(utilityTarget(CMakeBuildStep::testTarget(), this));
m_buildTargets.append(Utils::filtered(m_reader->buildTargets(), [](const CMakeBuildTarget &bt) {
if (m_reader) {
result.append(Utils::filtered(m_reader->takeBuildTargets(), [](const CMakeBuildTarget &bt) {
return bt.title != CMakeBuildStep::allTarget()
&& bt.title != CMakeBuildStep::cleanTarget()
&& bt.title != CMakeBuildStep::installTarget()
&& bt.title != CMakeBuildStep::testTarget();
}));
}
return m_buildTargets;
return result;
}
CMakeConfig BuildDirManager::parsedConfiguration() const
CMakeConfig BuildDirManager::takeCMakeConfiguration() const
{
QTC_ASSERT(!m_isHandlingError, return {});
if (!m_reader)
return m_cmakeCache;
if (m_cmakeCache.isEmpty())
m_cmakeCache = m_reader->takeParsedConfiguration();
return CMakeConfig();
for (auto &ci : m_cmakeCache)
CMakeConfig result = m_reader->takeParsedConfiguration();
for (auto &ci : result)
ci.inCMakeCache = true;
return m_cmakeCache;
return result;
}
CMakeConfig BuildDirManager::parseConfiguration(const Utils::FileName &cacheFile, QString *errorMessage)
CMakeConfig BuildDirManager::parseCMakeConfiguration(const Utils::FileName &cacheFile,
QString *errorMessage)
{
if (!cacheFile.exists()) {
if (errorMessage)
@@ -384,25 +363,26 @@ CMakeConfig BuildDirManager::parseConfiguration(const Utils::FileName &cacheFile
return result;
}
void BuildDirManager::checkConfiguration()
bool BuildDirManager::checkConfiguration()
{
if (m_tempDir) // always throw away changes in the tmpdir!
return;
QTC_ASSERT(m_parameters.isValid(), return false);
Kit *k = m_buildConfiguration->target()->kit();
const CMakeConfig cache = parsedConfiguration();
if (m_tempDir) // always throw away changes in the tmpdir!
return false;
const CMakeConfig cache = m_parameters.buildConfiguration->configurationFromCMake();
if (cache.isEmpty())
return; // No cache file yet.
return false; // No cache file yet.
CMakeConfig newConfig;
QSet<QString> changedKeys;
QSet<QString> removedKeys;
foreach (const CMakeConfigItem &iBc, m_buildConfiguration->cmakeConfiguration()) {
foreach (const CMakeConfigItem &iBc, m_parameters.configuration) {
const CMakeConfigItem &iCache
= Utils::findOrDefault(cache, [&iBc](const CMakeConfigItem &i) { return i.key == iBc.key; });
if (iCache.isNull()) {
removedKeys << QString::fromUtf8(iBc.key);
} else if (QString::fromUtf8(iCache.value) != iBc.expandedValue(k)) {
} else if (QString::fromUtf8(iCache.value) != iBc.expandedValue(m_parameters.expander)) {
changedKeys << QString::fromUtf8(iBc.key);
newConfig.append(iCache);
} else {
@@ -435,22 +415,15 @@ void BuildDirManager::checkConfiguration()
box->setDefaultButton(defaultButton);
box->exec();
if (box->clickedButton() == applyButton)
m_buildConfiguration->setCMakeConfiguration(newConfig);
if (box->clickedButton() == applyButton) {
m_parameters.configuration = newConfig;
QSignalBlocker blocker(m_parameters.buildConfiguration);
m_parameters.buildConfiguration->setConfigurationForCMake(newConfig);
return false;
} else if (box->clickedButton() == defaultButton)
return true;
}
}
void BuildDirManager::maybeForceReparse()
{
if (m_isHandlingError)
return;
if (!m_reader || !m_reader->hasData()) {
emit requestReparse(true);
return;
}
updateReaderType([this]() { maybeForceReparseOnceReaderReady(); });
return false;
}
} // namespace Internal
@@ -25,9 +25,13 @@
#pragma once
#include "builddirparameters.h"
#include "builddirreader.h"
#include "cmakebuildtarget.h"
#include "cmakeconfigitem.h"
#include <cpptools/cpprawprojectpart.h>
#include <utils/fileutils.h>
#include <utils/temporarydirectory.h>
@@ -37,12 +41,7 @@
#include <functional>
#include <memory>
namespace ProjectExplorer {
class FileNode;
class IOutputParser;
class Kit;
class Task;
} // namespace ProjectExplorer
namespace ProjectExplorer { class FileNode; }
namespace CMakeProjectManager {
@@ -50,6 +49,7 @@ class CMakeTool;
namespace Internal {
class CMakeProjectNode;
class CMakeBuildConfiguration;
class BuildDirManager : public QObject
@@ -57,61 +57,63 @@ class BuildDirManager : public QObject
Q_OBJECT
public:
BuildDirManager(CMakeBuildConfiguration *bc);
BuildDirManager();
~BuildDirManager() final;
bool isParsing() const;
void setParametersAndRequestParse(const BuildDirParameters &parameters,
int newReaderReparseOptions, int existingReaderReparseOptions);
CMakeBuildConfiguration *buildConfiguration() const;
void clearCache();
void forceReparse();
void forceReparseWithoutCheckingForChanges();
void maybeForceReparse(); // Only reparse if the configuration has changed...
void resetData();
bool persistCMakeState();
void parse(int reparseParameters);
void generateProjectTree(CMakeProjectNode *root,
const QList<const ProjectExplorer::FileNode *> &allFiles);
const QList<const ProjectExplorer::FileNode *> &allFiles) const;
void updateCodeModel(CppTools::RawProjectParts &rpps);
QList<CMakeBuildTarget> buildTargets() const;
CMakeConfig parsedConfiguration() const;
QList<CMakeBuildTarget> takeBuildTargets() const;
CMakeConfig takeCMakeConfiguration() const;
static CMakeConfig parseConfiguration(const Utils::FileName &cacheFile,
static CMakeConfig parseCMakeConfiguration(const Utils::FileName &cacheFile,
QString *errorMessage);
CMakeBuildConfiguration *buildConfiguration() const { return m_buildConfiguration; }
enum ReparseParameters { REPARSE_DEFAULT = 0, // use defaults
REPARSE_URGENT = 1, // Do not wait for more requests, start ASAP
REPARSE_FORCE_CONFIGURATION = 2, // Force configuration arguments to cmake
REPARSE_CHECK_CONFIGURATION = 4, // Check and warn if on-disk config and QtC config differ
REPARSE_IGNORE = 8, // Do not reparse:-)
REPARSE_FAIL = 16 // Do not reparse and raise a warning
};
signals:
void requestReparse(bool urgent) const;
void configurationStarted() const;
void requestReparse(int reparseParameters) const;
void parsingStarted() const;
void dataAvailable() const;
void errorOccured(const QString &err) const;
private:
void emitDataAvailable();
void emitErrorOccured(const QString &message) const;
void checkConfiguration();
bool checkConfiguration();
const Utils::FileName workDirectory() const;
Utils::FileName workDirectory(const BuildDirParameters &parameters) const;
void updateReaderType(std::function<void()> todo);
void updateReaderData();
void updateReaderType(const BuildDirParameters &p, std::function<void()> todo);
void forceReparseImpl(bool checkForChanges);
void parseOnceReaderReady(bool force, bool checkForChanges = true);
void maybeForceReparseOnceReaderReady();
bool hasConfigChanged();
void parse();
void becameDirty();
CMakeBuildConfiguration *m_buildConfiguration = nullptr;
BuildDirParameters m_parameters;
mutable std::unique_ptr<Utils::TemporaryDirectory> m_tempDir = nullptr;
mutable CMakeConfig m_cmakeCache;
std::unique_ptr<BuildDirReader> m_reader;
mutable QList<CMakeBuildTarget> m_buildTargets;
mutable std::unique_ptr<BuildDirReader> m_reader;
mutable bool m_isHandlingError = false;
};
@@ -0,0 +1,82 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "builddirparameters.h"
#include "cmakebuildconfiguration.h"
#include "cmakekitinformation.h"
#include <projectexplorer/kit.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
using namespace ProjectExplorer;
namespace CMakeProjectManager {
namespace Internal {
BuildDirParameters::BuildDirParameters() = default;
BuildDirParameters::BuildDirParameters(CMakeBuildConfiguration *bc)
{
buildConfiguration = bc;
const Kit *k = bc->target()->kit();
projectName = bc->target()->project()->displayName();
sourceDirectory = bc->target()->project()->projectDirectory();
buildDirectory = bc->buildDirectory();
environment = bc->environment();
cmakeTool = CMakeKitInformation::cmakeTool(k);
auto tc = ToolChainKitInformation::toolChain(k, Constants::CXX_LANGUAGE_ID);
if (tc)
cxxToolChainId = tc->id();
tc = ToolChainKitInformation::toolChain(k, Constants::C_LANGUAGE_ID);
if (tc)
cToolChainId = tc->id();
sysRoot = SysRootKitInformation::sysRoot(k);
expander = k->macroExpander();
configuration = bc->configurationForCMake();
generator = CMakeGeneratorKitInformation::generator(k);
extraGenerator = CMakeGeneratorKitInformation::extraGenerator(k);
platform = CMakeGeneratorKitInformation::platform(k);
toolset = CMakeGeneratorKitInformation::toolset(k);
generatorArguments = CMakeGeneratorKitInformation::generatorArguments(k);
}
bool BuildDirParameters::isValid() const { return buildConfiguration && cmakeTool; }
BuildDirParameters::BuildDirParameters(const BuildDirParameters &) = default;
} // namespace Internal
} // namespace CMakeProjectManager
@@ -0,0 +1,75 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "cmakeconfigitem.h"
#include "cmaketool.h"
#include <utils/environment.h>
#include <utils/fileutils.h>
#include <utils/macroexpander.h>
#include <QString>
namespace CMakeProjectManager {
namespace Internal {
class CMakeBuildConfiguration;
class BuildDirParameters {
public:
BuildDirParameters();
BuildDirParameters(CMakeBuildConfiguration *bc);
BuildDirParameters(const BuildDirParameters &other);
bool isValid() const;
CMakeBuildConfiguration *buildConfiguration = nullptr;
QString projectName;
Utils::FileName sourceDirectory;
Utils::FileName buildDirectory;
Utils::Environment environment;
CMakeTool *cmakeTool = nullptr;
QByteArray cxxToolChainId;
QByteArray cToolChainId;
Utils::FileName sysRoot;
Utils::MacroExpander *expander = nullptr;
CMakeConfig configuration;
QString generator;
QString extraGenerator;
QString platform;
QString toolset;
QStringList generatorArguments;
};
} // namespace Internal
} // namespace CMakeProjectManager
@@ -25,14 +25,10 @@
#include "builddirreader.h"
#include "cmakebuildconfiguration.h"
#include "cmakekitinformation.h"
#include "servermodereader.h"
#include "tealeafreader.h"
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
#include <utils/qtcassert.h>
using namespace ProjectExplorer;
@@ -43,57 +39,15 @@ namespace Internal {
// BuildDirReader:
// --------------------------------------------------------------------
BuildDirReader::Parameters::Parameters() = default;
BuildDirReader::Parameters::Parameters(const CMakeBuildConfiguration *bc)
BuildDirReader *BuildDirReader::createReader(const BuildDirParameters &p)
{
const ProjectExplorer::Kit *k = bc->target()->kit();
projectName = bc->target()->project()->displayName();
sourceDirectory = bc->target()->project()->projectDirectory();
buildDirectory = bc->buildDirectory();
environment = bc->environment();
CMakeTool *cmake = CMakeKitInformation::cmakeTool(k);
cmakeVersion = cmake->version();
cmakeHasServerMode = cmake->hasServerMode();
cmakeExecutable = cmake->cmakeExecutable();
pathMapper = cmake->pathMapper();
isAutorun = cmake->isAutoRun();
auto tc = ProjectExplorer::ToolChainKitInformation::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
if (tc)
cxxToolChainId = tc->id();
tc = ProjectExplorer::ToolChainKitInformation::toolChain(k, ProjectExplorer::Constants::C_LANGUAGE_ID);
if (tc)
cToolChainId = tc->id();
sysRoot = ProjectExplorer::SysRootKitInformation::sysRoot(k);
expander = k->macroExpander();
configuration = bc->cmakeConfiguration();
generator = CMakeGeneratorKitInformation::generator(k);
extraGenerator = CMakeGeneratorKitInformation::extraGenerator(k);
platform = CMakeGeneratorKitInformation::platform(k);
toolset = CMakeGeneratorKitInformation::toolset(k);
generatorArguments = CMakeGeneratorKitInformation::generatorArguments(k);
}
BuildDirReader::Parameters::Parameters(const BuildDirReader::Parameters &) = default;
BuildDirReader *BuildDirReader::createReader(const BuildDirReader::Parameters &p)
{
if (p.cmakeHasServerMode)
QTC_ASSERT(p.isValid() && p.cmakeTool, return nullptr);
if (p.cmakeTool->hasServerMode())
return new ServerModeReader;
return new TeaLeafReader;
}
void BuildDirReader::setParameters(const BuildDirReader::Parameters &p)
void BuildDirReader::setParameters(const BuildDirParameters &p)
{
m_parameters = p;
}
@@ -25,8 +25,9 @@
#pragma once
#include "builddirparameters.h"
#include "cmakebuildtarget.h"
#include "cmakeconfigitem.h"
#include "cmakeproject.h"
#include "cmaketool.h"
#include <cpptools/cpprawprojectpart.h>
@@ -38,6 +39,8 @@
#include <QFutureInterface>
#include <QObject>
namespace ProjectExplorer { class FileNode; }
namespace CMakeProjectManager {
namespace Internal {
@@ -49,52 +52,19 @@ class BuildDirReader : public QObject
Q_OBJECT
public:
struct Parameters {
Parameters();
Parameters(const CMakeBuildConfiguration *bc);
Parameters(const Parameters &other);
static BuildDirReader *createReader(const BuildDirParameters &p);
virtual void setParameters(const BuildDirParameters &p);
QString projectName;
Utils::FileName sourceDirectory;
Utils::FileName buildDirectory;
Utils::Environment environment;
Utils::FileName cmakeExecutable;
CMakeTool::Version cmakeVersion;
bool cmakeHasServerMode = false;
CMakeTool::PathMapper pathMapper;
QByteArray cxxToolChainId;
QByteArray cToolChainId;
Utils::FileName sysRoot;
Utils::MacroExpander *expander = nullptr;
CMakeConfig configuration;
QString generator;
QString extraGenerator;
QString platform;
QString toolset;
QStringList generatorArguments;
bool isAutorun = false;
};
static BuildDirReader *createReader(const BuildDirReader::Parameters &p);
virtual void setParameters(const Parameters &p);
virtual bool isCompatible(const Parameters &p) = 0;
virtual bool isCompatible(const BuildDirParameters &p) = 0;
virtual void resetData() = 0;
virtual void parse(bool force) = 0;
virtual void parse(bool forceConfiguration) = 0;
virtual void stop() = 0;
virtual bool isReady() const { return true; }
virtual bool isParsing() const = 0;
virtual bool hasData() const = 0;
virtual QList<CMakeBuildTarget> takeBuildTargets() = 0;
virtual CMakeConfig takeParsedConfiguration() = 0;
virtual QList<CMakeBuildTarget> buildTargets() const = 0;
virtual void generateProjectTree(CMakeProjectNode *root,
const QList<const ProjectExplorer::FileNode *> &allFiles) = 0;
virtual void updateCodeModel(CppTools::RawProjectParts &rpps) = 0;
@@ -107,7 +77,7 @@ signals:
void errorOccured(const QString &message) const;
protected:
Parameters m_parameters;
BuildDirParameters m_parameters;
};
} // namespace Internal
@@ -64,17 +64,11 @@ const char INITIAL_ARGUMENTS[] = "CMakeProjectManager.CMakeBuildConfiguration.In
const char CONFIGURATION_KEY[] = "CMake.Configuration";
CMakeBuildConfiguration::CMakeBuildConfiguration(ProjectExplorer::Target *parent) :
BuildConfiguration(parent, Core::Id(Constants::CMAKE_BC_ID)),
m_buildDirManager(new BuildDirManager(this))
BuildConfiguration(parent, Core::Id(Constants::CMAKE_BC_ID))
{
ctor();
}
CMakeBuildConfiguration::~CMakeBuildConfiguration()
{
m_buildDirManager->deleteLater(); // Do not block while waiting for cmake...
}
bool CMakeBuildConfiguration::isEnabled() const
{
return m_error.isEmpty() && !isParsing();
@@ -88,8 +82,7 @@ QString CMakeBuildConfiguration::disabledReason() const
CMakeBuildConfiguration::CMakeBuildConfiguration(ProjectExplorer::Target *parent,
CMakeBuildConfiguration *source) :
BuildConfiguration(parent, source),
m_configuration(source->m_configuration),
m_buildDirManager(new BuildDirManager(this))
m_configurationForCMake(source->m_configurationForCMake)
{
ctor();
cloneSteps(source);
@@ -99,7 +92,7 @@ QVariantMap CMakeBuildConfiguration::toMap() const
{
QVariantMap map(ProjectExplorer::BuildConfiguration::toMap());
const QStringList config
= Utils::transform(m_configuration, [](const CMakeConfigItem &i) { return i.toString(); });
= Utils::transform(m_configurationForCMake, [](const CMakeConfigItem &i) { return i.toString(); });
map.insert(QLatin1String(CONFIGURATION_KEY), config);
return map;
}
@@ -130,110 +123,28 @@ bool CMakeBuildConfiguration::fromMap(const QVariantMap &map)
}
// End Legacy
setCMakeConfiguration(legacyConf + conf);
setConfigurationForCMake(legacyConf + conf);
return true;
}
void CMakeBuildConfiguration::ctor()
{
auto project = static_cast<CMakeProject *>(target()->project());
setBuildDirectory(shadowBuildDirectory(project->projectFilePath(),
auto p = static_cast<CMakeProject *>(project());
setBuildDirectory(shadowBuildDirectory(p->projectFilePath(),
target()->kit(),
displayName(), BuildConfiguration::Unknown));
connect(m_buildDirManager.get(), &BuildDirManager::requestReparse,
this, [this](bool urgent) { emit requestReparse(this, urgent); });
connect(m_buildDirManager.get(), &BuildDirManager::dataAvailable,
this, [this, project]() {
clearError();
project->handleParsingSuccess(this);
});
connect(m_buildDirManager.get(), &BuildDirManager::errorOccured,
this, [this, project](const QString &msg) {
setError(msg);
project->handleParsingError(this);
});
connect(m_buildDirManager.get(), &BuildDirManager::configurationStarted,
this, [this]() {
clearError(ForceEnabledChanged::True);
emit parsingStarted(this);
});
connect(this, &CMakeBuildConfiguration::environmentChanged,
m_buildDirManager.get(), &BuildDirManager::forceReparse);
connect(this, &CMakeBuildConfiguration::buildDirectoryChanged,
m_buildDirManager.get(), &BuildDirManager::forceReparse);
}
void CMakeBuildConfiguration::maybeForceReparse()
{
clearError();
m_buildDirManager->maybeForceReparse();
connect(p, &Project::parsingFinished, this, &BuildConfiguration::enabledChanged);
}
bool CMakeBuildConfiguration::isParsing() const
{
return m_buildDirManager && m_buildDirManager->isParsing();
}
void CMakeBuildConfiguration::resetData()
{
clearError();
m_buildDirManager->resetData();
}
bool CMakeBuildConfiguration::persistCMakeState()
{
return m_buildDirManager->persistCMakeState();
}
bool CMakeBuildConfiguration::updateCMakeStateBeforeBuild()
{
return static_cast<CMakeProject *>(project())->mustUpdateCMakeStateBeforeBuild();
}
void CMakeBuildConfiguration::runCMake()
{
if (!m_buildDirManager || m_buildDirManager->isParsing())
return;
clearError();
m_buildDirManager->forceReparse();
}
void CMakeBuildConfiguration::clearCache()
{
if (m_buildDirManager)
m_buildDirManager->clearCache();
return project()->isParsing() && isActive();
}
QList<CMakeBuildTarget> CMakeBuildConfiguration::buildTargets() const
{
if (!m_buildDirManager || m_buildDirManager->isParsing())
return QList<CMakeBuildTarget>();
return m_buildDirManager->buildTargets();
}
CMakeProjectNode *
CMakeBuildConfiguration::generateProjectTree(const QList<const FileNode*> &allFiles) const
{
if (!m_buildDirManager || m_buildDirManager->isParsing())
return nullptr;
auto root = new CMakeProjectNode(target()->project()->projectDirectory());
m_buildDirManager->generateProjectTree(root, allFiles);
if (root->isEmpty()) {
delete root;
return nullptr;
}
return root;
}
void CMakeBuildConfiguration::updateCodeModel(CppTools::RawProjectParts &rpps)
{
m_buildDirManager->updateCodeModel(rpps);
return m_buildTargets;
}
FileName CMakeBuildConfiguration::shadowBuildDirectory(const FileName &projectFilePath,
@@ -273,50 +184,23 @@ void CMakeBuildConfiguration::buildTarget(const QString &buildTarget)
cmBs->setBuildTarget(originalBuildTarget);
}
QList<ConfigModel::DataItem> CMakeBuildConfiguration::completeCMakeConfiguration() const
CMakeConfig CMakeBuildConfiguration::configurationFromCMake() const
{
if (!m_buildDirManager || m_buildDirManager->isParsing())
return QList<ConfigModel::DataItem>();
return Utils::transform(m_buildDirManager->parsedConfiguration(),
[](const CMakeConfigItem &i) {
ConfigModel::DataItem j;
j.key = QString::fromUtf8(i.key);
j.value = QString::fromUtf8(i.value);
j.description = QString::fromUtf8(i.documentation);
j.values = i.values;
j.inCMakeCache = i.inCMakeCache;
j.isAdvanced = i.isAdvanced;
j.isHidden = i.type == CMakeConfigItem::INTERNAL || i.type == CMakeConfigItem::STATIC;
switch (i.type) {
case CMakeConfigItem::FILEPATH:
j.type = ConfigModel::DataItem::FILE;
break;
case CMakeConfigItem::PATH:
j.type = ConfigModel::DataItem::DIRECTORY;
break;
case CMakeConfigItem::BOOL:
j.type = ConfigModel::DataItem::BOOLEAN;
break;
case CMakeConfigItem::STRING:
j.type = ConfigModel::DataItem::STRING;
break;
default:
j.type = ConfigModel::DataItem::UNKNOWN;
break;
}
return j;
});
return m_configurationFromCMake;
}
void CMakeBuildConfiguration::setCurrentCMakeConfiguration(const QList<ConfigModel::DataItem> &items)
void CMakeBuildConfiguration::setConfigurationFromCMake(const CMakeConfig &config)
{
if (!m_buildDirManager || m_buildDirManager->isParsing())
return;
m_configurationFromCMake = config;
}
void CMakeBuildConfiguration::setBuildTargets(const QList<CMakeBuildTarget> &targets)
{
m_buildTargets = targets;
}
void CMakeBuildConfiguration::setConfigurationForCMake(const QList<ConfigModel::DataItem> &items)
{
const CMakeConfig newConfig = Utils::transform(items, [](const ConfigModel::DataItem &i) {
CMakeConfigItem ni;
ni.key = i.key.toUtf8();
@@ -346,10 +230,8 @@ void CMakeBuildConfiguration::setCurrentCMakeConfiguration(const QList<ConfigMod
return ni;
});
const CMakeConfig config = cmakeConfiguration() + newConfig;
setCMakeConfiguration(config);
m_buildDirManager->forceReparseWithoutCheckingForChanges();
const CMakeConfig config = configurationForCMake() + newConfig;
setConfigurationForCMake(config);
}
void CMakeBuildConfiguration::clearError(ForceEnabledChanged fec)
@@ -383,14 +265,14 @@ static CMakeConfig removeDuplicates(const CMakeConfig &config)
return result;
}
void CMakeBuildConfiguration::setCMakeConfiguration(const CMakeConfig &config)
void CMakeBuildConfiguration::setConfigurationForCMake(const CMakeConfig &config)
{
m_configuration = removeDuplicates(config);
m_configurationForCMake = removeDuplicates(config);
const Kit *k = target()->kit();
CMakeConfig kitConfig = CMakeConfigurationKitInformation::configuration(k);
bool hasKitOverride = false;
foreach (const CMakeConfigItem &i, m_configuration) {
foreach (const CMakeConfigItem &i, m_configurationForCMake) {
const QString b = CMakeConfigItem::expandedValueOf(k, i.key, kitConfig);
if (!b.isNull() && i.expandedValue(k) != b) {
hasKitOverride = true;
@@ -402,11 +284,13 @@ void CMakeBuildConfiguration::setCMakeConfiguration(const CMakeConfig &config)
setWarning(tr("CMake configuration set by the kit was overridden in the project."));
else
setWarning(QString());
emit configurationForCMakeChanged();
}
CMakeConfig CMakeBuildConfiguration::cmakeConfiguration() const
CMakeConfig CMakeBuildConfiguration::configurationForCMake() const
{
return removeDuplicates(CMakeConfigurationKitInformation::configuration(target()->kit()) + m_configuration);
return removeDuplicates(CMakeConfigurationKitInformation::configuration(target()->kit()) + m_configurationForCMake);
}
void CMakeBuildConfiguration::setError(const QString &message)
@@ -528,9 +412,9 @@ QList<ProjectExplorer::BuildInfo *> CMakeBuildConfigurationFactory::availableSet
ProjectExplorer::BuildConfiguration *CMakeBuildConfigurationFactory::create(ProjectExplorer::Target *parent,
const ProjectExplorer::BuildInfo *info) const
{
QTC_ASSERT(info->factory() == this, return 0);
QTC_ASSERT(info->kitId == parent->kit()->id(), return 0);
QTC_ASSERT(!info->displayName.isEmpty(), return 0);
QTC_ASSERT(info->factory() == this, return nullptr);
QTC_ASSERT(info->kitId == parent->kit()->id(), return nullptr);
QTC_ASSERT(!info->displayName.isEmpty(), return nullptr);
CMakeBuildInfo copy(*static_cast<const CMakeBuildInfo *>(info));
CMakeProject *project = static_cast<CMakeProject *>(parent->project());
@@ -556,7 +440,7 @@ ProjectExplorer::BuildConfiguration *CMakeBuildConfigurationFactory::create(Proj
cleanSteps->insertStep(0, cleanStep);
bc->setBuildDirectory(copy.buildDirectory);
bc->setCMakeConfiguration(copy.configuration);
bc->setConfigurationForCMake(copy.configuration);
return bc;
}
@@ -571,7 +455,7 @@ bool CMakeBuildConfigurationFactory::canClone(const ProjectExplorer::Target *par
CMakeBuildConfiguration *CMakeBuildConfigurationFactory::clone(ProjectExplorer::Target *parent, ProjectExplorer::BuildConfiguration *source)
{
if (!canClone(parent, source))
return 0;
return nullptr;
auto old = static_cast<CMakeBuildConfiguration *>(source);
return new CMakeBuildConfiguration(parent, old);
}
@@ -586,12 +470,11 @@ bool CMakeBuildConfigurationFactory::canRestore(const ProjectExplorer::Target *p
CMakeBuildConfiguration *CMakeBuildConfigurationFactory::restore(ProjectExplorer::Target *parent, const QVariantMap &map)
{
if (!canRestore(parent, map))
return 0;
auto bc = new CMakeBuildConfiguration(parent);
return nullptr;
auto bc = std::make_unique<CMakeBuildConfiguration>(parent);
if (bc->fromMap(map))
return bc;
delete bc;
return 0;
return bc.release();
return nullptr;
}
bool CMakeBuildConfigurationFactory::canHandle(const ProjectExplorer::Target *t) const
@@ -52,11 +52,9 @@ class CMakeProjectNode;
class CMakeBuildConfiguration : public ProjectExplorer::BuildConfiguration
{
Q_OBJECT
friend class CMakeBuildConfigurationFactory;
public:
CMakeBuildConfiguration(ProjectExplorer::Target *parent);
~CMakeBuildConfiguration();
bool isEnabled() const override;
QString disabledReason() const override;
@@ -69,25 +67,13 @@ public:
void emitBuildTypeChanged();
void setCMakeConfiguration(const CMakeConfig &config);
bool hasCMakeConfiguration() const;
CMakeConfig cmakeConfiguration() const;
CMakeConfig configurationForCMake() const;
CMakeConfig configurationFromCMake() const;
QString error() const;
QString warning() const;
bool isParsing() const;
void maybeForceReparse();
void resetData();
bool persistCMakeState();
bool updateCMakeStateBeforeBuild();
void runCMake();
void clearCache();
QList<CMakeBuildTarget> buildTargets() const;
CMakeProjectManager::Internal::CMakeProjectNode *generateProjectTree(const QList<const ProjectExplorer::FileNode *> &allFiles) const;
void updateCodeModel(CppTools::RawProjectParts &rpps);
static Utils::FileName
shadowBuildDirectory(const Utils::FileName &projectFilePath, const ProjectExplorer::Kit *k,
@@ -97,12 +83,11 @@ public:
void buildTarget(const QString &buildTarget);
signals:
void requestReparse(CMakeBuildConfiguration *, bool isUrgent);
void parsingStarted(CMakeBuildConfiguration *);
void errorOccured(const QString &message);
void warningOccured(const QString &message);
void configurationForCMakeChanged();
protected:
CMakeBuildConfiguration(ProjectExplorer::Target *parent, CMakeBuildConfiguration *source);
bool fromMap(const QVariantMap &map) override;
@@ -110,22 +95,30 @@ protected:
private:
void ctor();
bool isParsing() const;
enum ForceEnabledChanged : quint8 { False, True };
void clearError(ForceEnabledChanged fec = ForceEnabledChanged::False);
QList<ConfigModel::DataItem> completeCMakeConfiguration() const;
void setCurrentCMakeConfiguration(const QList<ConfigModel::DataItem> &items);
void setBuildTargets(const QList<CMakeBuildTarget> &targets);
void setConfigurationFromCMake(const CMakeConfig &config);
void setConfigurationForCMake(const QList<ConfigModel::DataItem> &items);
void setConfigurationForCMake(const CMakeConfig &config);
void setError(const QString &message);
void setWarning(const QString &message);
CMakeConfig m_configuration;
CMakeConfig m_configurationForCMake;
QString m_error;
QString m_warning;
std::unique_ptr<BuildDirManager> m_buildDirManager;
CMakeConfig m_configurationFromCMake;
QList<CMakeBuildTarget> m_buildTargets;
friend class CMakeBuildConfigurationFactory;
friend class CMakeBuildSettingsWidget;
friend class CMakeProjectManager::CMakeProject;
friend class BuildDirManager;
};
class CMakeProjectImporter;
@@ -52,7 +52,7 @@ public:
QTC_ASSERT(bc->target()->project(), return);
sourceDirectory = bc->target()->project()->projectDirectory().toString();
configuration = bc->cmakeConfiguration();
configuration = bc->configurationForCMake();
}
bool operator==(const BuildInfo &o) const final
@@ -227,13 +227,13 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
if (m_buildConfiguration->isParsing())
m_showProgressTimer.start();
else {
m_configModel->setConfiguration(m_buildConfiguration->completeCMakeConfiguration());
m_configModel->setConfiguration(m_buildConfiguration->configurationFromCMake());
m_configView->expandAll();
}
connect(m_buildConfiguration->target()->project(), &ProjectExplorer::Project::parsingFinished,
connect(project, &ProjectExplorer::Project::parsingFinished,
this, [this, buildDirChooser, stretcher]() {
m_configModel->setConfiguration(m_buildConfiguration->completeCMakeConfiguration());
m_configModel->setConfiguration(m_buildConfiguration->configurationFromCMake());
m_configView->expandAll();
stretcher->stretch();
updateButtonState();
@@ -264,7 +264,7 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
connect(m_resetButton, &QPushButton::clicked, m_configModel, &ConfigModel::resetAllChanges);
connect(m_reconfigureButton, &QPushButton::clicked, this, [this]() {
m_buildConfiguration->setCurrentCMakeConfiguration(m_configModel->configurationChanges());
m_buildConfiguration->setConfigurationForCMake(m_configModel->configurationChanges());
});
connect(m_editButton, &QPushButton::clicked, this, [this]() {
QModelIndex idx = m_configView->currentIndex();
@@ -269,10 +269,11 @@ void CMakeBuildStep::run(QFutureInterface<bool> &fi)
QTC_ASSERT(bc, return);
bool mustDelay = false;
if (bc->persistCMakeState()) {
auto p = static_cast<CMakeProject *>(bc->project());
if (p->persistCMakeState()) {
emit addOutput(tr("Persisting CMake state..."), BuildStep::OutputFormat::NormalMessage);
mustDelay = true;
} else if (bc->updateCMakeStateBeforeBuild()) {
} else if (p->mustUpdateCMakeStateBeforeBuild()) {
emit addOutput(tr("Running CMake in preparation to build..."), BuildStep::OutputFormat::NormalMessage);
mustDelay = true;
} else {
@@ -0,0 +1,46 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "cmakebuildtarget.h"
using namespace Utils;
namespace CMakeProjectManager {
void CMakeBuildTarget::clear()
{
executable.clear();
makeCommand.clear();
workingDirectory.clear();
sourceDirectory.clear();
title.clear();
targetType = UtilityType;
includeFiles.clear();
compilerOptions.clear();
macros.clear();
files.clear();
}
} // namespace CMakeProjectManager
@@ -0,0 +1,64 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "cmake_global.h"
#include <projectexplorer/projectmacro.h>
#include <utils/fileutils.h>
#include <QStringList>
namespace CMakeProjectManager {
enum TargetType {
ExecutableType = 0,
StaticLibraryType = 2,
DynamicLibraryType = 3,
UtilityType = 64
};
class CMAKE_EXPORT CMakeBuildTarget
{
public:
QString title;
Utils::FileName executable; // TODO: rename to output?
TargetType targetType = UtilityType;
Utils::FileName workingDirectory;
Utils::FileName sourceDirectory;
Utils::FileName makeCommand;
// code model
QList<Utils::FileName> includeFiles;
QStringList compilerOptions;
ProjectExplorer::Macros macros;
QList<Utils::FileName> files;
void clear();
};
} // namespace CMakeProjectManager
+206 -101
View File
@@ -42,6 +42,7 @@
#include <projectexplorer/deploymentdata.h>
#include <projectexplorer/headerpath.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/kitmanager.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
#include <projectexplorer/toolchain.h>
@@ -66,6 +67,11 @@ namespace CMakeProjectManager {
using namespace Internal;
static CMakeBuildConfiguration *activeBc(const CMakeProject *p)
{
return qobject_cast<CMakeBuildConfiguration *>(p->activeTarget() ? p->activeTarget()->activeBuildConfiguration() : nullptr);
}
// QtCreator CMake Generator wishlist:
// Which make targets we need to build to get all executables
// What is the actual compiler executable
@@ -77,27 +83,129 @@ using namespace Internal;
CMakeProject::CMakeProject(const FileName &fileName) : Project(Constants::CMAKEMIMETYPE, fileName),
m_cppCodeModelUpdater(new CppTools::CppProjectUpdater(this))
{
m_delayedParsingTimer.setSingleShot(true);
connect(&m_delayedParsingTimer, &QTimer::timeout,
this, [this]() { startParsingProject(PARSE); });
setId(CMakeProjectManager::Constants::CMAKEPROJECT_ID);
setProjectContext(Core::Context(CMakeProjectManager::Constants::PROJECTCONTEXT));
setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID));
setDisplayName(projectDirectory().fileName());
connect(this, &Project::activeProjectConfigurationChanged,
this, &CMakeProject::handleActiveProjectConfigurationChanged);
// Timer:
m_delayedParsingTimer.setSingleShot(true);
subscribeSignal(&CMakeBuildConfiguration::requestReparse,
this, [this](CMakeBuildConfiguration *bc, bool isUrgent) {
if (bc->isActive()) {
m_delayedParsingTimer.setInterval(isUrgent ? 0 : 1000);
m_delayedParsingTimer.start();
connect(&m_delayedParsingTimer, &QTimer::timeout,
this, [this]() { startParsing(m_delayedParsingParameters); });
// BuildDirManager:
connect(&m_buildDirManager, &BuildDirManager::requestReparse,
this, &CMakeProject::handleReparseRequest);
connect(&m_buildDirManager, &BuildDirManager::dataAvailable,
this, [this]() {
CMakeBuildConfiguration *bc = activeBc(this);
if (bc && bc == m_buildDirManager.buildConfiguration()) {
bc->clearError();
handleParsingSuccess(bc);
}
});
connect(&m_buildDirManager, &BuildDirManager::errorOccured,
this, [this](const QString &msg) {
CMakeBuildConfiguration *bc = activeBc(this);
if (bc && bc == m_buildDirManager.buildConfiguration()) {
bc->setError(msg);
handleParsingError(bc);
}
});
connect(&m_buildDirManager, &BuildDirManager::parsingStarted,
this, [this]() {
CMakeBuildConfiguration *bc = activeBc(this);
if (bc && bc == m_buildDirManager.buildConfiguration())
bc->clearError(CMakeBuildConfiguration::ForceEnabledChanged::True);
});
// Kit changed:
connect(KitManager::instance(), &KitManager::kitUpdated,
this, [this](Kit *k) {
CMakeBuildConfiguration *bc = activeBc(this);
if (!bc || k != bc->target()->kit())
return; // not for us...
// Build configuration has not changed, but Kit settings might have:
// reparse and check the configuration, independent of whether the reader has changed
m_buildDirManager.setParametersAndRequestParse(
BuildDirParameters(bc),
BuildDirManager::REPARSE_CHECK_CONFIGURATION,
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
});
// Target switched:
connect(this, &Project::activeTargetChanged, this, [this]() {
CMakeBuildConfiguration *bc = activeBc(this);
// Target has switched, so the kit has changed, too.
// * run cmake with configuration arguments if the reader needs to be switched
// * run cmake without configuration arguments if the reader stays
m_buildDirManager.setParametersAndRequestParse(
BuildDirParameters(bc),
BuildDirManager::REPARSE_CHECK_CONFIGURATION,
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
});
// BuildConfiguration switched:
subscribeSignal(&Target::activeBuildConfigurationChanged, this, [this]() {
CMakeBuildConfiguration *bc = activeBc(this);
// Build configuration has switched:
// * Error out if the reader updates, can not happen since all BCs share a target/kit.
// * run cmake without configuration arguments if the reader stays
m_buildDirManager.setParametersAndRequestParse(
BuildDirParameters(bc),
BuildDirManager::REPARSE_FAIL,
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
});
// BuildConfiguration changed:
subscribeSignal(&CMakeBuildConfiguration::environmentChanged, this, [this]() {
auto senderBc = qobject_cast<CMakeBuildConfiguration *>(sender());
if (senderBc && senderBc->isActive()) {
// The environment on our BC has changed:
// * Error out if the reader updates, can not happen since all BCs share a target/kit.
// * run cmake without configuration arguments if the reader stays
m_buildDirManager.setParametersAndRequestParse(
BuildDirParameters(senderBc),
BuildDirManager::REPARSE_FAIL,
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
}
});
subscribeSignal(&CMakeBuildConfiguration::buildDirectoryChanged, this, [this]() {
auto senderBc = qobject_cast<CMakeBuildConfiguration *>(sender());
if (senderBc && senderBc->isActive() && senderBc == m_buildDirManager.buildConfiguration()) {
// The build directory of our BC has changed:
// * Error out if the reader updates, can not happen since all BCs share a target/kit.
// * run cmake without configuration arguments if the reader stays
// If no configuration exists, then the arguments will get added automatically by
// the reader.
m_buildDirManager.setParametersAndRequestParse(
BuildDirParameters(senderBc),
BuildDirManager::REPARSE_FAIL,
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
}
});
subscribeSignal(&CMakeBuildConfiguration::configurationForCMakeChanged, this, [this]() {
auto senderBc = qobject_cast<CMakeBuildConfiguration *>(sender());
if (senderBc && senderBc->isActive() && senderBc == m_buildDirManager.buildConfiguration()) {
// The CMake configuration has changed on our BC:
// * Error out if the reader updates, can not happen since all BCs share a target/kit.
// * run cmake with configuration arguments if the reader stays
m_buildDirManager.setParametersAndRequestParse(
BuildDirParameters(senderBc),
BuildDirManager::REPARSE_FAIL,
BuildDirManager::REPARSE_FORCE_CONFIGURATION);
}
});
// TreeScanner:
connect(&m_treeScanner, &TreeScanner::finished, this, &CMakeProject::handleTreeScanningFinished);
m_treeScanner.setFilter([this](const Utils::MimeType &mimeType, const Utils::FileName &fn) {
@@ -148,15 +256,19 @@ CMakeProject::~CMakeProject()
void CMakeProject::updateProjectData(CMakeBuildConfiguration *bc)
{
Target *const t = activeTarget();
const CMakeBuildConfiguration *aBc = activeBc(this);
QTC_ASSERT(bc, return);
QTC_ASSERT(bc == (t ? t->activeBuildConfiguration() : nullptr), return);
QTC_ASSERT(m_treeScanner.isFinished() && !bc->isParsing(), return);
QTC_ASSERT(bc == aBc, return);
QTC_ASSERT(m_treeScanner.isFinished() && !m_buildDirManager.isParsing(), return);
Target *t = bc->target();
Kit *k = t->kit();
auto newRoot = bc->generateProjectTree(m_allFiles);
bc->setBuildTargets(m_buildDirManager.takeBuildTargets());
bc->setConfigurationFromCMake(m_buildDirManager.takeCMakeConfiguration());
auto newRoot = generateProjectTree(m_allFiles);
if (newRoot) {
setDisplayName(newRoot->displayName());
setRootProjectNode(newRoot);
@@ -184,7 +296,7 @@ void CMakeProject::updateProjectData(CMakeBuildConfiguration *bc)
}
CppTools::RawProjectParts rpps;
bc->updateCodeModel(rpps);
m_buildDirManager.updateCodeModel(rpps);
for (CppTools::RawProjectPart &rpp : rpps) {
// TODO: Set the Qt version only if target actually depends on Qt.
@@ -197,6 +309,8 @@ void CMakeProject::updateProjectData(CMakeBuildConfiguration *bc)
updateQmlJSCodeModel();
m_buildDirManager.resetData();
emit fileListChanged();
emit bc->emitBuildTypeChanged();
@@ -220,10 +334,10 @@ void CMakeProject::updateQmlJSCodeModel()
if (!bc)
return;
const QList<ConfigModel::DataItem> &cm = bc->completeCMakeConfiguration();
foreach (const ConfigModel::DataItem &di, cm) {
if (di.key.contains(QStringLiteral("QML_IMPORT_PATH"))) {
cmakeImports = di.value;
const CMakeConfig &cm = bc->configurationFromCMake();
foreach (const CMakeConfigItem &di, cm) {
if (di.key.contains("QML_IMPORT_PATH")) {
cmakeImports = QString::fromUtf8(di.value);
break;
}
}
@@ -234,6 +348,16 @@ void CMakeProject::updateQmlJSCodeModel()
modelManager->updateProjectInfo(projectInfo, this);
}
CMakeProjectNode *CMakeProject::generateProjectTree(const QList<const FileNode *> &allFiles) const
{
if (m_buildDirManager.isParsing())
return nullptr;
auto root = std::make_unique<CMakeProjectNode>(projectDirectory());
m_buildDirManager.generateProjectTree(root.get(), allFiles);
return root ? root.release() : nullptr;
}
bool CMakeProject::needsConfiguration() const
{
return targets().isEmpty();
@@ -264,53 +388,28 @@ void CMakeProject::runCMake()
if (isParsing())
return;
startParsingProject(PARSE);
CMakeBuildConfiguration *bc = activeBc(this);
if (bc) {
BuildDirParameters parameters(bc);
m_buildDirManager.setParametersAndRequestParse(parameters,
BuildDirManager::REPARSE_CHECK_CONFIGURATION,
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
}
}
void CMakeProject::runCMakeAndScanProjectTree()
{
if (isParsing())
if (!m_treeScanner.isFinished())
return;
startParsingProject(static_cast<DataCollectionAction>(PARSE | SCAN));
}
void CMakeProject::startParsingProject(const CMakeProject::DataCollectionAction action)
{
const bool runParse = action & PARSE;
const bool runScan = action & SCAN;
CMakeBuildConfiguration *bc = activeTarget()
? qobject_cast<CMakeBuildConfiguration *>(activeTarget()->activeBuildConfiguration())
: nullptr;
if (!bc)
return;
if (!m_treeScanner.isFinished() || m_waitingForScan)
return;
emitParsingStarted();
m_waitingForParse = runParse;
m_waitingForScan = runScan;
m_combinedScanAndParseResult = true;
if (runParse)
bc->runCMake();
if (runScan) {
m_treeScanner.asyncScanForFiles(projectDirectory());
Core::ProgressManager::addTask(m_treeScanner.future(),
tr("Scan \"%1\" project tree").arg(displayName()),
"CMake.Scan.Tree");
}
m_waitingForScan = true;
runCMake();
}
void CMakeProject::buildCMakeTarget(const QString &buildTarget)
{
QTC_ASSERT(!buildTarget.isEmpty(), return);
Target *t = activeTarget();
auto bc = qobject_cast<CMakeBuildConfiguration *>(t ? t->activeBuildConfiguration() : nullptr);
CMakeBuildConfiguration *bc = activeBc(this);
if (bc)
bc->buildTarget(buildTarget);
}
@@ -322,15 +421,60 @@ ProjectImporter *CMakeProject::projectImporter() const
return m_projectImporter.get();
}
bool CMakeProject::persistCMakeState()
{
return m_buildDirManager.persistCMakeState();
}
void CMakeProject::clearCMakeCache()
{
m_buildDirManager.clearCache();
}
QList<CMakeBuildTarget> CMakeProject::buildTargets() const
{
CMakeBuildConfiguration *bc = nullptr;
if (activeTarget())
bc = qobject_cast<CMakeBuildConfiguration *>(activeTarget()->activeBuildConfiguration());
CMakeBuildConfiguration *bc = activeBc(this);
return bc ? bc->buildTargets() : QList<CMakeBuildTarget>();
}
void CMakeProject::handleReparseRequest(int reparseParameters)
{
QTC_ASSERT(!(reparseParameters & BuildDirManager::REPARSE_FAIL), return);
if (reparseParameters & BuildDirManager::REPARSE_IGNORE)
return;
m_delayedParsingTimer.setInterval((reparseParameters & BuildDirManager::REPARSE_URGENT) ? 0 : 1000);
m_delayedParsingTimer.start();
m_delayedParsingParameters = m_delayedParsingParameters | reparseParameters;
}
void CMakeProject::startParsing(int reparseParameters)
{
m_delayedParsingParameters = BuildDirManager::REPARSE_DEFAULT;
QTC_ASSERT((reparseParameters & BuildDirManager::REPARSE_FAIL) == 0, return);
if (reparseParameters & BuildDirManager::REPARSE_IGNORE)
return;
QTC_ASSERT(activeBc(this), return);
emitParsingStarted();
m_waitingForParse = true;
m_combinedScanAndParseResult = true;
if (m_waitingForScan) {
QTC_CHECK(m_treeScanner.isFinished());
m_treeScanner.asyncScanForFiles(projectDirectory());
Core::ProgressManager::addTask(m_treeScanner.future(),
tr("Scan \"%1\" project tree").arg(displayName()),
"CMake.Scan.Tree");
}
m_buildDirManager.parse(reparseParameters);
}
QStringList CMakeProject::buildTargetTitles(bool runnable) const
{
const QList<CMakeBuildTarget> targets
@@ -361,33 +505,9 @@ bool CMakeProject::setupTarget(Target *t)
if (t->buildConfigurations().isEmpty())
return false;
t->updateDefaultDeployConfigurations();
return true;
}
void CMakeProject::handleActiveProjectConfigurationChanged(ProjectConfiguration *pc)
{
if (auto bc = qobject_cast<CMakeBuildConfiguration *>(pc)) {
if (!bc->isActive())
return;
} else if (!qobject_cast<Target *>(pc)) {
return;
}
for (Target *t : targets()) {
for (BuildConfiguration *bc : t->buildConfigurations()) {
auto i = qobject_cast<CMakeBuildConfiguration *>(bc);
QTC_ASSERT(i, continue);
if (i->isActive()) {
m_waitingForParse = true;
i->maybeForceReparse();
} else {
i->resetData();
}
}
}
}
void CMakeProject::handleTreeScanningFinished()
{
QTC_CHECK(m_waitingForScan);
@@ -395,8 +515,7 @@ void CMakeProject::handleTreeScanningFinished()
qDeleteAll(m_allFiles);
m_allFiles = Utils::transform(m_treeScanner.release(), [](const FileNode *fn) { return fn; });
auto t = activeTarget();
auto bc = qobject_cast<CMakeBuildConfiguration*>(t ? t->activeBuildConfiguration() : nullptr);
CMakeBuildConfiguration *bc = activeBc(this);
QTC_ASSERT(bc, return);
m_combinedScanAndParseResult = m_combinedScanAndParseResult && true;
@@ -407,7 +526,7 @@ void CMakeProject::handleTreeScanningFinished()
void CMakeProject::handleParsingSuccess(CMakeBuildConfiguration *bc)
{
QTC_CHECK(m_waitingForParse);
QTC_ASSERT(m_waitingForParse, return);
if (!bc || !bc->isActive())
return;
@@ -626,18 +745,4 @@ void CMakeProject::createGeneratedCodeModelSupport()
CppTools::GeneratedCodeModelSupport::update(m_extraCompilers);
}
void CMakeBuildTarget::clear()
{
executable.clear();
makeCommand.clear();
workingDirectory.clear();
sourceDirectory.clear();
title.clear();
targetType = UtilityType;
includeFiles.clear();
compilerOptions.clear();
macros.clear();
files.clear();
}
} // namespace CMakeProjectManager
+17 -31
View File
@@ -26,8 +26,11 @@
#pragma once
#include "cmake_global.h"
#include "builddirmanager.h"
#include "cmakebuildtarget.h"
#include "cmakeprojectimporter.h"
#include "treescanner.h"
#include "builddirmanager.h"
#include <projectexplorer/extracompiler.h>
#include <projectexplorer/projectmacro.h>
@@ -42,40 +45,16 @@
#include <memory>
namespace CppTools { class CppProjectUpdater; }
namespace ProjectExplorer { class FileNode; }
namespace CMakeProjectManager {
namespace Internal {
class CMakeBuildConfiguration;
class CMakeBuildSettingsWidget;
class CMakeProjectNode;
} // namespace Internal
enum TargetType {
ExecutableType = 0,
StaticLibraryType = 2,
DynamicLibraryType = 3,
UtilityType = 64
};
class CMAKE_EXPORT CMakeBuildTarget
{
public:
QString title;
Utils::FileName executable; // TODO: rename to output?
TargetType targetType = UtilityType;
Utils::FileName workingDirectory;
Utils::FileName sourceDirectory;
Utils::FileName makeCommand;
// code model
QList<Utils::FileName> includeFiles;
QStringList compilerOptions;
ProjectExplorer::Macros macros;
QList<Utils::FileName> files;
void clear();
};
class CMAKE_EXPORT CMakeProject : public ProjectExplorer::Project
{
Q_OBJECT
@@ -103,6 +82,10 @@ public:
ProjectExplorer::ProjectImporter *projectImporter() const final;
bool persistCMakeState();
void clearCMakeCache();
bool mustUpdateCMakeStateBeforeBuild();
protected:
RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) final;
bool setupTarget(ProjectExplorer::Target *t) final;
@@ -110,10 +93,10 @@ protected:
private:
QList<CMakeBuildTarget> buildTargets() const;
enum DataCollectionAction { PARSE = 1, SCAN = 2 };
void startParsingProject(const DataCollectionAction a);
void handleReparseRequest(int reparseParameters);
void startParsing(int reparseParameters);
void handleActiveProjectConfigurationChanged(ProjectExplorer::ProjectConfiguration *pc);
void handleTreeScanningFinished();
void handleParsingSuccess(Internal::CMakeBuildConfiguration *bc);
void handleParsingError(Internal::CMakeBuildConfiguration *bc);
@@ -121,19 +104,21 @@ private:
void updateProjectData(Internal::CMakeBuildConfiguration *bc);
void updateQmlJSCodeModel();
Internal::CMakeProjectNode *
generateProjectTree(const QList<const ProjectExplorer::FileNode*> &allFiles) const;
void createGeneratedCodeModelSupport();
QStringList filesGeneratedFrom(const QString &sourceFile) const final;
void updateTargetRunConfigurations(ProjectExplorer::Target *t);
void updateApplicationAndDeploymentTargets();
bool mustUpdateCMakeStateBeforeBuild();
// TODO probably need a CMake specific node structure
QList<CMakeBuildTarget> m_buildTargets;
CppTools::CppProjectUpdater *m_cppCodeModelUpdater = nullptr;
QList<ProjectExplorer::ExtraCompiler *> m_extraCompilers;
Internal::TreeScanner m_treeScanner;
Internal::BuildDirManager m_buildDirManager;
bool m_waitingForScan = false;
bool m_waitingForParse = false;
@@ -144,6 +129,7 @@ private:
mutable std::unique_ptr<Internal::CMakeProjectImporter> m_projectImporter;
QTimer m_delayedParsingTimer;
int m_delayedParsingParameters = 0;
friend class Internal::CMakeBuildConfiguration;
friend class Internal::CMakeBuildSettingsWidget;
@@ -243,7 +243,7 @@ QList<void *> CMakeProjectImporter::examineDirectory(const Utils::FileName &impo
}
QString errorMessage;
const CMakeConfig config = BuildDirManager::parseConfiguration(cacheFile, &errorMessage);
const CMakeConfig config = BuildDirManager::parseCMakeConfiguration(cacheFile, &errorMessage);
if (config.isEmpty() || !errorMessage.isEmpty()) {
qCDebug(cmInputLog()) << "Failed to read configuration from" << cacheFile << errorMessage;
return { };
@@ -24,7 +24,6 @@
****************************************************************************/
#include "cmakeprojectmanager.h"
#include "builddirmanager.h"
#include "cmakebuildconfiguration.h"
#include "cmakekitinformation.h"
#include "cmakeprojectconstants.h"
@@ -43,9 +42,6 @@
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
#include <utils/qtcprocess.h>
#include <utils/synchronousprocess.h>
#include <QAction>
#include <QDateTime>
#include <QIcon>
@@ -121,19 +117,15 @@ void CMakeManager::updateCmakeActions()
void CMakeManager::clearCMakeCache(Project *project)
{
if (!project || !project->activeTarget())
return;
auto bc = qobject_cast<CMakeBuildConfiguration *>(project->activeTarget()->activeBuildConfiguration());
if (!bc)
CMakeProject *cmakeProject = qobject_cast<CMakeProject *>(project);
if (!cmakeProject || !cmakeProject->activeTarget() || !cmakeProject->activeTarget()->activeBuildConfiguration())
return;
bc->clearCache();
cmakeProject->clearCMakeCache();
}
void CMakeManager::runCMake(Project *project)
{
if (!project)
return;
CMakeProject *cmakeProject = qobject_cast<CMakeProject *>(project);
if (!cmakeProject || !cmakeProject->activeTarget() || !cmakeProject->activeTarget()->activeBuildConfiguration())
return;
@@ -146,8 +138,6 @@ void CMakeManager::runCMake(Project *project)
void CMakeManager::rescanProject(Project *project)
{
if (!project)
return;
CMakeProject *cmakeProject = qobject_cast<CMakeProject *>(project);
if (!cmakeProject || !cmakeProject->activeTarget() || !cmakeProject->activeTarget()->activeBuildConfiguration())
return;
@@ -2,9 +2,11 @@ DEFINES += CMAKEPROJECTMANAGER_LIBRARY
include(../../qtcreatorplugin.pri)
HEADERS = builddirmanager.h \
builddirparameters.h \
builddirreader.h \
cmakebuildinfo.h \
cmakebuildstep.h \
cmakebuildtarget.h \
cmakeconfigitem.h \
cmakeproject.h \
cmakeprojectimporter.h \
@@ -36,8 +38,10 @@ HEADERS = builddirmanager.h \
treescanner.h
SOURCES = builddirmanager.cpp \
builddirparameters.cpp \
builddirreader.cpp \
cmakebuildstep.cpp \
cmakebuildtarget.cpp \
cmakeconfigitem.cpp \
cmakeproject.cpp \
cmakeprojectimporter.cpp \
@@ -19,6 +19,8 @@ QtcPlugin {
]
files: [
"builddirparameters.cpp",
"builddirparameters.h",
"builddirmanager.cpp",
"builddirmanager.h",
"builddirreader.cpp",
@@ -31,6 +33,8 @@ QtcPlugin {
"cmakebuildsettingswidget.h",
"cmakebuildstep.cpp",
"cmakebuildstep.h",
"cmakebuildtarget.cpp",
"cmakebuildtarget.h",
"cmakecbpparser.cpp",
"cmakecbpparser.h",
"cmakeconfigitem.cpp",
@@ -166,7 +166,7 @@ QString CMakeRunConfiguration::disabledReason() const
auto cp = qobject_cast<CMakeProject *>(target()->project());
QTC_ASSERT(cp, return QString());
if (cp->hasParsingData() && !cp->hasBuildTarget(m_buildSystemTarget))
if (!cp->hasBuildTarget(m_buildSystemTarget))
return tr("The project no longer builds the target associated with this run configuration.");
return RunConfiguration::disabledReason();
}
@@ -200,6 +200,42 @@ QList<ConfigModel::DataItem> ConfigModel::configurationChanges() const
});
}
void ConfigModel::setConfiguration(const CMakeConfig &config)
{
setConfiguration(Utils::transform(config, [](const CMakeConfigItem &i) {
ConfigModel::DataItem j;
j.key = QString::fromUtf8(i.key);
j.value = QString::fromUtf8(i.value);
j.description = QString::fromUtf8(i.documentation);
j.values = i.values;
j.inCMakeCache = i.inCMakeCache;
j.isAdvanced = i.isAdvanced;
j.isHidden = i.type == CMakeConfigItem::INTERNAL || i.type == CMakeConfigItem::STATIC;
switch (i.type) {
case CMakeConfigItem::FILEPATH:
j.type = ConfigModel::DataItem::FILE;
break;
case CMakeConfigItem::PATH:
j.type = ConfigModel::DataItem::DIRECTORY;
break;
case CMakeConfigItem::BOOL:
j.type = ConfigModel::DataItem::BOOLEAN;
break;
case CMakeConfigItem::STRING:
j.type = ConfigModel::DataItem::STRING;
break;
default:
j.type = ConfigModel::DataItem::UNKNOWN;
break;
}
return j;
}));
}
void ConfigModel::setConfiguration(const QList<ConfigModel::InternalDataItem> &config)
{
QList<InternalDataItem> tmp = config;
@@ -25,6 +25,8 @@
#pragma once
#include "cmakeconfigitem.h"
#include <QAbstractTableModel>
#include <utils/treemodel.h>
@@ -65,6 +67,7 @@ public:
const DataItem::Type type = DataItem::UNKNOWN,
const QString &description = QString(),
const QStringList &values = QStringList());
void setConfiguration(const CMakeConfig &config);
void setConfiguration(const QList<DataItem> &config);
void setKitConfiguration(const QHash<QString, QString> &kitConfig);
void flush();
@@ -80,6 +83,7 @@ public:
QList<DataItem> configurationChanges() const;
private:
class InternalDataItem : public DataItem
{
@@ -97,9 +101,9 @@ private:
QString kitValue;
};
void setConfiguration(const QList<InternalDataItem> &config);
void generateTree();
void setConfiguration(const QList<InternalDataItem> &config);
QList<InternalDataItem> m_configuration;
QHash<QString, QString> m_kitConfiguration;
@@ -97,12 +97,15 @@ ServerModeReader::~ServerModeReader()
stop();
}
void ServerModeReader::setParameters(const BuildDirReader::Parameters &p)
void ServerModeReader::setParameters(const BuildDirParameters &p)
{
QTC_ASSERT(p.cmakeTool, return);
BuildDirReader::setParameters(p);
if (!m_cmakeServer) {
m_cmakeServer.reset(new ServerMode(p.environment,
p.sourceDirectory, p.buildDirectory, p.cmakeExecutable,
p.sourceDirectory, p.buildDirectory,
p.cmakeTool->cmakeExecutable(),
p.generator, p.extraGenerator, p.platform, p.toolset,
true, 1));
connect(m_cmakeServer.get(), &ServerMode::errorOccured,
@@ -135,14 +138,17 @@ void ServerModeReader::setParameters(const BuildDirReader::Parameters &p)
}
}
bool ServerModeReader::isCompatible(const BuildDirReader::Parameters &p)
bool ServerModeReader::isCompatible(const BuildDirParameters &p)
{
// Server mode connection got lost, reset...
if (!m_parameters.cmakeExecutable.isEmpty() && !m_cmakeServer)
if (!p.cmakeTool)
return false;
return p.cmakeHasServerMode
&& p.cmakeExecutable == m_parameters.cmakeExecutable
// Server mode connection got lost, reset...
if (!m_parameters.cmakeTool->cmakeExecutable().isEmpty() && !m_cmakeServer)
return false;
return p.cmakeTool->hasServerMode()
&& p.cmakeTool->cmakeExecutable() == m_parameters.cmakeTool->cmakeExecutable()
&& p.environment == m_parameters.environment
&& p.generator == m_parameters.generator
&& p.extraGenerator == m_parameters.extraGenerator
@@ -154,24 +160,33 @@ bool ServerModeReader::isCompatible(const BuildDirReader::Parameters &p)
void ServerModeReader::resetData()
{
m_hasData = false;
m_cmakeConfiguration.clear();
// m_cmakeFiles: Keep these!
m_cmakeInputsFileNodes.clear();
qDeleteAll(m_projects); // Also deletes targets and filegroups that are its children!
m_projects.clear();
m_targets.clear();
m_fileGroups.clear();
}
void ServerModeReader::parse(bool force)
void ServerModeReader::parse(bool forceConfiguration)
{
emit configurationStarted();
Core::MessageManager::write(tr("Starting to parse CMake project."));
QTC_ASSERT(m_cmakeServer, return);
QVariantMap extra;
if (force || !QDir(m_parameters.buildDirectory.toString()).exists("CMakeCache.txt")) {
if (forceConfiguration || !QDir(m_parameters.buildDirectory.toString()).exists("CMakeCache.txt")) {
QStringList cacheArguments = transform(m_parameters.configuration,
[this](const CMakeConfigItem &i) {
return i.toArgument(m_parameters.expander);
});
Core::MessageManager::write(tr("Starting to parse CMake project, using: \"%1\".")
.arg(cacheArguments.join("\", \"")));
cacheArguments.prepend(QString()); // Work around a bug in CMake 3.7.0 and 3.7.1 where
// the first argument gets lost!
extra.insert("cacheArguments", QVariant(cacheArguments));
} else {
Core::MessageManager::write(tr("Starting to parse CMake project."));
}
m_future.reset(new QFutureInterface<void>());
@@ -205,12 +220,7 @@ bool ServerModeReader::isParsing() const
return static_cast<bool>(m_future);
}
bool ServerModeReader::hasData() const
{
return m_hasData;
}
QList<CMakeBuildTarget> ServerModeReader::buildTargets() const
QList<CMakeBuildTarget> ServerModeReader::takeBuildTargets()
{
const QList<CMakeBuildTarget> result = transform(m_targets, [](const Target *t) -> CMakeBuildTarget {
CMakeBuildTarget ct;
@@ -243,8 +253,8 @@ QList<CMakeBuildTarget> ServerModeReader::buildTargets() const
CMakeConfig ServerModeReader::takeParsedConfiguration()
{
CMakeConfig config = m_cmakeCache;
m_cmakeCache.clear();
CMakeConfig config = m_cmakeConfiguration;
m_cmakeConfiguration.clear();
return config;
}
@@ -369,11 +379,6 @@ void ServerModeReader::updateCodeModel(CppTools::RawProjectParts &rpps)
: CppTools::ProjectPart::Library);
rpps.append(rpp);
}
qDeleteAll(m_projects); // Not used anymore!
m_projects.clear();
m_targets.clear();
m_fileGroups.clear();
}
void ServerModeReader::handleReply(const QVariantMap &data, const QString &inReplyTo)
@@ -412,7 +417,6 @@ void ServerModeReader::handleReply(const QVariantMap &data, const QString &inRep
m_future->reportFinished();
m_future.reset();
}
m_hasData = true;
Core::MessageManager::write(tr("CMake Project was parsed successfully."));
emit dataAvailable();
}
@@ -669,7 +673,7 @@ void ServerModeReader::extractCacheData(const QVariantMap &data)
item.values = CMakeConfigItem::cmakeSplitValue(properties.value("STRINGS").toString(), true);
config.append(item);
}
m_cmakeCache = config;
m_cmakeConfiguration = config;
}
void ServerModeReader::fixTarget(ServerModeReader::Target *target) const
@@ -33,10 +33,11 @@
#include <memory>
namespace ProjectExplorer { class ProjectNode; }
namespace CMakeProjectManager {
namespace Internal {
class ServerModeReader : public BuildDirReader
{
Q_OBJECT
@@ -45,18 +46,17 @@ public:
ServerModeReader();
~ServerModeReader() final;
void setParameters(const Parameters &p) final;
void setParameters(const BuildDirParameters &p) final;
bool isCompatible(const Parameters &p) final;
bool isCompatible(const BuildDirParameters &p) final;
void resetData() final;
void parse(bool force) final;
void parse(bool forceConfiguration) final;
void stop() final;
bool isReady() const final;
bool isParsing() const final;
bool hasData() const final;
QList<CMakeBuildTarget> buildTargets() const final;
QList<CMakeBuildTarget> takeBuildTargets() final;
CMakeConfig takeParsedConfiguration() final;
void generateProjectTree(CMakeProjectNode *root,
const QList<const ProjectExplorer::FileNode *> &allFiles) final;
@@ -160,21 +160,19 @@ private:
const QList<ProjectExplorer::FileNode *> knownHeaders,
const QList<const ProjectExplorer::FileNode *> &allFiles);
bool m_hasData = false;
std::unique_ptr<ServerMode> m_cmakeServer;
std::unique_ptr<QFutureInterface<void>> m_future;
int m_progressStepMinimum = 0;
int m_progressStepMaximum = 1000;
CMakeConfig m_cmakeCache;
CMakeConfig m_cmakeConfiguration;
QSet<Utils::FileName> m_cmakeFiles;
QList<ProjectExplorer::FileNode *> m_cmakeInputsFileNodes;
QList<Project *> m_projects;
mutable QList<Target *> m_targets;
QList<Target *> m_targets;
QList<FileGroup *> m_fileGroups;
CMakeParser m_parser;
@@ -130,7 +130,9 @@ TeaLeafReader::TeaLeafReader()
{
connect(EditorManager::instance(), &EditorManager::aboutToSave,
this, [this](const IDocument *document) {
if (m_cmakeFiles.contains(document->filePath()) || !m_parameters.isAutorun)
if (m_cmakeFiles.contains(document->filePath())
|| !m_parameters.cmakeTool
|| !m_parameters.cmakeTool->isAutoRun())
emit dirty();
});
@@ -150,15 +152,15 @@ TeaLeafReader::~TeaLeafReader()
resetData();
}
bool TeaLeafReader::isCompatible(const BuildDirReader::Parameters &p)
bool TeaLeafReader::isCompatible(const BuildDirParameters &p)
{
return !p.cmakeHasServerMode;
if (!p.cmakeTool)
return false;
return !p.cmakeTool->hasServerMode();
}
void TeaLeafReader::resetData()
{
m_hasData = false;
qDeleteAll(m_watchedFiles);
m_watchedFiles.clear();
@@ -188,11 +190,11 @@ static QString findCbpFile(const QDir &directory)
return file;
}
void TeaLeafReader::parse(bool force)
void TeaLeafReader::parse(bool forceConfiguration)
{
const QString cbpFile = findCbpFile(QDir(m_parameters.buildDirectory.toString()));
const QFileInfo cbpFileFi = cbpFile.isEmpty() ? QFileInfo() : QFileInfo(cbpFile);
if (!cbpFileFi.exists() || force) {
if (!cbpFileFi.exists() || forceConfiguration) {
// Initial create:
startCMake(toArguments(m_parameters.configuration, m_parameters.expander));
return;
@@ -206,7 +208,6 @@ void TeaLeafReader::parse(bool force)
startCMake(QStringList());
} else {
extractData();
m_hasData = true;
emit dataAvailable();
}
}
@@ -228,12 +229,7 @@ bool TeaLeafReader::isParsing() const
return m_cmakeProcess && m_cmakeProcess->state() != QProcess::NotRunning;
}
bool TeaLeafReader::hasData() const
{
return m_hasData;
}
QList<CMakeBuildTarget> TeaLeafReader::buildTargets() const
QList<CMakeBuildTarget> TeaLeafReader::takeBuildTargets()
{
return m_buildTargets;
}
@@ -247,7 +243,7 @@ CMakeConfig TeaLeafReader::takeParsedConfiguration()
return { };
QString errorMessage;
CMakeConfig result = BuildDirManager::parseConfiguration(cacheFile, &errorMessage);
CMakeConfig result = BuildDirManager::parseCMakeConfiguration(cacheFile, &errorMessage);
if (!errorMessage.isEmpty()) {
emit errorOccured(errorMessage);
@@ -412,6 +408,8 @@ void TeaLeafReader::cleanUpProcess()
void TeaLeafReader::extractData()
{
QTC_ASSERT(m_parameters.isValid() && m_parameters.cmakeTool, return);
const FileName srcDir = m_parameters.sourceDirectory;
const FileName bldDir = m_parameters.buildDirectory;
const FileName topCMake = Utils::FileName(srcDir).appendPath("CMakeLists.txt");
@@ -437,7 +435,7 @@ void TeaLeafReader::extractData()
// setFolderName
CMakeCbpParser cbpparser;
// Parsing
if (!cbpparser.parseCbpFile(m_parameters.pathMapper, cbpFile, srcDir))
if (!cbpparser.parseCbpFile(m_parameters.cmakeTool->pathMapper(), cbpFile, srcDir))
return;
m_projectName = cbpparser.projectName();
@@ -460,6 +458,8 @@ void TeaLeafReader::extractData()
void TeaLeafReader::startCMake(const QStringList &configurationArguments)
{
QTC_ASSERT(m_parameters.isValid() && m_parameters.cmakeTool, return);
const FileName buildDirectory = m_parameters.buildDirectory;
QTC_ASSERT(!m_cmakeProcess, return);
QTC_ASSERT(!m_parser, return);
@@ -503,7 +503,7 @@ void TeaLeafReader::startCMake(const QStringList &configurationArguments)
TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
MessageManager::write(tr("Running \"%1 %2\" in %3.")
.arg(m_parameters.cmakeExecutable.toUserOutput())
.arg(m_parameters.cmakeTool->cmakeExecutable().toUserOutput())
.arg(args)
.arg(buildDirectory.toUserOutput()));
@@ -513,7 +513,7 @@ void TeaLeafReader::startCMake(const QStringList &configurationArguments)
tr("Configuring \"%1\"").arg(m_parameters.projectName),
"CMake.Configure");
m_cmakeProcess->setCommand(m_parameters.cmakeExecutable.toString(), args);
m_cmakeProcess->setCommand(m_parameters.cmakeTool->cmakeExecutable().toString(), args);
emit configurationStarted();
m_cmakeProcess->start();
}
@@ -549,7 +549,6 @@ void TeaLeafReader::cmakeFinished(int code, QProcess::ExitStatus status)
delete m_future;
m_future = nullptr;
m_hasData = true;
emit dataAvailable();
}
@@ -663,7 +662,7 @@ bool TeaLeafReader::extractFlagsFromNinja(const CMakeBuildTarget &buildTarget,
// found
// Get "all" target's working directory
QByteArray ninjaFile;
QString buildNinjaFile = buildTargets().at(0).workingDirectory.toString();
QString buildNinjaFile = takeBuildTargets().at(0).workingDirectory.toString();
buildNinjaFile += "/build.ninja";
QFile buildNinja(buildNinjaFile);
if (buildNinja.exists()) {
@@ -46,15 +46,14 @@ public:
TeaLeafReader();
~TeaLeafReader() final;
bool isCompatible(const Parameters &p) final;
bool isCompatible(const BuildDirParameters &p) final;
void resetData() final;
void parse(bool force) final;
void parse(bool forceConfiguration) final;
void stop() final;
bool isParsing() const final;
bool hasData() const final;
QList<CMakeBuildTarget> buildTargets() const final;
QList<CMakeBuildTarget> takeBuildTargets() final;
CMakeConfig takeParsedConfiguration() final;
void generateProjectTree(CMakeProjectNode *root,
const QList<const ProjectExplorer::FileNode *> &allFiles) final;
@@ -80,8 +79,6 @@ private:
ProjectExplorer::IOutputParser *m_parser = nullptr;
QFutureInterface<void> *m_future = nullptr;
bool m_hasData = false;
QSet<Utils::FileName> m_cmakeFiles;
QString m_projectName;
QList<CMakeBuildTarget> m_buildTargets;
+28 -24
View File
@@ -153,20 +153,20 @@ public:
QList<DocumentManager::RecentFile> m_recentFiles;
static const int m_maxRecentFiles = 7;
QFileSystemWatcher *m_fileWatcher; // Delayed creation.
QFileSystemWatcher *m_linkWatcher; // Delayed creation (only UNIX/if a link is seen).
bool m_blockActivated;
QFileSystemWatcher *m_fileWatcher = nullptr; // Delayed creation.
QFileSystemWatcher *m_linkWatcher = nullptr; // Delayed creation (only UNIX/if a link is seen).
bool m_blockActivated = false;
bool m_checkOnFocusChange = false;
QString m_lastVisitedDirectory;
QString m_lastVisitedDirectory = QDir::currentPath();
QString m_defaultLocationForNewFiles;
FileName m_projectsDirectory;
bool m_useProjectsDirectory;
bool m_useProjectsDirectory = true;
QString m_buildDirectory;
// When we are calling into an IDocument
// we don't want to receive a changed()
// signal
// That makes the code easier
IDocument *m_blockedIDocument;
IDocument *m_blockedIDocument = nullptr;
};
static DocumentManager *m_instance;
@@ -210,13 +210,7 @@ void DocumentManagerPrivate::onApplicationFocusChange()
m_instance->checkForReload();
}
DocumentManagerPrivate::DocumentManagerPrivate() :
m_fileWatcher(0),
m_linkWatcher(0),
m_blockActivated(false),
m_lastVisitedDirectory(QDir::currentPath()),
m_useProjectsDirectory(true),
m_blockedIDocument(0)
DocumentManagerPrivate::DocumentManagerPrivate()
{
connect(qApp, &QApplication::focusChanged, this, &DocumentManagerPrivate::onApplicationFocusChange);
}
@@ -261,21 +255,24 @@ static void addFileInfo(IDocument *document, const QString &filePath,
const QFileInfo fi(filePath);
state.modified = fi.lastModified();
state.permissions = fi.permissions();
// Add watcher if we don't have that already
// Add state if we don't have already
if (!d->m_states.contains(filePathKey)) {
FileState state;
state.watchedFilePath = filePath;
d->m_states.insert(filePathKey, state);
}
// Add or update watcher on file path
// This is also used to update the watcher in case of saved (==replaced) files or
// update link targets, even if there are multiple documents registered for it
const QString watchedFilePath = d->m_states.value(filePathKey).watchedFilePath;
qCDebug(log) << "adding (" << (isLink ? "link" : "full") << ") watch for"
<< state.watchedFilePath;
QFileSystemWatcher *watcher = 0;
<< watchedFilePath;
QFileSystemWatcher *watcher = nullptr;
if (isLink)
watcher = d->linkWatcher();
else
watcher = d->fileWatcher();
watcher->addPath(state.watchedFilePath);
}
watcher->addPath(watchedFilePath);
d->m_states[filePathKey].lastUpdatedState.insert(document, state);
}
@@ -429,7 +426,7 @@ void DocumentManager::renamedFile(const QString &from, const QString &to)
removeFileInfo(document);
document->setFilePath(FileName::fromString(to));
addFileInfo(document);
d->m_blockedIDocument = 0;
d->m_blockedIDocument = nullptr;
}
emit m_instance->allDocumentsRenamed(from, to);
}
@@ -617,7 +614,7 @@ static bool saveModifiedFilesHelper(const QList<IDocument *> &documents,
// There can be several IDocuments pointing to the same file
// Prefer one that is not readonly
// (even though it *should* not happen that the IDocuments are inconsistent with readonly)
if (!modifiedDocumentsMap.key(name, 0) || !document->isFileReadOnly())
if (!modifiedDocumentsMap.key(name, nullptr) || !document->isFileReadOnly())
modifiedDocumentsMap.insert(document, name);
}
}
@@ -827,10 +824,17 @@ bool DocumentManager::saveAllModifiedDocumentsSilently(bool *canceled,
\a FailedToClose will contain a list of documents that could not be saved if passed into the
method.
*/
bool DocumentManager::saveModifiedDocumentsSilently(const QList<IDocument *> &documents, bool *canceled,
bool DocumentManager::saveModifiedDocumentsSilently(const QList<IDocument *> &documents,
bool *canceled,
QList<IDocument *> *failedToClose)
{
return saveModifiedFilesHelper(documents, QString(), canceled, true, QString(), 0, failedToClose);
return saveModifiedFilesHelper(documents,
QString(),
canceled,
true,
QString(),
nullptr,
failedToClose);
}
/*!
@@ -1178,7 +1182,7 @@ void DocumentManager::checkForReload()
errorStrings << errorString;
}
d->m_blockedIDocument = 0;
d->m_blockedIDocument = nullptr;
}
if (!filesToDiff.isEmpty()) {
+28 -19
View File
@@ -80,38 +80,47 @@ public:
static QString cleanAbsoluteFilePath(const QString &filePath, ResolveMode resolveMode);
static QString filePathKey(const QString &filePath, ResolveMode resolveMode);
static bool saveDocument(IDocument *document, const QString &fileName = QString(), bool *isReadOnly = 0);
static bool saveDocument(IDocument *document,
const QString &fileName = QString(),
bool *isReadOnly = nullptr);
static QStringList getOpenFileNames(const QString &filters,
const QString &path = QString(),
QString *selectedFilter = 0);
static QString getSaveFileName(const QString &title, const QString &pathIn,
const QString &filter = QString(), QString *selectedFilter = 0);
QString *selectedFilter = nullptr);
static QString getSaveFileName(const QString &title,
const QString &pathIn,
const QString &filter = QString(),
QString *selectedFilter = nullptr);
static QString getSaveFileNameWithExtension(const QString &title, const QString &pathIn,
const QString &filter);
static QString getSaveAsFileName(const IDocument *document);
static bool saveAllModifiedDocumentsSilently(bool *canceled = 0,
QList<IDocument *> *failedToClose = 0);
static bool saveModifiedDocumentsSilently(const QList<IDocument *> &documents, bool *canceled = 0,
QList<IDocument *> *failedToClose = 0);
static bool saveModifiedDocumentSilently(IDocument *document, bool *canceled = 0,
QList<IDocument *> *failedToClose = 0);
static bool saveAllModifiedDocumentsSilently(bool *canceled = nullptr,
QList<IDocument *> *failedToClose = nullptr);
static bool saveModifiedDocumentsSilently(const QList<IDocument *> &documents,
bool *canceled = nullptr,
QList<IDocument *> *failedToClose = nullptr);
static bool saveModifiedDocumentSilently(IDocument *document,
bool *canceled = nullptr,
QList<IDocument *> *failedToClose = nullptr);
static bool saveAllModifiedDocuments(const QString &message = QString(), bool *canceled = 0,
static bool saveAllModifiedDocuments(const QString &message = QString(),
bool *canceled = nullptr,
const QString &alwaysSaveMessage = QString(),
bool *alwaysSave = 0,
QList<IDocument *> *failedToClose = 0);
bool *alwaysSave = nullptr,
QList<IDocument *> *failedToClose = nullptr);
static bool saveModifiedDocuments(const QList<IDocument *> &documents,
const QString &message = QString(), bool *canceled = 0,
const QString &message = QString(),
bool *canceled = nullptr,
const QString &alwaysSaveMessage = QString(),
bool *alwaysSave = 0,
QList<IDocument *> *failedToClose = 0);
bool *alwaysSave = nullptr,
QList<IDocument *> *failedToClose = nullptr);
static bool saveModifiedDocument(IDocument *document,
const QString &message = QString(), bool *canceled = 0,
const QString &message = QString(),
bool *canceled = nullptr,
const QString &alwaysSaveMessage = QString(),
bool *alwaysSave = 0,
QList<IDocument *> *failedToClose = 0);
bool *alwaysSave = nullptr,
QList<IDocument *> *failedToClose = nullptr);
static QString fileDialogLastVisitedDirectory();
static void setFileDialogLastVisitedDirectory(const QString &);
@@ -367,6 +367,7 @@ DocumentModel::Entry *DocumentModelPrivate::removeEditor(IEditor *editor)
QTC_ASSERT(d->m_editors.contains(document), return nullptr);
d->m_editors[document].removeAll(editor);
DocumentModel::Entry *entry = DocumentModel::entryForDocument(document);
QTC_ASSERT(entry, return nullptr);
if (d->m_editors.value(document).isEmpty()) {
d->m_editors.remove(document);
entry->document = new IDocument;
@@ -26,7 +26,6 @@
#include "basefilefilter.h"
#include <coreplugin/editormanager/editormanager.h>
#include <utils/camelhumpmatcher.h>
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
@@ -100,9 +99,8 @@ QList<LocatorFilterEntry> BaseFileFilter::matchesFor(QFutureInterface<LocatorFil
QList<LocatorFilterEntry> goodEntries;
const QString entry = QDir::fromNativeSeparators(origEntry);
const EditorManager::FilePathInfo fp = EditorManager::splitLineAndColumnNumber(entry);
const QRegularExpression regexp = containsWildcard(entry)
? createWildcardRegExp(entry) : CamelHumpMatcher::createCamelHumpRegExp(entry);
const QRegularExpression regexp = createRegExp(entry);
if (!regexp.isValid()) {
d->m_current.clear(); // free memory
return betterEntries;
@@ -143,16 +141,14 @@ QList<LocatorFilterEntry> BaseFileFilter::matchesFor(QFutureInterface<LocatorFil
filterEntry.fileName = path;
filterEntry.extraInfo = FileUtils::shortNativePath(FileName(fi));
LocatorFilterEntry::HighlightInfo::DataType hDataType = LocatorFilterEntry::HighlightInfo::DisplayName;
const bool betterMatch = match.capturedStart() == 0;
if (hasPathSeparator) {
match = regexp.match(filterEntry.extraInfo);
hDataType = LocatorFilterEntry::HighlightInfo::ExtraInfo;
}
const CamelHumpMatcher::HighlightingPositions positions =
CamelHumpMatcher::highlightingPositions(match);
filterEntry.highlightInfo =
LocatorFilterEntry::HighlightInfo(positions.starts, positions.lengths, hDataType);
highlightInfo(match, LocatorFilterEntry::HighlightInfo::ExtraInfo);
} else {
filterEntry.highlightInfo = highlightInfo(match);
}
if (betterMatch)
betterEntries.append(filterEntry);
@@ -26,6 +26,7 @@
#include "ilocatorfilter.h"
#include <coreplugin/coreconstants.h>
#include <utils/camelhumpmatcher.h>
#include <QBoxLayout>
#include <QCheckBox>
@@ -212,7 +213,7 @@ bool ILocatorFilter::containsWildcard(const QString &str)
* The regular expression contains capture groups to allow highlighting
* matched characters after a match.
*/
QRegularExpression ILocatorFilter::createWildcardRegExp(const QString &text)
static QRegularExpression createWildcardRegExp(const QString &text)
{
QString pattern = '(' + text + ')';
pattern.replace('?', ").(");
@@ -221,6 +222,21 @@ QRegularExpression ILocatorFilter::createWildcardRegExp(const QString &text)
return QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption);
}
QRegularExpression ILocatorFilter::createRegExp(const QString &text)
{
return containsWildcard(text) ? createWildcardRegExp(text)
: CamelHumpMatcher::createCamelHumpRegExp(text);
}
LocatorFilterEntry::HighlightInfo ILocatorFilter::highlightInfo(
const QRegularExpressionMatch &match, LocatorFilterEntry::HighlightInfo::DataType dataType)
{
const CamelHumpMatcher::HighlightingPositions positions =
CamelHumpMatcher::highlightingPositions(match);
return LocatorFilterEntry::HighlightInfo(positions.starts, positions.lengths, dataType);
}
/*!
Specifies a title for configuration dialogs.
*/
@@ -144,7 +144,9 @@ public:
static Qt::CaseSensitivity caseSensitivity(const QString &str);
static bool containsWildcard(const QString &str);
static QRegularExpression createWildcardRegExp(const QString &text);
static QRegularExpression createRegExp(const QString &text);
LocatorFilterEntry::HighlightInfo highlightInfo(const QRegularExpressionMatch &match,
LocatorFilterEntry::HighlightInfo::DataType dataType = LocatorFilterEntry::HighlightInfo::DisplayName);
static QString msgConfigureDialogTitle();
static QString msgPrefixLabel();
@@ -27,7 +27,6 @@
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <utils/camelhumpmatcher.h>
#include <utils/fileutils.h>
#include <QAbstractItemModel>
@@ -61,9 +60,8 @@ QList<LocatorFilterEntry> OpenDocumentsFilter::matchesFor(QFutureInterface<Locat
QList<LocatorFilterEntry> goodEntries;
QList<LocatorFilterEntry> betterEntries;
const EditorManager::FilePathInfo fp = EditorManager::splitLineAndColumnNumber(entry);
const QRegularExpression regexp = containsWildcard(entry)
? createWildcardRegExp(entry) : CamelHumpMatcher::createCamelHumpRegExp(entry);
const QRegularExpression regexp = createRegExp(entry);
if (!regexp.isValid())
return goodEntries;
@@ -76,13 +74,10 @@ QList<LocatorFilterEntry> OpenDocumentsFilter::matchesFor(QFutureInterface<Locat
QString displayName = editorEntry.displayName;
const QRegularExpressionMatch match = regexp.match(displayName);
if (match.hasMatch()) {
const CamelHumpMatcher::HighlightingPositions positions =
CamelHumpMatcher::highlightingPositions(match);
LocatorFilterEntry filterEntry(this, displayName, QString(fileName + fp.postfix));
filterEntry.extraInfo = FileUtils::shortNativePath(FileName::fromString(fileName));
filterEntry.fileName = fileName;
filterEntry.highlightInfo.starts = positions.starts;
filterEntry.highlightInfo.lengths = positions.lengths;
filterEntry.highlightInfo = highlightInfo(match);
if (match.capturedStart() == 0)
betterEntries.append(filterEntry);
else
@@ -30,7 +30,6 @@
#include <coreplugin/idocument.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <utils/camelhumpmatcher.h>
#include <QRegularExpression>
@@ -67,9 +66,7 @@ QList<Core::LocatorFilterEntry> CppCurrentDocumentFilter::matchesFor(
QList<Core::LocatorFilterEntry> goodEntries;
QList<Core::LocatorFilterEntry> betterEntries;
const QRegularExpression regexp = containsWildcard(entry)
? createWildcardRegExp(entry) : CamelHumpMatcher::createCamelHumpRegExp(entry);
const QRegularExpression regexp = createRegExp(entry);
if (!regexp.isValid())
return goodEntries;
@@ -98,14 +95,13 @@ QList<Core::LocatorFilterEntry> CppCurrentDocumentFilter::matchesFor(
Core::LocatorFilterEntry filterEntry(this, name, id, info->icon());
filterEntry.extraInfo = extraInfo;
if (!match.hasMatch()) {
if (match.hasMatch()) {
filterEntry.highlightInfo = highlightInfo(match);
} else {
match = regexp.match(extraInfo);
filterEntry.highlightInfo.dataType = Core::LocatorFilterEntry::HighlightInfo::ExtraInfo;
filterEntry.highlightInfo =
highlightInfo(match, Core::LocatorFilterEntry::HighlightInfo::ExtraInfo);
}
const CamelHumpMatcher::HighlightingPositions positions =
CamelHumpMatcher::highlightingPositions(match);
filterEntry.highlightInfo.starts = positions.starts;
filterEntry.highlightInfo.lengths = positions.lengths;
if (betterMatch)
betterEntries.append(filterEntry);
+2 -7
View File
@@ -28,7 +28,6 @@
#include <coreplugin/editormanager/editormanager.h>
#include <utils/algorithm.h>
#include <utils/camelhumpmatcher.h>
#include <QRegularExpression>
@@ -76,9 +75,8 @@ QList<Core::LocatorFilterEntry> CppLocatorFilter::matchesFor(
const Qt::CaseSensitivity caseSensitivityForPrefix = caseSensitivity(entry);
bool hasColonColon = entry.contains(QLatin1String("::"));
const IndexItem::ItemType wanted = matchTypes();
const QRegularExpression regexp = containsWildcard(entry)
? createWildcardRegExp(entry) : CamelHumpMatcher::createCamelHumpRegExp(entry);
const QRegularExpression regexp = createRegExp(entry);
if (!regexp.isValid())
return goodEntries;
@@ -95,10 +93,7 @@ QList<Core::LocatorFilterEntry> CppLocatorFilter::matchesFor(
// to update the match if the displayName is different from matchString
if (matchString != filterEntry.displayName)
match = regexp.match(filterEntry.displayName);
const CamelHumpMatcher::HighlightingPositions positions =
CamelHumpMatcher::highlightingPositions(match);
filterEntry.highlightInfo.starts = positions.starts;
filterEntry.highlightInfo.lengths = positions.lengths;
filterEntry.highlightInfo = highlightInfo(match);
if (matchString.startsWith(entry, caseSensitivityForPrefix))
bestEntries.append(filterEntry);
+21 -47
View File
@@ -194,22 +194,10 @@ public:
CdbEngine::CommandHandler handler;
};
static inline bool validMode(DebuggerStartMode sm)
// Accessed by DebuggerRunTool
DebuggerEngine *createCdbEngine()
{
return sm != NoStartMode;
}
// Accessed by RunControlFactory
DebuggerEngine *createCdbEngine(QStringList *errors, DebuggerStartMode sm)
{
if (HostOsInfo::isWindowsHost()) {
if (validMode(sm))
return new CdbEngine();
errors->append(CdbEngine::tr("Internal error: Invalid start parameters passed for the CDB engine."));
} else {
errors->append(CdbEngine::tr("Unsupported CDB host system."));
}
return 0;
return new CdbEngine;
}
void addCdbOptionPages(QList<Core::IOptionsPage *> *opts)
@@ -224,24 +212,27 @@ void addCdbOptionPages(QList<Core::IOptionsPage *> *opts)
CdbEngine::CdbEngine() :
m_tokenPrefix("<token>"),
m_effectiveStartMode(NoStartMode),
m_accessible(false),
m_specialStopMode(NoSpecialStop),
m_nextCommandToken(0),
m_currentBuiltinResponseToken(-1),
m_extensionCommandPrefix("!" QT_CREATOR_CDB_EXT "."),
m_operateByInstructionPending(true),
m_operateByInstruction(true), // Default CDB setting
m_hasDebuggee(false),
m_wow64State(wow64Uninitialized),
m_elapsedLogTime(0),
m_sourceStepInto(false),
m_watchPointX(0),
m_watchPointY(0),
m_ignoreCdbOutput(false)
m_extensionCommandPrefix("!" QT_CREATOR_CDB_EXT ".")
{
setObjectName("CdbEngine");
DisplayFormats stringFormats;
stringFormats.append(SimpleFormat);
stringFormats.append(SeparateFormat);
WatchHandler *wh = watchHandler();
wh->addTypeFormats("QString", stringFormats);
wh->addTypeFormats("QString *", stringFormats);
wh->addTypeFormats("QByteArray", stringFormats);
wh->addTypeFormats("QByteArray *", stringFormats);
wh->addTypeFormats("std__basic_string", stringFormats); // Python dumper naming convention for std::[w]string
DisplayFormats imageFormats;
imageFormats.append(SimpleFormat);
imageFormats.append(EnhancedFormat);
wh->addTypeFormats("QImage", imageFormats);
wh->addTypeFormats("QImage *", imageFormats);
connect(action(OperateByInstruction), &QAction::triggered,
this, &CdbEngine::operateByInstructionTriggered);
connect(action(CreateFullBacktrace), &QAction::triggered,
@@ -477,23 +468,6 @@ void CdbEngine::setupEngine()
STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
notifyEngineSetupFailed();
}
DisplayFormats stringFormats;
stringFormats.append(SimpleFormat);
stringFormats.append(SeparateFormat);
WatchHandler *wh = watchHandler();
wh->addTypeFormats("QString", stringFormats);
wh->addTypeFormats("QString *", stringFormats);
wh->addTypeFormats("QByteArray", stringFormats);
wh->addTypeFormats("QByteArray *", stringFormats);
wh->addTypeFormats("std__basic_string", stringFormats); // Python dumper naming convention for std::[w]string
DisplayFormats imageFormats;
imageFormats.append(SimpleFormat);
imageFormats.append(EnhancedFormat);
wh->addTypeFormats("QImage", imageFormats);
wh->addTypeFormats("QImage *", imageFormats);
}
bool CdbEngine::launchCDB(const DebuggerRunParameters &sp, QString *errorMessage)
+15 -15
View File
@@ -224,40 +224,40 @@ private:
QProcess m_process;
QScopedPointer<Utils::ConsoleProcess> m_consoleStub;
DebuggerStartMode m_effectiveStartMode;
DebuggerStartMode m_effectiveStartMode = NoStartMode;
QByteArray m_outputBuffer;
//! Debugger accessible (expecting commands)
bool m_accessible;
SpecialStopMode m_specialStopMode;
bool m_accessible = false;
SpecialStopMode m_specialStopMode = NoSpecialStop;
ProjectExplorer::DeviceProcessSignalOperation::Ptr m_signalOperation;
int m_nextCommandToken;
int m_nextCommandToken = 0;
QHash<int, DebuggerCommand> m_commandForToken;
QString m_currentBuiltinResponse;
int m_currentBuiltinResponseToken;
int m_currentBuiltinResponseToken = -1;
QMap<QString, NormalizedSourceFileName> m_normalizedFileCache;
const QString m_extensionCommandPrefix; //!< Library name used as prefix
bool m_operateByInstructionPending; //!< Creator operate by instruction action changed.
bool m_operateByInstruction;
bool m_hasDebuggee;
bool m_operateByInstructionPending = true; //!< Creator operate by instruction action changed.
bool m_operateByInstruction = true; // Default CDB setting.
bool m_hasDebuggee = false;
enum Wow64State {
wow64Uninitialized,
noWow64Stack,
wow64Stack32Bit,
wow64Stack64Bit
} m_wow64State;
} m_wow64State = wow64Uninitialized;
QTime m_logTime;
mutable int m_elapsedLogTime;
mutable int m_elapsedLogTime = 0;
QString m_extensionMessageBuffer;
bool m_sourceStepInto;
int m_watchPointX;
int m_watchPointY;
bool m_sourceStepInto = false;
int m_watchPointX = 0;
int m_watchPointY = 0;
PendingBreakPointMap m_pendingBreakpointMap;
PendingBreakPointMap m_insertSubBreakpointMap;
PendingBreakPointMap m_pendingSubBreakpointMap;
bool m_autoBreakPointCorrection;
bool m_autoBreakPointCorrection = false;
QHash<QString, QString> m_fileNameModuleHash;
QMultiHash<QString, quint64> m_symbolAddressCache;
bool m_ignoreCdbOutput;
bool m_ignoreCdbOutput = false;
QVariantList m_customSpecialStopData;
QList<SourcePathMapping> m_sourcePathMappings;
QScopedPointer<GdbMi> m_coreStopReason;
+1 -9
View File
@@ -191,15 +191,7 @@ enum DebuggerEngineType
GdbEngineType = 0x001,
CdbEngineType = 0x004,
PdbEngineType = 0x008,
QmlEngineType = 0x020,
QmlCppEngineType = 0x040,
LldbEngineType = 0x100,
AllEngineTypes = GdbEngineType
| CdbEngineType
| PdbEngineType
| QmlEngineType
| QmlCppEngineType
| LldbEngineType
LldbEngineType = 0x100
};
enum DebuggerLanguage
-1
View File
@@ -128,7 +128,6 @@ public:
// Macro-expanded and passed to debugger startup.
QString additionalStartupCommands;
DebuggerEngineType masterEngineType = NoEngineType;
DebuggerEngineType cppEngineType = NoEngineType;
bool isCppDebugging = true;
+1 -1
View File
@@ -1179,6 +1179,7 @@ bool DebuggerPluginPrivate::parseArgument(QStringList::const_iterator &it,
auto runControl = new RunControl(nullptr, ProjectExplorer::Constants::DEBUG_RUN_MODE);
auto debugger = new DebuggerRunTool(runControl, kit);
debugger->setInferiorExecutable(executable);
if (pid) {
debugger->setStartMode(AttachExternal);
debugger->setCloseMode(DetachAtClose);
@@ -1198,7 +1199,6 @@ bool DebuggerPluginPrivate::parseArgument(QStringList::const_iterator &it,
debugger->setStartMessage(tr("Attaching to core file %1.").arg(coreFile));
} else {
debugger->setStartMode(StartExternal);
debugger->setInferiorExecutable(executable);
debugger->setRunControlName(tr("Executable file \"%1\"").arg(executable));
debugger->setStartMessage(tr("Debugging file %1.").arg(executable));
}
+93 -56
View File
@@ -55,6 +55,8 @@
#include <utils/portlist.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <utils/temporarydirectory.h>
#include <utils/temporaryfile.h>
#include <utils/url.h>
#include <coreplugin/icore.h>
@@ -77,11 +79,11 @@ enum { debug = 0 };
namespace Debugger {
namespace Internal {
DebuggerEngine *createCdbEngine(QStringList *error, DebuggerStartMode sm);
DebuggerEngine *createCdbEngine();
DebuggerEngine *createGdbEngine();
DebuggerEngine *createPdbEngine();
DebuggerEngine *createQmlEngine(bool useTerminal);
DebuggerEngine *createQmlCppEngine(DebuggerEngine *cppEngine, bool useTerminal);
DebuggerEngine *createQmlEngine();
DebuggerEngine *createQmlCppEngine(DebuggerEngine *cppEngine);
DebuggerEngine *createLldbEngine();
class LocalProcessRunner : public RunWorker
@@ -175,10 +177,73 @@ public:
Utils::QtcProcess m_proc;
};
class CoreUnpacker : public RunWorker
{
public:
CoreUnpacker(RunControl *runControl, const QString &coreFileName)
: RunWorker(runControl), m_coreFileName(coreFileName)
{}
QString coreFileName() const { return m_tempCoreFileName; }
private:
~CoreUnpacker() final
{
m_coreUnpackProcess.blockSignals(true);
m_coreUnpackProcess.terminate();
m_coreUnpackProcess.deleteLater();
if (m_tempCoreFile.isOpen())
m_tempCoreFile.close();
QFile::remove(m_tempCoreFileName);
}
void start() final
{
{
Utils::TemporaryFile tmp("tmpcore-XXXXXX");
tmp.open();
m_tempCoreFileName = tmp.fileName();
}
m_coreUnpackProcess.setWorkingDirectory(TemporaryDirectory::masterDirectoryPath());
connect(&m_coreUnpackProcess, static_cast<void (QProcess::*)(int)>(&QProcess::finished),
this, &CoreUnpacker::reportStarted);
const QString msg = DebuggerRunTool::tr("Unpacking core file to %1");
appendMessage(msg.arg(m_tempCoreFileName), LogMessageFormat);
if (m_coreFileName.endsWith(".lzo")) {
m_coreUnpackProcess.start("lzop", {"-o", m_tempCoreFileName, "-x", m_coreFileName});
return;
}
if (m_coreFileName.endsWith(".gz")) {
appendMessage(msg.arg(m_tempCoreFileName), LogMessageFormat);
m_tempCoreFile.setFileName(m_tempCoreFileName);
m_tempCoreFile.open(QFile::WriteOnly);
connect(&m_coreUnpackProcess, &QProcess::readyRead, this, [this] {
m_tempCoreFile.write(m_coreUnpackProcess.readAll());
});
m_coreUnpackProcess.start("gzip", {"-c", "-d", m_coreFileName});
return;
}
QTC_CHECK(false);
reportFailure("Unknown file extension in " + m_coreFileName);
}
QFile m_tempCoreFile;
QString m_coreFileName;
QString m_tempCoreFileName;
QProcess m_coreUnpackProcess;
};
class DebuggerRunToolPrivate
{
public:
QPointer<TerminalRunner> terminalRunner;
QPointer<CoreUnpacker> coreUnpacker;
};
} // namespace Internal
@@ -196,7 +261,6 @@ void DebuggerRunTool::setStartMode(DebuggerStartMode startMode)
m_runParameters.startMode = AttachToRemoteProcess;
m_runParameters.isCppDebugging = false;
m_runParameters.isQmlDebugging = true;
m_runParameters.masterEngineType = QmlEngineType;
m_runParameters.closeMode = KillAtClose;
// FIXME: This is horribly wrong.
@@ -376,6 +440,11 @@ void DebuggerRunTool::setStartMessage(const QString &msg)
void DebuggerRunTool::setCoreFileName(const QString &coreFile, bool isSnapshot)
{
if (coreFile.endsWith(".gz") || coreFile.endsWith(".lzo")) {
d->coreUnpacker = new CoreUnpacker(runControl(), coreFile);
addStartDependency(d->coreUnpacker);
}
m_runParameters.coreFile = coreFile;
m_runParameters.isSnapshot = isSnapshot;
}
@@ -421,29 +490,6 @@ void DebuggerRunTool::addSearchDirectory(const QString &dir)
m_runParameters.additionalSearchDirectories.append(dir);
}
static QLatin1String engineTypeName(DebuggerEngineType et)
{
switch (et) {
case Debugger::NoEngineType:
break;
case Debugger::GdbEngineType:
return QLatin1String("Gdb engine");
case Debugger::CdbEngineType:
return QLatin1String("Cdb engine");
case Debugger::PdbEngineType:
return QLatin1String("Pdb engine");
case Debugger::QmlEngineType:
return QLatin1String("QML engine");
case Debugger::QmlCppEngineType:
return QLatin1String("QML C++ engine");
case Debugger::LldbEngineType:
return QLatin1String("LLDB command line engine");
case Debugger::AllEngineTypes:
break;
}
return QLatin1String("No engine");
}
void DebuggerRunTool::start()
{
Debugger::Internal::saveModeToRestore();
@@ -469,6 +515,9 @@ void DebuggerRunTool::start()
// return;
// }
if (d->coreUnpacker)
m_runParameters.coreFile = d->coreUnpacker->coreFileName();
if (!fixupParameters())
return;
@@ -480,19 +529,17 @@ void DebuggerRunTool::start()
runControl()->setDisplayName(m_runParameters.displayName);
DebuggerEngine *cppEngine = nullptr;
if (!m_engine) {
switch (m_runParameters.cppEngineType) {
case GdbEngineType:
cppEngine = createGdbEngine();
break;
case CdbEngineType: {
QStringList errors;
cppEngine = createCdbEngine(&errors, m_runParameters.startMode);
if (!errors.isEmpty()) {
reportFailure(errors.join('\n'));
case CdbEngineType:
if (!HostOsInfo::isWindowsHost()) {
reportFailure(tr("Unsupported CDB host system."));
return;
}
}
cppEngine = createCdbEngine();
break;
case LldbEngineType:
cppEngine = createLldbEngine();
@@ -501,26 +548,22 @@ void DebuggerRunTool::start()
cppEngine = createPdbEngine();
break;
default:
QTC_CHECK(false);
// Can happen for pure Qml.
break;
}
switch (m_runParameters.masterEngineType) {
case QmlEngineType:
m_engine = createQmlEngine(terminalRunner() != nullptr);
break;
case QmlCppEngineType:
if (m_runParameters.isQmlDebugging) {
if (cppEngine)
m_engine = createQmlCppEngine(cppEngine, terminalRunner() != nullptr);
break;
default:
m_engine = createQmlCppEngine(cppEngine);
else
m_engine = createQmlEngine();
} else {
m_engine = cppEngine;
break;
}
}
if (!m_engine) {
reportFailure(DebuggerPlugin::tr("Unable to create a debugging engine of the type \"%1\"").
arg(engineTypeName(m_runParameters.masterEngineType)));
reportFailure(DebuggerPlugin::tr("Unable to create a debugging engine"));
return;
}
@@ -670,18 +713,15 @@ bool DebuggerRunTool::fixupParameters()
}
}
if (rp.masterEngineType == NoEngineType) {
if (rp.isQmlDebugging) {
QmlDebug::QmlDebugServicesPreset service;
if (rp.isCppDebugging) {
if (rp.nativeMixedEnabled) {
service = QmlDebug::QmlNativeDebuggerServices;
} else {
rp.masterEngineType = QmlCppEngineType;
service = QmlDebug::QmlDebuggerServices;
}
} else {
rp.masterEngineType = QmlEngineType;
service = QmlDebug::QmlDebuggerServices;
}
if (rp.startMode != AttachExternal && rp.startMode != AttachCrashedExternal) {
@@ -691,10 +731,6 @@ bool DebuggerRunTool::fixupParameters()
QtcProcess::addArg(&rp.inferior.commandLineArguments, qmlarg);
}
}
}
if (rp.masterEngineType == NoEngineType)
rp.masterEngineType = rp.cppEngineType;
if (rp.startMode == NoStartMode)
rp.startMode = StartInternal;
@@ -758,7 +794,6 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, Kit *kit)
kit = runConfig->target()->kit();
QTC_ASSERT(kit, return);
m_runParameters.cppEngineType = DebuggerKitInformation::engineType(kit);
m_runParameters.sysRoot = SysRootKitInformation::sysRoot(kit).toString();
m_runParameters.macroExpander = kit->macroExpander();
m_runParameters.debugger = DebuggerKitInformation::runnable(kit);
@@ -778,6 +813,9 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, Kit *kit)
m_runParameters.multiProcess = aspect->useMultiProcess();
}
if (m_runParameters.isCppDebugging)
m_runParameters.cppEngineType = DebuggerKitInformation::engineType(kit);
const QByteArray envBinary = qgetenv("QTC_DEBUGGER_PATH");
if (!envBinary.isEmpty())
m_runParameters.debugger.executable = QString::fromLocal8Bit(envBinary);
@@ -815,8 +853,7 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, Kit *kit)
m_runParameters.inferior.commandLineArguments.append(' ');
m_runParameters.inferior.commandLineArguments.append(args);
}
m_runParameters.cppEngineType = PdbEngineType;
m_runParameters.masterEngineType = PdbEngineType;
m_engine = createPdbEngine();
}
}
}
@@ -32,9 +32,6 @@
#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/devicesupport/deviceusedportsgatherer.h>
#include <ssh/sshconnection.h> // FIXME: Remove after downstream was adapted
#include <QHostAddress> // FIXME: Remove after downstream was adapted
namespace Debugger {
namespace Internal {
@@ -1,2 +0,0 @@
// Remove after downstream was adapted
+70 -208
View File
@@ -67,7 +67,6 @@
#include <utils/qtcprocess.h>
#include <utils/savedaction.h>
#include <utils/synchronousprocess.h>
#include <utils/temporarydirectory.h>
#include <utils/temporaryfile.h>
#include <QDirIterator>
@@ -219,21 +218,6 @@ GdbEngine::GdbEngine()
GdbEngine::~GdbEngine()
{
if (isCoreEngine()) {
if (m_coreUnpackProcess) {
m_coreUnpackProcess->blockSignals(true);
m_coreUnpackProcess->terminate();
m_coreUnpackProcess->deleteLater();
m_coreUnpackProcess = nullptr;
if (m_tempCoreFile.isOpen())
m_tempCoreFile.close();
}
if (!m_tempCoreName.isEmpty()) {
QFile tmpFile(m_tempCoreName);
tmpFile.remove();
}
}
//ExtensionSystem::PluginManager::removeObject(m_debugInfoTaskHandler);
delete m_debugInfoTaskHandler;
m_debugInfoTaskHandler = 0;
@@ -1763,38 +1747,6 @@ void GdbEngine::handleInferiorShutdown(const DebuggerResponse &response)
notifyInferiorShutdownFailed();
}
void GdbEngine::notifyAdapterShutdownFailed()
{
showMessage("ADAPTER SHUTDOWN FAILED");
CHECK_STATE(EngineShutdownRequested);
notifyEngineShutdownFailed();
}
void GdbEngine::notifyAdapterShutdownOk()
{
CHECK_STATE(EngineShutdownRequested);
showMessage(QString("INITIATE GDBENGINE SHUTDOWN IN STATE %1, PROC: %2")
.arg(lastGoodState()).arg(m_gdbProc.state()));
m_commandsDoneCallback = 0;
switch (m_gdbProc.state()) {
case QProcess::Running: {
if (runParameters().closeMode == KillAndExitMonitorAtClose)
runCommand({"monitor exit"});
runCommand({"exitGdb", ExitRequest, CB(handleGdbExit)});
break;
}
case QProcess::NotRunning:
// Cannot find executable.
notifyEngineShutdownOk();
break;
case QProcess::Starting:
showMessage("GDB NOT REALLY RUNNING; KILLING IT");
m_gdbProc.kill();
notifyEngineShutdownFailed();
break;
}
}
void GdbEngine::handleGdbExit(const DebuggerResponse &response)
{
if (response.resultClass == ResultExit) {
@@ -3767,8 +3719,24 @@ static SourcePathMap mergeStartParametersSourcePathMap(const DebuggerRunParamete
// Starting up & shutting down
//
void GdbEngine::startGdb(const QStringList &args)
void GdbEngine::setupEngine()
{
CHECK_STATE(EngineSetupRequested);
showMessage("TRYING TO START ADAPTER");
if (isRemoteEngine() && HostOsInfo::isWindowsHost())
m_gdbProc.setUseCtrlCStub(runParameters().useCtrlCStub); // This is only set for QNX
QStringList gdbArgs;
if (isPlainEngine()) {
if (!m_outputCollector.listen()) {
handleAdapterStartFailed(tr("Cannot set up communication with child process: %1")
.arg(m_outputCollector.errorString()));
return;
}
gdbArgs.append("--tty=" + m_outputCollector.serverName());
}
const QString tests = QString::fromLocal8Bit(qgetenv("QTC_DEBUGGER_TESTS"));
foreach (const QStringRef &test, tests.splitRef(QLatin1Char(',')))
m_testCases.insert(test.toInt());
@@ -3787,12 +3755,10 @@ void GdbEngine::startGdb(const QStringList &args)
return;
}
QStringList gdbArgs;
gdbArgs << "-i";
gdbArgs << "mi";
if (!boolSetting(LoadGdbInit))
gdbArgs << "-n";
gdbArgs += args;
connect(&m_gdbProc, &QProcess::errorOccurred, this, &GdbEngine::handleGdbError);
connect(&m_gdbProc, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
@@ -4162,27 +4128,6 @@ void GdbEngine::notifyInferiorSetupFailedHelper(const QString &msg)
notifyInferiorSetupFailed();
}
void GdbEngine::handleAdapterCrashed(const QString &msg)
{
showMessage("ADAPTER CRASHED");
// The adapter is expected to have cleaned up after itself when we get here,
// so the effect is about the same as AdapterStartFailed => use it.
// Don't bother with state transitions - this can happen in any state and
// the end result is always the same, so it makes little sense to find a
// "path" which does not assert.
if (state() == EngineSetupRequested)
notifyEngineSetupFailed();
else
notifyEngineIll();
// No point in being friendly here ...
m_gdbProc.kill();
if (!msg.isEmpty())
AsynchronousMessageBox::critical(tr("Adapter crashed"), msg);
}
void GdbEngine::createFullBacktrace()
{
DebuggerCommand cmd("thread apply all bt full", NeedsTemporaryStop | ConsoleCommand);
@@ -4314,61 +4259,12 @@ bool GdbEngine::isTermEngine() const
return !isCoreEngine() && !isAttachEngine() && !isRemoteEngine() && terminal();
}
void GdbEngine::setupEngine()
{
m_startMode = runParameters().startMode;
CHECK_STATE(EngineSetupRequested);
showMessage("TRYING TO START ADAPTER");
if (isAttachEngine()) {
startGdb();
} else if (isRemoteEngine()) {
if (HostOsInfo::isWindowsHost())
m_gdbProc.setUseCtrlCStub(runParameters().useCtrlCStub); // This is only set for QNX
startGdb();
} else if (isTermEngine()) {
showMessage("TRYING TO START ADAPTER");
startGdb();
} else if (isCoreEngine()) {
CHECK_STATE(EngineSetupRequested);
showMessage("TRYING TO START ADAPTER");
const DebuggerRunParameters &rp = runParameters();
m_executable = rp.inferior.executable;
QFileInfo fi(rp.coreFile);
m_coreName = fi.absoluteFilePath();
unpackCoreIfNeeded();
} else if (isPlainEngine()) {
QStringList gdbArgs;
if (!m_outputCollector.listen()) {
handleAdapterStartFailed(tr("Cannot set up communication with child process: %1")
.arg(m_outputCollector.errorString()));
return;
}
gdbArgs.append("--tty=" + m_outputCollector.serverName());
startGdb(gdbArgs);
}
}
void GdbEngine::setupInferior()
{
CHECK_STATE(InferiorSetupRequested);
const DebuggerRunParameters &rp = runParameters();
if (isAttachEngine()) {
// Task 254674 does not want to remove them
//qq->breakHandler()->removeAllBreakpoints();
@@ -4377,7 +4273,6 @@ void GdbEngine::setupInferior()
} else if (isRemoteEngine()) {
setLinuxOsAbi();
const DebuggerRunParameters &rp = runParameters();
QString symbolFile;
if (!rp.symbolFile.isEmpty()) {
QFileInfo fi(rp.symbolFile);
@@ -4438,8 +4333,30 @@ void GdbEngine::setupInferior()
} else if (isCoreEngine()) {
setLinuxOsAbi();
QString executable = rp.inferior.executable;
if (executable.isEmpty()) {
CoreInfo cinfo = CoreInfo::readExecutableNameFromCore(rp.debugger, rp.coreFile);
if (!cinfo.isCore) {
AsynchronousMessageBox::warning(tr("Error Loading Core File"),
tr("The specified file does not appear to be a core file."));
notifyInferiorSetupFailed();
return;
}
executable = cinfo.foundExecutableName;
if (executable.isEmpty()) {
AsynchronousMessageBox::warning(tr("Error Loading Symbols"),
tr("No executable to load symbols from specified core."));
notifyInferiorSetupFailed();
return;
}
}
// Do that first, otherwise no symbols are loaded.
QFileInfo fi(m_executable);
QFileInfo fi(executable);
QString path = fi.absoluteFilePath();
runCommand({"-file-exec-and-symbols \"" + path + '"',
CB(handleFileExecAndSymbols)});
@@ -4501,7 +4418,7 @@ void GdbEngine::runEngine()
} else if (isCoreEngine()) {
runCommand({"target core " + coreFileName(), CB(handleTargetCore)});
runCommand({"target core " + runParameters().coreFile, CB(handleTargetCore)});
} else if (isTermEngine()) {
@@ -4628,7 +4545,27 @@ void GdbEngine::shutdownEngine()
m_outputCollector.shutdown();
}
notifyAdapterShutdownOk();
CHECK_STATE(EngineShutdownRequested);
showMessage(QString("INITIATE GDBENGINE SHUTDOWN IN STATE %1, PROC: %2")
.arg(lastGoodState()).arg(m_gdbProc.state()));
m_commandsDoneCallback = 0;
switch (m_gdbProc.state()) {
case QProcess::Running: {
if (runParameters().closeMode == KillAndExitMonitorAtClose)
runCommand({"monitor exit"});
runCommand({"exitGdb", ExitRequest, CB(handleGdbExit)});
break;
}
case QProcess::NotRunning:
// Cannot find executable.
notifyEngineShutdownOk();
break;
case QProcess::Starting:
showMessage("GDB NOT REALLY RUNNING; KILLING IT");
m_gdbProc.kill();
notifyEngineShutdownFailed();
break;
}
}
void GdbEngine::handleFileExecAndSymbols(const DebuggerResponse &response)
@@ -4652,7 +4589,7 @@ void GdbEngine::handleFileExecAndSymbols(const DebuggerResponse &response)
} else if (isCoreEngine()) {
QString core = coreFileName();
QString core = runParameters().coreFile;
if (response.resultClass == ResultDone) {
showMessage(tr("Symbols found."), StatusBar);
handleInferiorPrepared();
@@ -4954,7 +4891,11 @@ CoreInfo CoreInfo::readExecutableNameFromCore(const StandardRunnable &debugger,
cinfo.rawStringFromCore = QString::fromLocal8Bit(reader.readCoreName(&cinfo.isCore));
cinfo.foundExecutableName = findExecutableFromName(cinfo.rawStringFromCore, coreFile);
#else
QStringList args = {"-nx", "-batch", "-c", coreFile};
QStringList args = {"-nx", "-batch"};
// Multiarch GDB on Windows crashes if osabi is cygwin (the default) when opening a core dump.
if (HostOsInfo::isWindowsHost())
args += {"-ex", "set osabi GNU/Linux"};
args += {"-ex", "core " + coreFile};
SynchronousProcess proc;
QStringList envLang = QProcess::systemEnvironment();
@@ -4981,41 +4922,6 @@ CoreInfo CoreInfo::readExecutableNameFromCore(const StandardRunnable &debugger,
return cinfo;
}
void GdbEngine::continueSetupEngine()
{
if (isCoreEngine()) {
bool isCore = true;
if (m_coreUnpackProcess) {
isCore = m_coreUnpackProcess->exitCode() == 0;
m_coreUnpackProcess->deleteLater();
m_coreUnpackProcess = 0;
if (m_tempCoreFile.isOpen())
m_tempCoreFile.close();
}
if (isCore && m_executable.isEmpty()) {
CoreInfo cinfo =
CoreInfo::readExecutableNameFromCore(runParameters().debugger, coreFileName());
if (cinfo.isCore) {
m_executable = cinfo.foundExecutableName;
if (m_executable.isEmpty()) {
AsynchronousMessageBox::warning(tr("Error Loading Symbols"),
tr("No executable to load symbols from specified core."));
notifyEngineSetupFailed();
return;
}
}
}
if (isCore) {
startGdb();
} else {
AsynchronousMessageBox::warning(tr("Error Loading Core File"),
tr("The specified file does not appear to be a core file."));
notifyEngineSetupFailed();
}
}
}
void GdbEngine::handleTargetCore(const DebuggerResponse &response)
{
CHECK_STATE(EngineRunRequested);
@@ -5045,50 +4951,6 @@ void GdbEngine::handleCoreRoundTrip(const DebuggerResponse &response)
QTimer::singleShot(1000, this, &GdbEngine::loadAllSymbols);
}
static QString tempCoreFilename()
{
Utils::TemporaryFile tmp("tmpcore-XXXXXX");
tmp.open();
return tmp.fileName();
}
void GdbEngine::unpackCoreIfNeeded()
{
QStringList arguments;
const QString msg = "Unpacking core file to %1";
if (m_coreName.endsWith(".lzo")) {
m_tempCoreName = tempCoreFilename();
showMessage(msg.arg(m_tempCoreName));
arguments << "-o" << m_tempCoreName << "-x" << m_coreName;
m_coreUnpackProcess = new QProcess(this);
m_coreUnpackProcess->setWorkingDirectory(TemporaryDirectory::masterDirectoryPath());
m_coreUnpackProcess->start("lzop", arguments);
connect(m_coreUnpackProcess, static_cast<void (QProcess::*)(int)>(&QProcess::finished),
this, &GdbEngine::continueSetupEngine);
} else if (m_coreName.endsWith(".gz")) {
m_tempCoreName = tempCoreFilename();
showMessage(msg.arg(m_tempCoreName));
m_tempCoreFile.setFileName(m_tempCoreName);
m_tempCoreFile.open(QFile::WriteOnly);
arguments << "-c" << "-d" << m_coreName;
m_coreUnpackProcess = new QProcess(this);
m_coreUnpackProcess->setWorkingDirectory(TemporaryDirectory::masterDirectoryPath());
m_coreUnpackProcess->start("gzip", arguments);
connect(m_coreUnpackProcess, &QProcess::readyRead, this, [this] {
m_tempCoreFile.write(m_coreUnpackProcess->readAll());
});
connect(m_coreUnpackProcess, static_cast<void (QProcess::*)(int)>(&QProcess::finished),
this, &GdbEngine::continueSetupEngine);
} else {
continueSetupEngine();
}
}
QString GdbEngine::coreFileName() const
{
return m_tempCoreName.isEmpty() ? m_coreName : m_tempCoreName;
}
void GdbEngine::doUpdateLocals(const UpdateParameters &params)
{
m_pendingBreakpointRequests = 0;
-17
View File
@@ -96,7 +96,6 @@ private: ////////// General Interface //////////
////////// Gdb Process Management //////////
void startGdb(const QStringList &args = QStringList());
void handleInferiorShutdown(const DebuggerResponse &response);
void handleGdbExit(const DebuggerResponse &response);
void setLinuxOsAbi();
@@ -120,13 +119,6 @@ private: ////////// General Interface //////////
// The engine is still running just fine, but it failed to acquire a debuggee.
void notifyInferiorSetupFailedHelper(const QString &msg);
void notifyAdapterShutdownOk();
void notifyAdapterShutdownFailed();
// Something went wrong with the adapter *after* adapterStarted() was emitted.
// Make sure to clean up everything before emitting this signal.
void handleAdapterCrashed(const QString &msg);
void handleGdbFinished(int exitCode, QProcess::ExitStatus exitStatus);
void handleGdbError(QProcess::ProcessError error);
void readGdbStandardOutput();
@@ -445,19 +437,10 @@ private: ////////// General Interface //////////
// Core
void handleTargetCore(const DebuggerResponse &response);
void handleCoreRoundTrip(const DebuggerResponse &response);
void unpackCoreIfNeeded();
QString coreFileName() const;
QString coreName() const;
void continueSetupEngine();
QString mainFunction() const;
QString m_executable;
QString m_coreName;
QString m_tempCoreName;
QProcess *m_coreUnpackProcess = nullptr;
QFile m_tempCoreFile;
Utils::QtcProcess m_gdbProc;
OutputCollector m_outputCollector;
QString m_errorString;
+4 -4
View File
@@ -48,9 +48,9 @@ enum { debug = 0 };
#define CHECK_STATE(s) do { checkState(s, __FILE__, __LINE__); } while (0)
DebuggerEngine *createQmlCppEngine(DebuggerEngine *cppEngine, bool useTerminal)
DebuggerEngine *createQmlCppEngine(DebuggerEngine *cppEngine)
{
return new QmlCppEngine(cppEngine, useTerminal);
return new QmlCppEngine(cppEngine);
}
@@ -60,10 +60,10 @@ DebuggerEngine *createQmlCppEngine(DebuggerEngine *cppEngine, bool useTerminal)
//
////////////////////////////////////////////////////////////////////////
QmlCppEngine::QmlCppEngine(DebuggerEngine *cppEngine, bool useTerminal)
QmlCppEngine::QmlCppEngine(DebuggerEngine *cppEngine)
{
setObjectName("QmlCppEngine");
m_qmlEngine = new QmlEngine(useTerminal);
m_qmlEngine = new QmlEngine;
m_qmlEngine->setMasterEngine(this);
m_cppEngine = cppEngine;
m_cppEngine->setMasterEngine(this);
+1 -1
View File
@@ -37,7 +37,7 @@ class QmlCppEngine : public DebuggerEngine
Q_OBJECT
public:
QmlCppEngine(DebuggerEngine *cppEngine, bool useTerminal);
explicit QmlCppEngine(DebuggerEngine *cppEngine);
~QmlCppEngine() override;
bool canDisplayTooltip() const override;
+9 -9
View File
@@ -246,7 +246,7 @@ static void updateDocument(IDocument *document, const QTextDocument *textDocumen
//
///////////////////////////////////////////////////////////////////////
QmlEngine::QmlEngine(bool useTerminal)
QmlEngine::QmlEngine()
: d(new QmlEnginePrivate(this, new QmlDebugConnection(this)))
{
setObjectName("QmlEngine");
@@ -266,12 +266,6 @@ QmlEngine::QmlEngine(bool useTerminal)
connect(&d->applicationLauncher, &ApplicationLauncher::processStarted,
this, &QmlEngine::handleLauncherStarted);
// we won't get any debug output
if (useTerminal) {
d->retryOnConnectFail = true;
d->automaticConnect = true;
}
debuggerConsole()->setScriptEvaluator([this](const QString &expr) {
executeDebuggerCommand(expr, QmlLanguage);
});
@@ -522,6 +516,12 @@ void QmlEngine::closeConnection()
void QmlEngine::runEngine()
{
// we won't get any debug output
if (!terminal()) {
d->retryOnConnectFail = true;
d->automaticConnect = true;
}
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
if (!isSlaveEngine()) {
@@ -2481,9 +2481,9 @@ void QmlEnginePrivate::flushSendBuffer()
sendBuffer.clear();
}
DebuggerEngine *createQmlEngine(bool useTerminal)
DebuggerEngine *createQmlEngine()
{
return new QmlEngine(useTerminal);
return new QmlEngine;
}
} // Internal

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