forked from qt-creator/qt-creator
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:
Vendored
+66
@@ -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)
|
||||
Vendored
+154
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,5 +1,5 @@
|
||||
|
||||
#line 215 "./glsl.g"
|
||||
#line 210 "./glsl.g"
|
||||
|
||||
/****************************************************************************
|
||||
**
|
||||
|
||||
+1248
-1231
File diff suppressed because it is too large
Load Diff
+216
-210
@@ -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,231 +38,234 @@
|
||||
//
|
||||
|
||||
// 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
|
||||
|
||||
class GLSLParserTable
|
||||
{
|
||||
public:
|
||||
enum VariousConstants {
|
||||
EOF_SYMBOL = 0,
|
||||
T_ADD_ASSIGN = 3,
|
||||
T_AMPERSAND = 4,
|
||||
T_AND_ASSIGN = 5,
|
||||
T_AND_OP = 6,
|
||||
T_ATTRIBUTE = 7,
|
||||
T_BANG = 8,
|
||||
T_BOOL = 9,
|
||||
T_BREAK = 10,
|
||||
T_BVEC2 = 11,
|
||||
T_BVEC3 = 12,
|
||||
T_BVEC4 = 13,
|
||||
T_CARET = 14,
|
||||
T_CASE = 15,
|
||||
T_CENTROID = 16,
|
||||
T_COLON = 17,
|
||||
T_COMMA = 18,
|
||||
T_COMMENT = 172,
|
||||
T_CONST = 19,
|
||||
T_CONTINUE = 20,
|
||||
T_DASH = 21,
|
||||
T_DEC_OP = 22,
|
||||
T_DEFAULT = 23,
|
||||
T_DISCARD = 24,
|
||||
T_DIV_ASSIGN = 25,
|
||||
T_DMAT2 = 26,
|
||||
T_DMAT2X2 = 27,
|
||||
T_DMAT2X3 = 28,
|
||||
T_DMAT2X4 = 29,
|
||||
T_DMAT3 = 30,
|
||||
T_DMAT3X2 = 31,
|
||||
T_DMAT3X3 = 32,
|
||||
T_DMAT3X4 = 33,
|
||||
T_DMAT4 = 34,
|
||||
T_DMAT4X2 = 35,
|
||||
T_DMAT4X3 = 36,
|
||||
T_DMAT4X4 = 37,
|
||||
T_DO = 38,
|
||||
T_DOT = 39,
|
||||
T_DOUBLE = 40,
|
||||
T_DVEC2 = 41,
|
||||
T_DVEC3 = 42,
|
||||
T_DVEC4 = 43,
|
||||
T_ELSE = 44,
|
||||
T_EQUAL = 45,
|
||||
T_EQ_OP = 46,
|
||||
T_ERROR = 173,
|
||||
T_FALSE = 170,
|
||||
T_FEED_EXPRESSION = 2,
|
||||
T_FEED_GLSL = 1,
|
||||
T_FLAT = 47,
|
||||
T_FLOAT = 48,
|
||||
T_FOR = 49,
|
||||
T_GE_OP = 50,
|
||||
T_HIGHP = 51,
|
||||
T_IDENTIFIER = 52,
|
||||
T_IF = 53,
|
||||
T_IN = 54,
|
||||
T_INC_OP = 55,
|
||||
T_INOUT = 56,
|
||||
T_INT = 57,
|
||||
T_INVARIANT = 58,
|
||||
T_ISAMPLER1D = 59,
|
||||
T_ISAMPLER1DARRAY = 60,
|
||||
T_ISAMPLER2D = 61,
|
||||
T_ISAMPLER2DARRAY = 62,
|
||||
T_ISAMPLER2DMS = 63,
|
||||
T_ISAMPLER2DMSARRAY = 64,
|
||||
T_ISAMPLER2DRECT = 65,
|
||||
T_ISAMPLER3D = 66,
|
||||
T_ISAMPLERBUFFER = 67,
|
||||
T_ISAMPLERCUBE = 68,
|
||||
T_ISAMPLERCUBEARRAY = 69,
|
||||
T_IVEC2 = 70,
|
||||
T_IVEC3 = 71,
|
||||
T_IVEC4 = 72,
|
||||
T_LAYOUT = 73,
|
||||
T_LEFT_ANGLE = 74,
|
||||
T_LEFT_ASSIGN = 75,
|
||||
T_LEFT_BRACE = 76,
|
||||
T_LEFT_BRACKET = 77,
|
||||
T_LEFT_OP = 78,
|
||||
T_LEFT_PAREN = 79,
|
||||
T_LE_OP = 80,
|
||||
T_LOWP = 81,
|
||||
T_MAT2 = 82,
|
||||
T_MAT2X2 = 83,
|
||||
T_MAT2X3 = 84,
|
||||
T_MAT2X4 = 85,
|
||||
T_MAT3 = 86,
|
||||
T_MAT3X2 = 87,
|
||||
T_MAT3X3 = 88,
|
||||
T_MAT3X4 = 89,
|
||||
T_MAT4 = 90,
|
||||
T_MAT4X2 = 91,
|
||||
T_MAT4X3 = 92,
|
||||
T_MAT4X4 = 93,
|
||||
T_MEDIUMP = 94,
|
||||
T_MOD_ASSIGN = 95,
|
||||
T_MUL_ASSIGN = 96,
|
||||
T_NE_OP = 97,
|
||||
T_NOPERSPECTIVE = 98,
|
||||
T_NUMBER = 99,
|
||||
T_OR_ASSIGN = 100,
|
||||
T_OR_OP = 101,
|
||||
T_OUT = 102,
|
||||
T_PATCH = 103,
|
||||
T_PERCENT = 104,
|
||||
T_PLUS = 105,
|
||||
T_PRECISION = 106,
|
||||
T_PREPROC = 171,
|
||||
T_QUESTION = 107,
|
||||
T_RESERVED = 174,
|
||||
T_RETURN = 108,
|
||||
T_RIGHT_ANGLE = 109,
|
||||
T_RIGHT_ASSIGN = 110,
|
||||
T_RIGHT_BRACE = 111,
|
||||
T_RIGHT_BRACKET = 112,
|
||||
T_RIGHT_OP = 113,
|
||||
T_RIGHT_PAREN = 114,
|
||||
T_SAMPLE = 115,
|
||||
T_SAMPLER1D = 116,
|
||||
T_SAMPLER1DARRAY = 117,
|
||||
T_SAMPLER1DARRAYSHADOW = 118,
|
||||
T_SAMPLER1DSHADOW = 119,
|
||||
T_SAMPLER2D = 120,
|
||||
T_SAMPLER2DARRAY = 121,
|
||||
T_SAMPLER2DARRAYSHADOW = 122,
|
||||
T_SAMPLER2DMS = 123,
|
||||
T_SAMPLER2DMSARRAY = 124,
|
||||
T_SAMPLER2DRECT = 125,
|
||||
T_SAMPLER2DRECTSHADOW = 126,
|
||||
T_SAMPLER2DSHADOW = 127,
|
||||
T_SAMPLER3D = 128,
|
||||
T_SAMPLERBUFFER = 129,
|
||||
T_SAMPLERCUBE = 130,
|
||||
T_SAMPLERCUBEARRAY = 131,
|
||||
T_SAMPLERCUBEARRAYSHADOW = 132,
|
||||
T_SAMPLERCUBESHADOW = 133,
|
||||
T_SEMICOLON = 134,
|
||||
T_SLASH = 135,
|
||||
T_SMOOTH = 136,
|
||||
T_STAR = 137,
|
||||
T_STRUCT = 138,
|
||||
T_SUBROUTINE = 139,
|
||||
T_SUB_ASSIGN = 140,
|
||||
T_SWITCH = 141,
|
||||
T_TILDE = 142,
|
||||
T_TRUE = 169,
|
||||
T_TYPE_NAME = 143,
|
||||
T_UINT = 144,
|
||||
T_UNIFORM = 145,
|
||||
T_USAMPLER1D = 146,
|
||||
T_USAMPLER1DARRAY = 147,
|
||||
T_USAMPLER2D = 148,
|
||||
T_USAMPLER2DARRAY = 149,
|
||||
T_USAMPLER2DMS = 150,
|
||||
T_USAMPLER2DMSARRAY = 151,
|
||||
T_USAMPLER2DRECT = 152,
|
||||
T_USAMPLER3D = 153,
|
||||
T_USAMPLERBUFFER = 154,
|
||||
T_USAMPLERCUBE = 155,
|
||||
T_USAMPLERCUBEARRAY = 156,
|
||||
T_UVEC2 = 157,
|
||||
T_UVEC3 = 158,
|
||||
T_UVEC4 = 159,
|
||||
T_VARYING = 160,
|
||||
T_VEC2 = 161,
|
||||
T_VEC3 = 162,
|
||||
T_VEC4 = 163,
|
||||
T_VERTICAL_BAR = 164,
|
||||
T_VOID = 165,
|
||||
T_WHILE = 166,
|
||||
T_XOR_ASSIGN = 167,
|
||||
T_XOR_OP = 168,
|
||||
enum VariousConstants {
|
||||
EOF_SYMBOL = 0,
|
||||
T_ADD_ASSIGN = 3,
|
||||
T_AMPERSAND = 4,
|
||||
T_AND_ASSIGN = 5,
|
||||
T_AND_OP = 6,
|
||||
T_ATTRIBUTE = 7,
|
||||
T_BANG = 8,
|
||||
T_BOOL = 9,
|
||||
T_BREAK = 10,
|
||||
T_BVEC2 = 11,
|
||||
T_BVEC3 = 12,
|
||||
T_BVEC4 = 13,
|
||||
T_CARET = 14,
|
||||
T_CASE = 15,
|
||||
T_CENTROID = 16,
|
||||
T_COLON = 17,
|
||||
T_COMMA = 18,
|
||||
T_COMMENT = 172,
|
||||
T_CONST = 19,
|
||||
T_CONTINUE = 20,
|
||||
T_DASH = 21,
|
||||
T_DEC_OP = 22,
|
||||
T_DEFAULT = 23,
|
||||
T_DISCARD = 24,
|
||||
T_DIV_ASSIGN = 25,
|
||||
T_DMAT2 = 26,
|
||||
T_DMAT2X2 = 27,
|
||||
T_DMAT2X3 = 28,
|
||||
T_DMAT2X4 = 29,
|
||||
T_DMAT3 = 30,
|
||||
T_DMAT3X2 = 31,
|
||||
T_DMAT3X3 = 32,
|
||||
T_DMAT3X4 = 33,
|
||||
T_DMAT4 = 34,
|
||||
T_DMAT4X2 = 35,
|
||||
T_DMAT4X3 = 36,
|
||||
T_DMAT4X4 = 37,
|
||||
T_DO = 38,
|
||||
T_DOT = 39,
|
||||
T_DOUBLE = 40,
|
||||
T_DVEC2 = 41,
|
||||
T_DVEC3 = 42,
|
||||
T_DVEC4 = 43,
|
||||
T_ELSE = 44,
|
||||
T_EQUAL = 45,
|
||||
T_EQ_OP = 46,
|
||||
T_ERROR = 173,
|
||||
T_FALSE = 170,
|
||||
T_FEED_EXPRESSION = 2,
|
||||
T_FEED_GLSL = 1,
|
||||
T_FLAT = 47,
|
||||
T_FLOAT = 48,
|
||||
T_FOR = 49,
|
||||
T_GE_OP = 50,
|
||||
T_HIGHP = 51,
|
||||
T_IDENTIFIER = 52,
|
||||
T_IF = 53,
|
||||
T_IN = 54,
|
||||
T_INC_OP = 55,
|
||||
T_INOUT = 56,
|
||||
T_INT = 57,
|
||||
T_INVARIANT = 58,
|
||||
T_ISAMPLER1D = 59,
|
||||
T_ISAMPLER1DARRAY = 60,
|
||||
T_ISAMPLER2D = 61,
|
||||
T_ISAMPLER2DARRAY = 62,
|
||||
T_ISAMPLER2DMS = 63,
|
||||
T_ISAMPLER2DMSARRAY = 64,
|
||||
T_ISAMPLER2DRECT = 65,
|
||||
T_ISAMPLER3D = 66,
|
||||
T_ISAMPLERBUFFER = 67,
|
||||
T_ISAMPLERCUBE = 68,
|
||||
T_ISAMPLERCUBEARRAY = 69,
|
||||
T_IVEC2 = 70,
|
||||
T_IVEC3 = 71,
|
||||
T_IVEC4 = 72,
|
||||
T_LAYOUT = 73,
|
||||
T_LEFT_ANGLE = 74,
|
||||
T_LEFT_ASSIGN = 75,
|
||||
T_LEFT_BRACE = 76,
|
||||
T_LEFT_BRACKET = 77,
|
||||
T_LEFT_OP = 78,
|
||||
T_LEFT_PAREN = 79,
|
||||
T_LE_OP = 80,
|
||||
T_LOWP = 81,
|
||||
T_MAT2 = 82,
|
||||
T_MAT2X2 = 83,
|
||||
T_MAT2X3 = 84,
|
||||
T_MAT2X4 = 85,
|
||||
T_MAT3 = 86,
|
||||
T_MAT3X2 = 87,
|
||||
T_MAT3X3 = 88,
|
||||
T_MAT3X4 = 89,
|
||||
T_MAT4 = 90,
|
||||
T_MAT4X2 = 91,
|
||||
T_MAT4X3 = 92,
|
||||
T_MAT4X4 = 93,
|
||||
T_MEDIUMP = 94,
|
||||
T_MOD_ASSIGN = 95,
|
||||
T_MUL_ASSIGN = 96,
|
||||
T_NE_OP = 97,
|
||||
T_NOPERSPECTIVE = 98,
|
||||
T_NUMBER = 99,
|
||||
T_OR_ASSIGN = 100,
|
||||
T_OR_OP = 101,
|
||||
T_OUT = 102,
|
||||
T_PATCH = 103,
|
||||
T_PERCENT = 104,
|
||||
T_PLUS = 105,
|
||||
T_PRECISION = 106,
|
||||
T_PREPROC = 171,
|
||||
T_QUESTION = 107,
|
||||
T_RESERVED = 174,
|
||||
T_RETURN = 108,
|
||||
T_RIGHT_ANGLE = 109,
|
||||
T_RIGHT_ASSIGN = 110,
|
||||
T_RIGHT_BRACE = 111,
|
||||
T_RIGHT_BRACKET = 112,
|
||||
T_RIGHT_OP = 113,
|
||||
T_RIGHT_PAREN = 114,
|
||||
T_SAMPLE = 115,
|
||||
T_SAMPLER1D = 116,
|
||||
T_SAMPLER1DARRAY = 117,
|
||||
T_SAMPLER1DARRAYSHADOW = 118,
|
||||
T_SAMPLER1DSHADOW = 119,
|
||||
T_SAMPLER2D = 120,
|
||||
T_SAMPLER2DARRAY = 121,
|
||||
T_SAMPLER2DARRAYSHADOW = 122,
|
||||
T_SAMPLER2DMS = 123,
|
||||
T_SAMPLER2DMSARRAY = 124,
|
||||
T_SAMPLER2DRECT = 125,
|
||||
T_SAMPLER2DRECTSHADOW = 126,
|
||||
T_SAMPLER2DSHADOW = 127,
|
||||
T_SAMPLER3D = 128,
|
||||
T_SAMPLERBUFFER = 129,
|
||||
T_SAMPLERCUBE = 130,
|
||||
T_SAMPLERCUBEARRAY = 131,
|
||||
T_SAMPLERCUBEARRAYSHADOW = 132,
|
||||
T_SAMPLERCUBESHADOW = 133,
|
||||
T_SEMICOLON = 134,
|
||||
T_SLASH = 135,
|
||||
T_SMOOTH = 136,
|
||||
T_STAR = 137,
|
||||
T_STRUCT = 138,
|
||||
T_SUBROUTINE = 139,
|
||||
T_SUB_ASSIGN = 140,
|
||||
T_SWITCH = 141,
|
||||
T_TILDE = 142,
|
||||
T_TRUE = 169,
|
||||
T_TYPE_NAME = 143,
|
||||
T_UINT = 144,
|
||||
T_UNIFORM = 145,
|
||||
T_USAMPLER1D = 146,
|
||||
T_USAMPLER1DARRAY = 147,
|
||||
T_USAMPLER2D = 148,
|
||||
T_USAMPLER2DARRAY = 149,
|
||||
T_USAMPLER2DMS = 150,
|
||||
T_USAMPLER2DMSARRAY = 151,
|
||||
T_USAMPLER2DRECT = 152,
|
||||
T_USAMPLER3D = 153,
|
||||
T_USAMPLERBUFFER = 154,
|
||||
T_USAMPLERCUBE = 155,
|
||||
T_USAMPLERCUBEARRAY = 156,
|
||||
T_UVEC2 = 157,
|
||||
T_UVEC3 = 158,
|
||||
T_UVEC4 = 159,
|
||||
T_VARYING = 160,
|
||||
T_VEC2 = 161,
|
||||
T_VEC3 = 162,
|
||||
T_VEC4 = 163,
|
||||
T_VERTICAL_BAR = 164,
|
||||
T_VOID = 165,
|
||||
T_WHILE = 166,
|
||||
T_XOR_ASSIGN = 167,
|
||||
T_XOR_OP = 168,
|
||||
|
||||
ACCEPT_STATE = 462,
|
||||
RULE_COUNT = 316,
|
||||
STATE_COUNT = 463,
|
||||
TERMINAL_COUNT = 175,
|
||||
NON_TERMINAL_COUNT = 85,
|
||||
ACCEPT_STATE = 462,
|
||||
RULE_COUNT = 316,
|
||||
STATE_COUNT = 463,
|
||||
TERMINAL_COUNT = 175,
|
||||
NON_TERMINAL_COUNT = 85,
|
||||
|
||||
GOTO_INDEX_OFFSET = 463,
|
||||
GOTO_INFO_OFFSET = 4681,
|
||||
GOTO_CHECK_OFFSET = 4681
|
||||
};
|
||||
GOTO_INDEX_OFFSET = 463,
|
||||
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)
|
||||
{
|
||||
const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt;
|
||||
if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt)
|
||||
return goto_default [nt];
|
||||
static inline int nt_action (int state, int nt)
|
||||
{
|
||||
const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt;
|
||||
if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt)
|
||||
return goto_default [nt];
|
||||
|
||||
return action_info [GOTO_INFO_OFFSET + yyn];
|
||||
}
|
||||
return action_info [GOTO_INFO_OFFSET + yyn];
|
||||
}
|
||||
|
||||
static inline int t_action (int state, int token)
|
||||
{
|
||||
const int yyn = action_index [state] + token;
|
||||
static inline int t_action (int state, int token)
|
||||
{
|
||||
const int yyn = action_index [state] + token;
|
||||
|
||||
if (yyn < 0 || action_check [yyn] != token)
|
||||
return - action_default [state];
|
||||
if (yyn < 0 || action_check [yyn] != token)
|
||||
return - action_default [state];
|
||||
|
||||
return action_info [yyn];
|
||||
}
|
||||
return action_info [yyn];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
QT_END_NAMESPACE
|
||||
#endif // GLSLPARSERTABLE_P_H
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
testResult->setFileName(m_file);
|
||||
testResult->setLine(m_lineNumber);
|
||||
|
||||
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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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 ¤tEditorFilePath,
|
||||
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
|
||||
+10
-103
@@ -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 ¤tEditorFilePath,
|
||||
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,12 +495,12 @@ 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(),
|
||||
Utf8String(),
|
||||
Utf8String::fromByteArray(info.unsavedContent),
|
||||
info.isDocumentModified,
|
||||
uint(m_interface->textDocument()->revision())}});
|
||||
BackendCommunicator &communicator = m_interface->communicator();
|
||||
communicator.updateTranslationUnitsForEditor({{m_interface->fileName(),
|
||||
Utf8String(),
|
||||
Utf8String::fromByteArray(info.unsavedContent),
|
||||
info.isDocumentModified,
|
||||
uint(m_interface->textDocument()->revision())}});
|
||||
}
|
||||
namespace {
|
||||
bool shouldSendDocumentForCompletion(const QString &filePath,
|
||||
@@ -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,9 +579,9 @@ 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),
|
||||
uint(cursorPosition.column), projectPartId,
|
||||
functionNameStart.line, functionNameStart.column);
|
||||
communicator.completeCode(this, filePath, uint(cursorPosition.line),
|
||||
uint(cursorPosition.column), projectPartId,
|
||||
functionNameStart.line, functionNameStart.column);
|
||||
setLastCompletionPosition(filePath, position);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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,11 +343,11 @@ ClangEditorDocumentProcessor::cursorInfo(const CppTools::CursorInfoParams ¶m
|
||||
const CppTools::SemanticInfo::LocalUseMap localUses
|
||||
= CppTools::BuiltinCursorInfo::findLocalUses(params.semanticInfo.doc, line, column);
|
||||
|
||||
return m_ipcCommunicator.requestReferences(simpleFileContainer(),
|
||||
static_cast<quint32>(line),
|
||||
static_cast<quint32>(column),
|
||||
textDocument(),
|
||||
localUses);
|
||||
return m_communicator.requestReferences(simpleFileContainer(),
|
||||
static_cast<quint32>(line),
|
||||
static_cast<quint32>(column),
|
||||
textDocument(),
|
||||
localUses);
|
||||
}
|
||||
|
||||
static QVector<Utf8String> prioritizeByBaseName(const QString &curPath,
|
||||
@@ -392,10 +392,10 @@ ClangEditorDocumentProcessor::requestFollowSymbol(int line, int column)
|
||||
dependentFiles = prioritizeByBaseName(filePath(), fileDeps);
|
||||
}
|
||||
|
||||
return m_ipcCommunicator.requestFollowSymbol(simpleFileContainer(),
|
||||
dependentFiles,
|
||||
static_cast<quint32>(line),
|
||||
static_cast<quint32>(column));
|
||||
return m_communicator.requestFollowSymbol(simpleFileContainer(),
|
||||
dependentFiles,
|
||||
static_cast<quint32>(line),
|
||||
static_cast<quint32>(column));
|
||||
}
|
||||
|
||||
ClangBackEnd::FileContainer ClangEditorDocumentProcessor::fileContainerWithArguments() const
|
||||
@@ -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 ¶meters) 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())
|
||||
@@ -183,8 +157,8 @@ void BuildDirManager::maybeForceReparseOnceReaderReady()
|
||||
if (ccit->key == kcit->key) {
|
||||
if (ccit->value != kcit->value) {
|
||||
if (criticalKeys.contains(kcit->key)) {
|
||||
clearCache();
|
||||
return;
|
||||
clearCache();
|
||||
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 ¶meters,
|
||||
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 ¶meters,
|
||||
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,
|
||||
QString *errorMessage);
|
||||
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 ¶meters) 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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
qCDebug(log) << "adding (" << (isLink ? "link" : "full") << ") watch for"
|
||||
<< state.watchedFilePath;
|
||||
QFileSystemWatcher *watcher = 0;
|
||||
if (isLink)
|
||||
watcher = d->linkWatcher();
|
||||
else
|
||||
watcher = d->fileWatcher();
|
||||
watcher->addPath(state.watchedFilePath);
|
||||
}
|
||||
// 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"
|
||||
<< watchedFilePath;
|
||||
QFileSystemWatcher *watcher = nullptr;
|
||||
if (isLink)
|
||||
watcher = d->linkWatcher();
|
||||
else
|
||||
watcher = d->fileWatcher();
|
||||
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()) {
|
||||
|
||||
@@ -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;
|
||||
filterEntry.highlightInfo =
|
||||
highlightInfo(match, LocatorFilterEntry::HighlightInfo::ExtraInfo);
|
||||
} else {
|
||||
filterEntry.highlightInfo = highlightInfo(match);
|
||||
}
|
||||
const CamelHumpMatcher::HighlightingPositions positions =
|
||||
CamelHumpMatcher::highlightingPositions(match);
|
||||
filterEntry.highlightInfo =
|
||||
LocatorFilterEntry::HighlightInfo(positions.starts, positions.lengths, hDataType);
|
||||
|
||||
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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -128,7 +128,6 @@ public:
|
||||
// Macro-expanded and passed to debugger startup.
|
||||
QString additionalStartupCommands;
|
||||
|
||||
DebuggerEngineType masterEngineType = NoEngineType;
|
||||
DebuggerEngineType cppEngineType = NoEngineType;
|
||||
|
||||
bool isCppDebugging = true;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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,47 +529,41 @@ 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:
|
||||
if (!HostOsInfo::isWindowsHost()) {
|
||||
reportFailure(tr("Unsupported CDB host system."));
|
||||
return;
|
||||
}
|
||||
cppEngine = createCdbEngine();
|
||||
break;
|
||||
case LldbEngineType:
|
||||
cppEngine = createLldbEngine();
|
||||
break;
|
||||
case PdbEngineType: // FIXME: Yes, Python counts as C++...
|
||||
cppEngine = createPdbEngine();
|
||||
break;
|
||||
default:
|
||||
// Can happen for pure Qml.
|
||||
break;
|
||||
}
|
||||
|
||||
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'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LldbEngineType:
|
||||
cppEngine = createLldbEngine();
|
||||
break;
|
||||
case PdbEngineType: // FIXME: Yes, Python counts as C++...
|
||||
cppEngine = createPdbEngine();
|
||||
break;
|
||||
default:
|
||||
QTC_CHECK(false);
|
||||
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,32 +713,25 @@ 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;
|
||||
}
|
||||
if (rp.isQmlDebugging) {
|
||||
QmlDebug::QmlDebugServicesPreset service;
|
||||
if (rp.isCppDebugging) {
|
||||
if (rp.nativeMixedEnabled) {
|
||||
service = QmlDebug::QmlNativeDebuggerServices;
|
||||
} else {
|
||||
rp.masterEngineType = QmlEngineType;
|
||||
service = QmlDebug::QmlDebuggerServices;
|
||||
}
|
||||
if (rp.startMode != AttachExternal && rp.startMode != AttachCrashedExternal) {
|
||||
QString qmlarg = rp.isCppDebugging && rp.nativeMixedEnabled
|
||||
? QmlDebug::qmlDebugNativeArguments(service, false)
|
||||
: QmlDebug::qmlDebugTcpArguments(service, Port(rp.qmlServer.port()));
|
||||
QtcProcess::addArg(&rp.inferior.commandLineArguments, qmlarg);
|
||||
}
|
||||
} else {
|
||||
service = QmlDebug::QmlDebuggerServices;
|
||||
}
|
||||
if (rp.startMode != AttachExternal && rp.startMode != AttachCrashedExternal) {
|
||||
QString qmlarg = rp.isCppDebugging && rp.nativeMixedEnabled
|
||||
? QmlDebug::qmlDebugNativeArguments(service, false)
|
||||
: QmlDebug::qmlDebugTcpArguments(service, Port(rp.qmlServer.port()));
|
||||
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
|
||||
@@ -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 ¶ms)
|
||||
{
|
||||
m_pendingBreakpointRequests = 0;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user