forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/3.5'
This commit is contained in:
87
dist/changes-3.5.0.md
vendored
87
dist/changes-3.5.0.md
vendored
@@ -30,12 +30,13 @@ General
|
||||
interpreted in the order given on the command line.
|
||||
* Fixed issues with raising the Qt Creator window on Gnome desktop
|
||||
(QTCREATORBUG-13845)
|
||||
* Fixed appearance on high DPI displays on Windows and Linux
|
||||
* Fixed appearance on high DPI displays on Windows
|
||||
(QTCREATORBUG-11179)
|
||||
* Added locator filter for running external tools
|
||||
|
||||
Editing
|
||||
|
||||
* Added highlighting of search results to editor scroll bar
|
||||
* Added option to jump directly to specific column in addition to
|
||||
line number when opening files through locator or command line
|
||||
* Added *Remove missing files* action to QRC editor
|
||||
@@ -43,22 +44,19 @@ Editing
|
||||
* Made global file search use multiple threads (QTCREATORBUG-10298)
|
||||
* Fixed highlighting of current line in read-only text editors
|
||||
(QTCREATORBUG-10104)
|
||||
|
||||
Help
|
||||
* Fixed issues with completion while inserting snippet (QTCREATORBUG-14633)
|
||||
|
||||
Project Management
|
||||
|
||||
* Fixed issues with restoring project tree state (QTCREATORBUG-14304)
|
||||
|
||||
QMake Projects
|
||||
|
||||
CMake Projects
|
||||
|
||||
* Made it possible to register multiple CMake executables
|
||||
* Added support for file targets when explicitly specified in the
|
||||
generated CodeBlocks file
|
||||
* Fixed default shadow build directory name
|
||||
|
||||
Qbs Projects
|
||||
|
||||
Generic Projects
|
||||
|
||||
* Fixed that resource links were removed from UI files
|
||||
@@ -66,9 +64,16 @@ Generic Projects
|
||||
|
||||
QML-Only Projects (.qmlproject)
|
||||
|
||||
* Re-enabled the plugin by default
|
||||
|
||||
Debugging
|
||||
|
||||
Analyzer
|
||||
* Added dumper for `QJsonValue`, `QJsonObject`, `QJsonArray`, `QUuid`
|
||||
* Added basic support for GDB's fork-follows-child
|
||||
* Improved support for GDB 7.9 and LLDB 3.7
|
||||
* Fixed display of `QHash` keys with value 0 (QTCREATORBUG-14451)
|
||||
* Fixed variable expansion state in QML debugger
|
||||
* Fixed display of members of returned values
|
||||
|
||||
QML Profiler
|
||||
|
||||
@@ -80,6 +85,7 @@ C++ Support
|
||||
|
||||
* Added separate icon for structs
|
||||
* Added support for setting the access specifier of an extracted function (QTCREATORBUG-12127)
|
||||
* Moved Clang code model backend out-of-process
|
||||
* Fixed *Convert to Stack Variable* refactoring action for empty
|
||||
initializer lists (QTCREATORBUG-14279)
|
||||
* Fixed misplaced newlines of refactoring actions (QTCREATORBUG-13872)
|
||||
@@ -96,10 +102,14 @@ C++ Support
|
||||
* GCC implementation of `std::map`, `std::unique_ptr` (and other pointer wrappers)
|
||||
and `std::vector` are known to work
|
||||
* MSVC implementation is not supported
|
||||
* Fixed that highlighting vanished after text zoom (QTCREATORBUG-14579)
|
||||
* Fixed issues with completion while renaming local variable (QTCREATORBUG-14633)
|
||||
|
||||
QML Support
|
||||
|
||||
* Removed Qt Quick 1 wizards
|
||||
* Fixed missing auto-completion for `QtQuick` and `QtQuick.Controls`
|
||||
(QTCREATORBUG-14563)
|
||||
|
||||
Qt Quick Designer
|
||||
|
||||
@@ -113,6 +123,7 @@ Version Control Systems
|
||||
FakeVim
|
||||
|
||||
* Added support for `C-r{register}`
|
||||
* Added support for remapping shortcuts
|
||||
|
||||
Todo
|
||||
|
||||
@@ -126,12 +137,17 @@ Platform Specific
|
||||
|
||||
Windows
|
||||
|
||||
* Fixed that Qt Creator could freeze while user application is running
|
||||
(QTCREATORBUG-14676)
|
||||
|
||||
OS X
|
||||
|
||||
* Added locator filter that uses Spotlight for locating files
|
||||
|
||||
Linux
|
||||
|
||||
* Fixed performance issue with journal support (QTCREATORBUG-14356)
|
||||
|
||||
Android
|
||||
|
||||
* Made it possible to create AVD without SD card (QTCREATORBUG-13590)
|
||||
@@ -142,6 +158,8 @@ Android
|
||||
(QTCREATORBUG-13615)
|
||||
* Added input field for activity name in Android manifest editor
|
||||
(QTCREATORBUG-13958)
|
||||
* Fixed issues with Android M (QTCREATORBUG-14537, QTCREATORBUG-14534)
|
||||
* Fixed issues with 64 bit
|
||||
* Fixed handling of external file changes in Android manifest editor
|
||||
* Fixed listing of Google AVDs (QTCREATORBUG-13980)
|
||||
* Fixed that kits were removed from projects when changing NDK path
|
||||
@@ -162,4 +180,57 @@ Remote Linux
|
||||
|
||||
BareMetal
|
||||
|
||||
* Fixed processing of additional OpenOCD arguments
|
||||
|
||||
Credits for these changes go to:
|
||||
Alessandro Portale
|
||||
André Pönitz
|
||||
Alexander Drozdov
|
||||
Alexander Izmailov
|
||||
Arnold Dumas
|
||||
Benjamin Zeller
|
||||
BogDan Vatra
|
||||
Christian Kandeler
|
||||
Christian Stenger
|
||||
Cristian Adam
|
||||
Daniel Teske
|
||||
David Schulz
|
||||
Denis Kormalev
|
||||
Eike Ziller
|
||||
Erik Verbruggen
|
||||
Finn Brudal
|
||||
Friedemann Kleint
|
||||
Hugues Delorme
|
||||
Jack Andersen
|
||||
Jarek Kobus
|
||||
Jochen Becher
|
||||
Jörg Bornemann
|
||||
Johannes Lorenz
|
||||
Kai Köhne
|
||||
Knut Petter Svendsen
|
||||
Kudryavtsev Alexander
|
||||
Leena Miettinen
|
||||
Libor Tomsik
|
||||
Lorenz Haas
|
||||
Lukas Holecek
|
||||
Marcel Krems
|
||||
Marco Benelli
|
||||
Marco Bubke
|
||||
Montel Laurent
|
||||
Nikita Baryshnikov
|
||||
Nikita Kniazev
|
||||
Nikolai Kosjar
|
||||
Olivier Goffart
|
||||
Orgad Shaneh
|
||||
Ray Donnelly
|
||||
Robert Löhning
|
||||
Stanislav Ionascu
|
||||
Sune Vuorela
|
||||
Takumi ASAKI
|
||||
Tasuku Suzuki
|
||||
Thiago Macieira
|
||||
Thomas Hartmann
|
||||
Thorben Kroeger
|
||||
Tim Jenssen
|
||||
Tobias Hunger
|
||||
Ulf Hermann
|
||||
|
@@ -208,6 +208,27 @@
|
||||
diff view, you can use context menu commands to apply, revert, stage, and
|
||||
unstage hunks, as well as send them to a code pasting service.
|
||||
|
||||
\section3 Using GNU Diffutils with ClearCase
|
||||
|
||||
You can use the GNU Diffutils tool With ClearCase to compare files and
|
||||
activities:
|
||||
|
||||
\list 1
|
||||
|
||||
\li Download \l{http://gnuwin32.sourceforge.net/packages/diffutils.htm}
|
||||
{Diffutils} and extract it to a directory in your PATH.
|
||||
|
||||
\li Select \uicontrol Tools > \uicontrol Options >
|
||||
\uicontrol {Version Control} > \uicontrol ClearCase.
|
||||
|
||||
\li Select the \uicontrol External radio button. The radio button is
|
||||
disabled if \c diff is not found in the PATH.
|
||||
|
||||
\li In the \uicontrol Arguments field, specify arguments for running
|
||||
\c diff.
|
||||
|
||||
\endlist
|
||||
|
||||
\section2 Viewing Versioning History and Change Details
|
||||
|
||||
Display the versioning history of a file by selecting \uicontrol{Log}
|
||||
|
@@ -395,8 +395,8 @@
|
||||
it. Triggering this keyboard shortcut will directly open the wizard without
|
||||
the need to navigate to \uicontrol File > \uicontrol {New File or Project}.
|
||||
|
||||
Keyboard shortcuts for wizards can be set in \uicontol Tools >
|
||||
\uicontol Options > \uicontrol Environment > \uicontrol Keyboard >
|
||||
Keyboard shortcuts for wizards can be set in \uicontrol Tools >
|
||||
\uicontrol Options > \uicontrol Environment > \uicontrol Keyboard >
|
||||
\uicontrol Wizard. All wizard actions start with \uicontrol Impl there.
|
||||
|
||||
\section1 Related Topics
|
||||
|
@@ -460,7 +460,7 @@ class DumperBase:
|
||||
return s.decode("hex")
|
||||
return bytes.fromhex(s).decode("utf8")
|
||||
|
||||
# Hex decoding operating on str or bytes, return str.
|
||||
# Hex encoding operating on str or bytes, return str.
|
||||
def hexencode(self, s):
|
||||
if sys.version_info[0] == 2:
|
||||
return s.encode("hex")
|
||||
|
@@ -1759,6 +1759,7 @@ class Tester(Dumper):
|
||||
|
||||
self.expandedINames = set(expandedINames)
|
||||
self.passExceptions = True
|
||||
self.sortStructMembers = True
|
||||
|
||||
self.loadDumpers({})
|
||||
error = lldb.SBError()
|
||||
|
@@ -621,10 +621,6 @@ def qdump__QHash(d, value):
|
||||
with SubItem(d, i):
|
||||
if isCompact:
|
||||
key = it["key"]
|
||||
if not key:
|
||||
# LLDB can't access directly since it's in anonymous union
|
||||
# for Qt4 optimized int keytype
|
||||
key = it[1]["key"]
|
||||
d.putMapName(key, j)
|
||||
d.putItem(it["value"])
|
||||
d.putType(valueType)
|
||||
@@ -638,10 +634,6 @@ def qform__QHashNode():
|
||||
|
||||
def qdump__QHashNode(d, value):
|
||||
key = value["key"]
|
||||
if not key:
|
||||
# LLDB can't access directly since it's in anonymous union
|
||||
# for Qt4 optimized int keytype
|
||||
key = value[1]["key"]
|
||||
val = value["value"]
|
||||
if d.isMapCompact(key.type, val.type):
|
||||
d.putMapName(key)
|
||||
|
@@ -5,7 +5,7 @@ PreferredStyles=Fusion
|
||||
[Palette]
|
||||
shadowBackground=ff232323
|
||||
text=ffe7e7e7
|
||||
textDisabled=ffa0a0a4
|
||||
textDisabled=ffa0a0a0
|
||||
hoverBackground=ff515151
|
||||
selectedBackground=ff151515
|
||||
normalBackground=ff333333
|
||||
@@ -17,6 +17,7 @@ BackgroundColorAlternate=alternateBackground
|
||||
BackgroundColorDark=shadowBackground
|
||||
BackgroundColorHover=hoverBackground
|
||||
BackgroundColorNormal=normalBackground
|
||||
BackgroundColorDisabled=ff444444
|
||||
BackgroundColorSelected=ff909090
|
||||
BadgeLabelBackgroundColorChecked=normalBackground
|
||||
BadgeLabelBackgroundColorUnchecked=selectedBackground
|
||||
|
@@ -12,6 +12,7 @@ BackgroundColorDark=ff232323
|
||||
BackgroundColorHover=ff515151
|
||||
BackgroundColorNormal=ffffffff
|
||||
BackgroundColorSelected=ff151515
|
||||
BackgroundColorDisabled=ffefebe7
|
||||
BadgeLabelBackgroundColorChecked=ffe0e0e0
|
||||
BadgeLabelBackgroundColorUnchecked=ff808080
|
||||
BadgeLabelTextColorChecked=ff606060
|
||||
|
13
src/libs/3rdparty/cplusplus/Parser.cpp
vendored
13
src/libs/3rdparty/cplusplus/Parser.cpp
vendored
@@ -40,9 +40,8 @@
|
||||
#endif
|
||||
|
||||
#define CPLUSPLUS_NO_DEBUG_RULE
|
||||
#define MAX_EXPRESSION_DEPTH 100
|
||||
#define MAX_EXPRESSION_DEPTH 1000
|
||||
#define MAX_STATEMENT_DEPTH 100
|
||||
#define MAX_INITIALIZER_CLAUSE_DEPTH 2000
|
||||
|
||||
using namespace CPlusPlus;
|
||||
|
||||
@@ -2801,7 +2800,7 @@ bool Parser::parseInitializerList0x(ExpressionListAST *&node)
|
||||
for (++_initializerClauseDepth.top();
|
||||
LA() == T_COMMA
|
||||
&& LA(2) != T_RBRACE
|
||||
&& _initializerClauseDepth.top() <= MAX_INITIALIZER_CLAUSE_DEPTH;
|
||||
&& _initializerClauseDepth.top() <= MAX_EXPRESSION_DEPTH;
|
||||
++_initializerClauseDepth.top()) {
|
||||
consumeToken(); // consume T_COMMA
|
||||
|
||||
@@ -2817,7 +2816,7 @@ bool Parser::parseInitializerList0x(ExpressionListAST *&node)
|
||||
}
|
||||
}
|
||||
|
||||
const bool result = _initializerClauseDepth.top() <= MAX_INITIALIZER_CLAUSE_DEPTH;
|
||||
const bool result = _initializerClauseDepth.top() <= MAX_EXPRESSION_DEPTH;
|
||||
_initializerClauseDepth.pop();
|
||||
if (!result)
|
||||
warning(cursor(), "Reached parse limit for initializer clause");
|
||||
@@ -5594,7 +5593,13 @@ void Parser::parseExpressionWithOperatorPrecedence(ExpressionAST *&lhs, int minP
|
||||
{
|
||||
DEBUG_THIS_RULE();
|
||||
|
||||
unsigned iterations = 0;
|
||||
while (precedence(tok().kind(), _templateArguments) >= minPrecedence) {
|
||||
if (++iterations > MAX_EXPRESSION_DEPTH) {
|
||||
warning(cursor(), "Reached parse limit for expression");
|
||||
return;
|
||||
}
|
||||
|
||||
const int operPrecedence = precedence(tok().kind(), _templateArguments);
|
||||
const int oper = consumeToken();
|
||||
|
||||
|
@@ -295,6 +295,11 @@ bool QmlDebugConnection::isOpen() const
|
||||
return d->gotHello;
|
||||
}
|
||||
|
||||
bool QmlDebugConnection::isConnecting() const
|
||||
{
|
||||
return !isOpen() && d->device;
|
||||
}
|
||||
|
||||
void QmlDebugConnection::close()
|
||||
{
|
||||
if (d->device && d->device->isOpen())
|
||||
|
@@ -57,6 +57,7 @@ public:
|
||||
void connectToHost(const QString &hostName, quint16 port);
|
||||
|
||||
bool isOpen() const;
|
||||
bool isConnecting() const;
|
||||
void close();
|
||||
|
||||
signals:
|
||||
|
@@ -366,6 +366,10 @@ QPalette Theme::palette() const
|
||||
pal.setColor(QPalette::ToolTipText, color(Theme::TextColorNormal));
|
||||
pal.setColor(QPalette::Link, color(Theme::TextColorLink));
|
||||
pal.setColor(QPalette::LinkVisited, color(Theme::TextColorLinkVisited));
|
||||
pal.setColor(QPalette::Disabled, QPalette::Window, color(Theme::BackgroundColorDisabled));
|
||||
pal.setBrush(QPalette::Disabled, QPalette::WindowText, color(Theme::TextColorDisabled));
|
||||
pal.setColor(QPalette::Disabled, QPalette::Base, color(Theme::BackgroundColorDisabled));
|
||||
pal.setBrush(QPalette::Disabled, QPalette::Text, color(Theme::TextColorDisabled));
|
||||
return pal;
|
||||
}
|
||||
|
||||
|
@@ -63,6 +63,7 @@ public:
|
||||
BackgroundColorHover,
|
||||
BackgroundColorNormal,
|
||||
BackgroundColorSelected,
|
||||
BackgroundColorDisabled,
|
||||
BadgeLabelBackgroundColorChecked,
|
||||
BadgeLabelBackgroundColorUnchecked,
|
||||
BadgeLabelTextColorChecked,
|
||||
|
@@ -284,7 +284,7 @@ void AutotoolsProject::buildFileNodeTree(const QDir &directory,
|
||||
FolderNode *parentFolder = 0;
|
||||
FolderNode *oldParentFolder = 0;
|
||||
|
||||
foreach (const QString& file, files) {
|
||||
foreach (const QString &file, files) {
|
||||
if (file.endsWith(QLatin1String(".moc")))
|
||||
continue;
|
||||
|
||||
@@ -306,8 +306,8 @@ void AutotoolsProject::buildFileNodeTree(const QDir &directory,
|
||||
parentFolder = m_rootNode;
|
||||
}
|
||||
}
|
||||
QTC_ASSERT(parentFolder != 0, return);
|
||||
if ((oldParentFolder != parentFolder) && !fileNodes.isEmpty()) {
|
||||
QTC_ASSERT(parentFolder, return);
|
||||
if (oldParentFolder && (oldParentFolder != parentFolder) && !fileNodes.isEmpty()) {
|
||||
// AutotoolsProjectNode::addFileNodes() is a very expensive operation. It is
|
||||
// important to collect as much file nodes of the same parent folder as
|
||||
// possible before invoking it.
|
||||
@@ -328,7 +328,7 @@ void AutotoolsProject::buildFileNodeTree(const QDir &directory,
|
||||
}
|
||||
}
|
||||
|
||||
if (!fileNodes.isEmpty())
|
||||
if (parentFolder && !fileNodes.isEmpty())
|
||||
parentFolder->addFileNodes(fileNodes);
|
||||
|
||||
// Remove unused file nodes and empty folder nodes
|
||||
|
208
src/plugins/clangcodemodel/activationsequenceprocessor.cpp
Normal file
208
src/plugins/clangcodemodel/activationsequenceprocessor.cpp
Normal file
@@ -0,0 +1,208 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "activationsequenceprocessor.h"
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
namespace {
|
||||
|
||||
QString truncateActivationStringByPosition(const QString &activationString,
|
||||
int positionInDocument)
|
||||
{
|
||||
if (positionInDocument == 1)
|
||||
return activationString.left(1);
|
||||
|
||||
if (positionInDocument == 2)
|
||||
return activationString.left(2);
|
||||
|
||||
return activationString;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ActivationSequenceProcessor::ActivationSequenceProcessor(const QString &activationString,
|
||||
int positionInDocument,
|
||||
bool wantFunctionCall)
|
||||
: m_positionInDocument(positionInDocument),
|
||||
m_wantFunctionCall(wantFunctionCall)
|
||||
{
|
||||
extractCharactersBeforePosition(truncateActivationStringByPosition(activationString,
|
||||
positionInDocument));
|
||||
|
||||
process();
|
||||
}
|
||||
|
||||
CPlusPlus::Kind ActivationSequenceProcessor::completionKind() const
|
||||
{
|
||||
return m_completionKind;
|
||||
}
|
||||
|
||||
int ActivationSequenceProcessor::offset() const
|
||||
{
|
||||
return m_offset;
|
||||
}
|
||||
|
||||
int ActivationSequenceProcessor::position() const
|
||||
{
|
||||
return m_positionInDocument - m_offset;
|
||||
}
|
||||
|
||||
void ActivationSequenceProcessor::extractCharactersBeforePosition(const QString &activationString)
|
||||
{
|
||||
if (activationString.size() >= 3) {
|
||||
m_char1 = activationString[0];
|
||||
m_char2 = activationString[1];
|
||||
m_char3 = activationString[2];
|
||||
} else if (activationString.size() == 2) {
|
||||
m_char2 = activationString[0];
|
||||
m_char3 = activationString[1];
|
||||
} else if (activationString.size() == 1) {
|
||||
m_char3 = activationString[0];
|
||||
}
|
||||
}
|
||||
|
||||
void ActivationSequenceProcessor::process()
|
||||
{
|
||||
processDot();
|
||||
processComma();
|
||||
processLeftParen();
|
||||
processColonColon();
|
||||
processArrow();
|
||||
processDotStar();
|
||||
processArrowStar();
|
||||
processDoxyGenComment();
|
||||
processAngleStringLiteral();
|
||||
processStringLiteral();
|
||||
processSlash();
|
||||
processPound();
|
||||
}
|
||||
|
||||
void ActivationSequenceProcessor::processDot()
|
||||
{
|
||||
if (m_char3 == QLatin1Char('.') && m_char2 != QLatin1Char('.')) {
|
||||
m_completionKind = CPlusPlus::T_DOT;
|
||||
m_offset = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void ActivationSequenceProcessor::processComma()
|
||||
{
|
||||
if (m_char3 == QLatin1Char(',') ) {
|
||||
m_completionKind = CPlusPlus::T_COMMA;
|
||||
m_offset = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void ActivationSequenceProcessor::processLeftParen()
|
||||
{
|
||||
if (m_char3 == QLatin1Char('(') && m_wantFunctionCall) {
|
||||
m_completionKind = CPlusPlus::T_LPAREN;
|
||||
m_offset = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void ActivationSequenceProcessor::processColonColon()
|
||||
{
|
||||
if (m_char2 == QLatin1Char(':') && m_char3 == QLatin1Char(':')) {
|
||||
m_completionKind = CPlusPlus::T_COLON_COLON;
|
||||
m_offset = 2;
|
||||
}
|
||||
}
|
||||
|
||||
void ActivationSequenceProcessor::processArrow()
|
||||
{
|
||||
if (m_char2 == QLatin1Char('-') && m_char3 == QLatin1Char('>')) {
|
||||
m_completionKind = CPlusPlus::T_ARROW;
|
||||
m_offset = 2;
|
||||
}
|
||||
}
|
||||
|
||||
void ActivationSequenceProcessor::processDotStar()
|
||||
{
|
||||
if (m_char2 == QLatin1Char('.') && m_char3 == QLatin1Char('*')) {
|
||||
m_completionKind = CPlusPlus::T_DOT_STAR;
|
||||
m_offset = 2;
|
||||
}
|
||||
}
|
||||
|
||||
void ActivationSequenceProcessor::processArrowStar()
|
||||
{
|
||||
if (m_char1 == QLatin1Char('-') && m_char2 == QLatin1Char('>') && m_char3 == QLatin1Char('*')) {
|
||||
m_completionKind = CPlusPlus::T_ARROW_STAR;
|
||||
m_offset = 3;
|
||||
}
|
||||
}
|
||||
|
||||
void ActivationSequenceProcessor::processDoxyGenComment()
|
||||
{
|
||||
if ((m_char2 == QLatin1Char('\\') || m_char2 == QLatin1Char('@'))
|
||||
&& (m_char3.isNull() || m_char3.isSpace())) {
|
||||
m_completionKind = CPlusPlus::T_DOXY_COMMENT;
|
||||
m_offset = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void ActivationSequenceProcessor::processAngleStringLiteral()
|
||||
{
|
||||
if (m_char3 == QLatin1Char('<')) {
|
||||
m_completionKind = CPlusPlus::T_ANGLE_STRING_LITERAL;
|
||||
m_offset = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void ActivationSequenceProcessor::processStringLiteral()
|
||||
{
|
||||
if (m_char3 == QLatin1Char('"')) {
|
||||
m_completionKind = CPlusPlus::T_STRING_LITERAL;
|
||||
m_offset = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void ActivationSequenceProcessor::processSlash()
|
||||
{
|
||||
if (m_char3 == QLatin1Char('/')) {
|
||||
m_completionKind = CPlusPlus::T_SLASH;
|
||||
m_offset = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void ActivationSequenceProcessor::processPound()
|
||||
{
|
||||
if (m_char3 == QLatin1Char('#')) {
|
||||
m_completionKind = CPlusPlus::T_POUND;
|
||||
m_offset = 1;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
|
81
src/plugins/clangcodemodel/activationsequenceprocessor.h
Normal file
81
src/plugins/clangcodemodel/activationsequenceprocessor.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CLANGCODEMODEL_INTERNAL_ACTIVATIONSEQUENCEPROCESSOR_H
|
||||
#define CLANGCODEMODEL_INTERNAL_ACTIVATIONSEQUENCEPROCESSOR_H
|
||||
|
||||
#include <cplusplus/Token.h>
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
class ActivationSequenceProcessor
|
||||
{
|
||||
public:
|
||||
ActivationSequenceProcessor(const QString &activationString,
|
||||
int positionInDocument,
|
||||
bool wantFunctionCall);
|
||||
|
||||
CPlusPlus::Kind completionKind() const;
|
||||
int offset() const;
|
||||
int position() const;
|
||||
|
||||
private:
|
||||
void extractCharactersBeforePosition(const QString &activationString);
|
||||
void process();
|
||||
void processDot();
|
||||
void processComma();
|
||||
void processLeftParen();
|
||||
void processColonColon();
|
||||
void processArrow();
|
||||
void processDotStar();
|
||||
void processArrowStar();
|
||||
void processDoxyGenComment();
|
||||
void processAngleStringLiteral();
|
||||
void processStringLiteral();
|
||||
void processSlash();
|
||||
void processPound();
|
||||
|
||||
private:
|
||||
CPlusPlus::Kind m_completionKind = CPlusPlus::T_EOF_SYMBOL;
|
||||
int m_offset = 0;
|
||||
int m_positionInDocument;
|
||||
QChar m_char1;
|
||||
QChar m_char2;
|
||||
QChar m_char3;
|
||||
bool m_wantFunctionCall;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
|
||||
#endif // CLANGCODEMODEL_INTERNAL_ACTIVATIONSEQUENCEPROCESSOR_H
|
@@ -28,34 +28,30 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
// Expected:
|
||||
// (clamp, ),
|
||||
// (perform, perform<$class T$>)
|
||||
// (perform3, perform3<$class T$, $int E$, $class D$>)
|
||||
#include "clangassistproposal.h"
|
||||
|
||||
// note: clang understands if parameter is redundant
|
||||
#include <texteditor/texteditor.h>
|
||||
|
||||
template<class T>
|
||||
T clamp(T value, T a = 0.0, T b = 1.0)
|
||||
{
|
||||
if (value < a)
|
||||
return a;
|
||||
if (value > b)
|
||||
return b;
|
||||
return value;
|
||||
}
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
template<class T>
|
||||
void perform()
|
||||
ClangAssistProposal::ClangAssistProposal(int cursorPos, TextEditor::GenericProposalModel *model)
|
||||
: GenericProposal(cursorPos, model)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T, int E, class D>
|
||||
void perform3()
|
||||
bool ClangAssistProposal::isCorrective() const
|
||||
{
|
||||
return ClangAssistProposalModel::replaceDotForArrow(model());
|
||||
}
|
||||
|
||||
void check()
|
||||
void ClangAssistProposal::makeCorrection(TextEditor::TextEditorWidget *editorWidget)
|
||||
{
|
||||
<<<<
|
||||
editorWidget->setCursorPosition(basePosition() - 1);
|
||||
editorWidget->replace(1, QLatin1String("->"));
|
||||
moveBasePosition(1);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
|
@@ -28,35 +28,29 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Expected: 'doB'
|
||||
* Not expected: 'doA'
|
||||
*/
|
||||
#ifndef CLANGCODEMODEL_INTERNAL_CLANGASSISTPROPOSAL_H
|
||||
#define CLANGCODEMODEL_INTERNAL_CLANGASSISTPROPOSAL_H
|
||||
|
||||
struct A {
|
||||
struct Inside {
|
||||
void doA() {}
|
||||
};
|
||||
};
|
||||
#include "clangassistproposalmodel.h"
|
||||
|
||||
struct B {
|
||||
struct Inside {
|
||||
void doB() {}
|
||||
};
|
||||
};
|
||||
#include <texteditor/codeassist/genericproposal.h>
|
||||
|
||||
template<class T> class C {
|
||||
public:
|
||||
typename T::Inside inner;
|
||||
};
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
int main()
|
||||
class ClangAssistProposal : public TextEditor::GenericProposal
|
||||
{
|
||||
C<A> ca;
|
||||
C<B> cb;
|
||||
ca.inner.doA();
|
||||
cb.inner.<<<<;
|
||||
public:
|
||||
ClangAssistProposal(int cursorPos, TextEditor::GenericProposalModel *model);
|
||||
|
||||
return 0;
|
||||
}
|
||||
virtual bool isCorrective() const;
|
||||
virtual void makeCorrection(TextEditor::TextEditorWidget *editorWidget);
|
||||
|
||||
private:
|
||||
bool m_replaceDotForArrow;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
|
||||
#endif // CLANGCODEMODEL_INTERNAL_CLANGASSISTPROPOSAL_H
|
225
src/plugins/clangcodemodel/clangassistproposalitem.cpp
Normal file
225
src/plugins/clangcodemodel/clangassistproposalitem.cpp
Normal file
@@ -0,0 +1,225 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "clangassistproposalitem.h"
|
||||
|
||||
#include <cplusplus/MatchingText.h>
|
||||
#include <cplusplus/Token.h>
|
||||
|
||||
#include <texteditor/completionsettings.h>
|
||||
#include <texteditor/texteditor.h>
|
||||
#include <texteditor/texteditorsettings.h>
|
||||
|
||||
using namespace CPlusPlus;
|
||||
using namespace ClangBackEnd;
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
bool ClangAssistProposalItem::prematurelyApplies(const QChar &typedChar) const
|
||||
{
|
||||
bool applies = false;
|
||||
|
||||
if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT)
|
||||
applies = QString::fromLatin1("(,").contains(typedChar);
|
||||
else if (m_completionOperator == T_STRING_LITERAL || m_completionOperator == T_ANGLE_STRING_LITERAL)
|
||||
applies = (typedChar == QLatin1Char('/')) && text().endsWith(QLatin1Char('/'));
|
||||
else if (!isCodeCompletion())
|
||||
applies = (typedChar == QLatin1Char('(')); /* && data().canConvert<CompleteFunctionDeclaration>()*/ //###
|
||||
else if (codeCompletion().completionKind() == CodeCompletion::ObjCMessageCompletionKind)
|
||||
applies = QString::fromLatin1(";.,").contains(typedChar);
|
||||
else
|
||||
applies = QString::fromLatin1(";.,:(").contains(typedChar);
|
||||
|
||||
if (applies)
|
||||
m_typedChar = typedChar;
|
||||
|
||||
return applies;
|
||||
}
|
||||
|
||||
void ClangAssistProposalItem::applyContextualContent(TextEditor::TextEditorWidget *editorWidget,
|
||||
int basePosition) const
|
||||
{
|
||||
const CodeCompletion ccr = codeCompletion();
|
||||
|
||||
QString toInsert = text();
|
||||
QString extraChars;
|
||||
int extraLength = 0;
|
||||
int cursorOffset = 0;
|
||||
|
||||
bool autoParenthesesEnabled = true;
|
||||
if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
|
||||
extraChars += QLatin1Char(')');
|
||||
if (m_typedChar == QLatin1Char('(')) // Eat the opening parenthesis
|
||||
m_typedChar = QChar();
|
||||
} else if (m_completionOperator == T_STRING_LITERAL || m_completionOperator == T_ANGLE_STRING_LITERAL) {
|
||||
if (!toInsert.endsWith(QLatin1Char('/'))) {
|
||||
extraChars += QLatin1Char((m_completionOperator == T_ANGLE_STRING_LITERAL) ? '>' : '"');
|
||||
} else {
|
||||
if (m_typedChar == QLatin1Char('/')) // Eat the slash
|
||||
m_typedChar = QChar();
|
||||
}
|
||||
} else if (!ccr.text().isEmpty()) {
|
||||
const TextEditor::CompletionSettings &completionSettings =
|
||||
TextEditor::TextEditorSettings::instance()->completionSettings();
|
||||
const bool autoInsertBrackets = completionSettings.m_autoInsertBrackets;
|
||||
|
||||
if (autoInsertBrackets &&
|
||||
(ccr.completionKind() == CodeCompletion::FunctionCompletionKind
|
||||
|| ccr.completionKind() == CodeCompletion::DestructorCompletionKind
|
||||
|| ccr.completionKind() == CodeCompletion::SignalCompletionKind
|
||||
|| ccr.completionKind() == CodeCompletion::SlotCompletionKind)) {
|
||||
// When the user typed the opening parenthesis, he'll likely also type the closing one,
|
||||
// in which case it would be annoying if we put the cursor after the already automatically
|
||||
// inserted closing parenthesis.
|
||||
const bool skipClosingParenthesis = m_typedChar != QLatin1Char('(');
|
||||
|
||||
if (completionSettings.m_spaceAfterFunctionName)
|
||||
extraChars += QLatin1Char(' ');
|
||||
extraChars += QLatin1Char('(');
|
||||
if (m_typedChar == QLatin1Char('('))
|
||||
m_typedChar = QChar();
|
||||
|
||||
// If the function doesn't return anything, automatically place the semicolon,
|
||||
// unless we're doing a scope completion (then it might be function definition).
|
||||
const QChar characterAtCursor = editorWidget->characterAt(editorWidget->position());
|
||||
bool endWithSemicolon = m_typedChar == QLatin1Char(';')/*
|
||||
|| (function->returnType()->isVoidType() && m_completionOperator != T_COLON_COLON)*/; //###
|
||||
const QChar semicolon = m_typedChar.isNull() ? QLatin1Char(';') : m_typedChar;
|
||||
|
||||
if (endWithSemicolon && characterAtCursor == semicolon) {
|
||||
endWithSemicolon = false;
|
||||
m_typedChar = QChar();
|
||||
}
|
||||
|
||||
// If the function takes no arguments, automatically place the closing parenthesis
|
||||
if (!isOverloaded() && !ccr.hasParameters() && skipClosingParenthesis) {
|
||||
extraChars += QLatin1Char(')');
|
||||
if (endWithSemicolon) {
|
||||
extraChars += semicolon;
|
||||
m_typedChar = QChar();
|
||||
}
|
||||
} else if (autoParenthesesEnabled) {
|
||||
const QChar lookAhead = editorWidget->characterAt(editorWidget->position() + 1);
|
||||
if (MatchingText::shouldInsertMatchingText(lookAhead)) {
|
||||
extraChars += QLatin1Char(')');
|
||||
--cursorOffset;
|
||||
if (endWithSemicolon) {
|
||||
extraChars += semicolon;
|
||||
--cursorOffset;
|
||||
m_typedChar = QChar();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (autoInsertBrackets && data().canConvert<CompleteFunctionDeclaration>()) {
|
||||
if (m_typedChar == QLatin1Char('('))
|
||||
m_typedChar = QChar();
|
||||
|
||||
// everything from the closing parenthesis on are extra chars, to
|
||||
// make sure an auto-inserted ")" gets replaced by ") const" if necessary
|
||||
int closingParen = toInsert.lastIndexOf(QLatin1Char(')'));
|
||||
extraChars = toInsert.mid(closingParen);
|
||||
toInsert.truncate(closingParen);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Append an unhandled typed character, adjusting cursor offset when it had been adjusted before
|
||||
if (!m_typedChar.isNull()) {
|
||||
extraChars += m_typedChar;
|
||||
if (cursorOffset != 0)
|
||||
--cursorOffset;
|
||||
}
|
||||
|
||||
// Avoid inserting characters that are already there
|
||||
const int endsPosition = editorWidget->position(TextEditor::EndOfLinePosition);
|
||||
const QString existingText = editorWidget->textAt(editorWidget->position(), endsPosition - editorWidget->position());
|
||||
int existLength = 0;
|
||||
if (!existingText.isEmpty()) {
|
||||
// Calculate the exist length in front of the extra chars
|
||||
existLength = toInsert.length() - (editorWidget->position() - basePosition);
|
||||
while (!existingText.startsWith(toInsert.right(existLength))) {
|
||||
if (--existLength == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < extraChars.length(); ++i) {
|
||||
const QChar a = extraChars.at(i);
|
||||
const QChar b = editorWidget->characterAt(editorWidget->position() + i + existLength);
|
||||
if (a == b)
|
||||
++extraLength;
|
||||
else
|
||||
break;
|
||||
}
|
||||
toInsert += extraChars;
|
||||
|
||||
// Insert the remainder of the name
|
||||
const int length = editorWidget->position() - basePosition + existLength + extraLength;
|
||||
editorWidget->setCursorPosition(basePosition);
|
||||
editorWidget->replace(length, toInsert);
|
||||
if (cursorOffset)
|
||||
editorWidget->setCursorPosition(editorWidget->position() + cursorOffset);
|
||||
}
|
||||
|
||||
void ClangAssistProposalItem::keepCompletionOperator(unsigned compOp)
|
||||
{
|
||||
m_completionOperator = compOp;
|
||||
}
|
||||
|
||||
bool ClangAssistProposalItem::isOverloaded() const
|
||||
{
|
||||
return !m_overloads.isEmpty();
|
||||
}
|
||||
|
||||
void ClangAssistProposalItem::addOverload(const CodeCompletion &ccr)
|
||||
{
|
||||
m_overloads.append(ccr);
|
||||
}
|
||||
|
||||
CodeCompletion ClangAssistProposalItem::codeCompletion() const
|
||||
{
|
||||
const QVariant &value = data();
|
||||
if (value.canConvert<CodeCompletion>())
|
||||
return value.value<CodeCompletion>();
|
||||
else
|
||||
return CodeCompletion();
|
||||
}
|
||||
|
||||
bool ClangAssistProposalItem::isCodeCompletion() const
|
||||
{
|
||||
return data().canConvert<CodeCompletion>();
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
|
67
src/plugins/clangcodemodel/clangassistproposalitem.h
Normal file
67
src/plugins/clangcodemodel/clangassistproposalitem.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CLANGCODEMODEL_INTERNAL_CLANGASSISTPROPOSALITEM_H
|
||||
#define CLANGCODEMODEL_INTERNAL_CLANGASSISTPROPOSALITEM_H
|
||||
|
||||
#include <codecompletion.h>
|
||||
|
||||
#include <texteditor/codeassist/assistproposalitem.h>
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
class ClangAssistProposalItem : public TextEditor::AssistProposalItem
|
||||
{
|
||||
friend bool operator<(const ClangAssistProposalItem &first, const ClangAssistProposalItem &second);
|
||||
public:
|
||||
ClangAssistProposalItem() {}
|
||||
|
||||
bool prematurelyApplies(const QChar &c) const override;
|
||||
void applyContextualContent(TextEditor::TextEditorWidget *editorWidget, int basePosition) const override;
|
||||
|
||||
void keepCompletionOperator(unsigned compOp);
|
||||
|
||||
bool isOverloaded() const;
|
||||
void addOverload(const ClangBackEnd::CodeCompletion &ccr);
|
||||
|
||||
ClangBackEnd::CodeCompletion codeCompletion() const;
|
||||
|
||||
bool isCodeCompletion() const;
|
||||
private:
|
||||
unsigned m_completionOperator;
|
||||
mutable QChar m_typedChar;
|
||||
QList<ClangBackEnd::CodeCompletion> m_overloads;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
|
||||
#endif // CLANGCODEMODEL_INTERNAL_CLANGASSISTPROPOSALITEM_H
|
78
src/plugins/clangcodemodel/clangassistproposalmodel.cpp
Normal file
78
src/plugins/clangcodemodel/clangassistproposalmodel.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "clangassistproposalitem.h"
|
||||
|
||||
#include "clangassistproposalmodel.h"
|
||||
|
||||
#include <texteditor/codeassist/assistproposalitem.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
namespace {
|
||||
|
||||
const ClangAssistProposalItem &toClangAssistProposalItem(TextEditor::AssistProposalItem *assistProposalItem)
|
||||
{
|
||||
return *static_cast<ClangAssistProposalItem*>(assistProposalItem);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool ClangAssistProposalModel::replaceDotForArrow(TextEditor::IAssistProposalModel *model)
|
||||
{
|
||||
auto clangAssistProposalModel = static_cast<ClangAssistProposalModel*>(model);
|
||||
|
||||
return clangAssistProposalModel->m_replaceDotForArrow;
|
||||
}
|
||||
|
||||
bool ClangAssistProposalModel::isSortable(const QString &/*prefix*/) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClangAssistProposalModel::sort(const QString &/*prefix*/)
|
||||
{
|
||||
using TextEditor::AssistProposalItem;
|
||||
|
||||
auto currentItemsCompare = [](AssistProposalItem *first, AssistProposalItem *second) {
|
||||
return (first->order() > 0
|
||||
&& (first->order() < second->order()
|
||||
|| (first->order() == second->order() && first->text() < second->text())));
|
||||
};
|
||||
|
||||
std::sort(m_currentItems.begin(), m_currentItems.end(), currentItemsCompare);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
|
@@ -28,26 +28,37 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
// Expected:
|
||||
// (List, List<$class Item$>),
|
||||
// (Tuple, Tuple<$class First$, $class Second$, $typename Third$>)
|
||||
#ifndef CLANGCODEMODEL_INTERNAL_CLANGASSISTPROPOSALMODEL_H
|
||||
#define CLANGCODEMODEL_INTERNAL_CLANGASSISTPROPOSALMODEL_H
|
||||
|
||||
template <class Item>
|
||||
class List
|
||||
#include <cplusplus/Token.h>
|
||||
|
||||
#include <texteditor/codeassist/genericproposalmodel.h>
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
class ClangAssistProposalModel : public TextEditor::GenericProposalModel
|
||||
{
|
||||
Item *data;
|
||||
public:
|
||||
ClangAssistProposalModel()
|
||||
: m_sortable(false)
|
||||
, m_completionOperator(CPlusPlus::T_EOF_SYMBOL)
|
||||
, m_replaceDotForArrow(false)
|
||||
{}
|
||||
|
||||
bool isSortable(const QString &prefix) const override;
|
||||
void sort(const QString &prefix) override;
|
||||
|
||||
static bool replaceDotForArrow(IAssistProposalModel *model);
|
||||
|
||||
private:
|
||||
bool m_sortable;
|
||||
unsigned m_completionOperator;
|
||||
bool m_replaceDotForArrow;
|
||||
};
|
||||
|
||||
template <class First, class Second, typename Third>
|
||||
class Tuple
|
||||
{
|
||||
First *data;
|
||||
Second *data2;
|
||||
Third *data3;
|
||||
};
|
||||
|
||||
void check()
|
||||
{
|
||||
<<<<
|
||||
}
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
|
||||
#endif // CLANGCODEMODEL_INTERNAL_CLANGASSISTPROPOSALMODEL_H
|
@@ -30,7 +30,7 @@
|
||||
|
||||
#include "clangbackendipcintegration.h"
|
||||
|
||||
#include "clangcompletion.h"
|
||||
#include "clangcompletionassistprocessor.h"
|
||||
#include "clangmodelmanagersupport.h"
|
||||
#include "clangutils.h"
|
||||
#include "pchmanager.h"
|
||||
|
@@ -12,123 +12,117 @@ DEFINES += "\"CLANG_RESOURCE_DIR=\\\"$${LLVM_LIBDIR}/clang/$${LLVM_VERSION}/incl
|
||||
unix:QMAKE_LFLAGS += -Wl,-rpath,\'$$LLVM_LIBDIR\'
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/clangcodemodelplugin.cpp \
|
||||
$$PWD/clangcompleter.cpp \
|
||||
$$PWD/clangcompletioncontextanalyzer.cpp \
|
||||
$$PWD/clangcompletion.cpp \
|
||||
$$PWD/clangeditordocumentparser.cpp \
|
||||
$$PWD/clangeditordocumentprocessor.cpp \
|
||||
$$PWD/clangmodelmanagersupport.cpp \
|
||||
$$PWD/clangprojectsettings.cpp \
|
||||
$$PWD/clangprojectsettingspropertiespage.cpp \
|
||||
$$PWD/clangutils.cpp \
|
||||
$$PWD/clangbackendipcintegration.cpp \
|
||||
$$PWD/completionchunkstotextconverter.cpp \
|
||||
$$PWD/completionproposalsbuilder.cpp \
|
||||
$$PWD/cppcreatemarkers.cpp \
|
||||
$$PWD/cxprettyprinter.cpp \
|
||||
$$PWD/diagnostic.cpp \
|
||||
$$PWD/fastindexer.cpp \
|
||||
$$PWD/pchinfo.cpp \
|
||||
$$PWD/pchmanager.cpp \
|
||||
$$PWD/raii/scopedclangoptions.cpp \
|
||||
$$PWD/semanticmarker.cpp \
|
||||
$$PWD/sourcelocation.cpp \
|
||||
$$PWD/sourcemarker.cpp \
|
||||
$$PWD/symbol.cpp \
|
||||
$$PWD/unit.cpp \
|
||||
$$PWD/unsavedfiledata.cpp \
|
||||
$$PWD/utils.cpp \
|
||||
$$PWD/utils_p.cpp
|
||||
activationsequenceprocessor.cpp \
|
||||
clangassistproposal.cpp \
|
||||
clangassistproposalitem.cpp \
|
||||
clangassistproposalmodel.cpp \
|
||||
clangbackendipcintegration.cpp \
|
||||
clangcodemodelplugin.cpp \
|
||||
clangcompletionassistinterface.cpp \
|
||||
clangcompletionassistprocessor.cpp \
|
||||
clangcompletionassistprovider.cpp \
|
||||
clangcompletioncontextanalyzer.cpp \
|
||||
clangeditordocumentparser.cpp \
|
||||
clangeditordocumentprocessor.cpp \
|
||||
clangfunctionhintmodel.cpp \
|
||||
clangmodelmanagersupport.cpp \
|
||||
clangprojectsettings.cpp \
|
||||
clangprojectsettingspropertiespage.cpp \
|
||||
clangutils.cpp \
|
||||
completionchunkstotextconverter.cpp \
|
||||
cppcreatemarkers.cpp \
|
||||
cxprettyprinter.cpp \
|
||||
diagnostic.cpp \
|
||||
fastindexer.cpp \
|
||||
pchinfo.cpp \
|
||||
pchmanager.cpp \
|
||||
raii/scopedclangoptions.cpp \
|
||||
semanticmarker.cpp \
|
||||
sourcelocation.cpp \
|
||||
sourcemarker.cpp \
|
||||
symbol.cpp \
|
||||
unit.cpp \
|
||||
unsavedfiledata.cpp \
|
||||
utils.cpp \
|
||||
utils_p.cpp
|
||||
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/clangcodemodelplugin.h \
|
||||
$$PWD/clangcompleter.h \
|
||||
$$PWD/clangcompletioncontextanalyzer.h \
|
||||
$$PWD/clangcompletion.h \
|
||||
$$PWD/clangeditordocumentparser.h \
|
||||
$$PWD/clangeditordocumentprocessor.h \
|
||||
$$PWD/clang_global.h \
|
||||
$$PWD/clangmodelmanagersupport.h \
|
||||
$$PWD/clangprojectsettings.h \
|
||||
$$PWD/clangprojectsettingspropertiespage.h \
|
||||
$$PWD/clangutils.h \
|
||||
$$PWD/clangbackendipcintegration.h \
|
||||
$$PWD/completionchunkstotextconverter.h \
|
||||
$$PWD/completionproposalsbuilder.h \
|
||||
$$PWD/constants.h \
|
||||
$$PWD/cppcreatemarkers.h \
|
||||
$$PWD/cxprettyprinter.h \
|
||||
$$PWD/cxraii.h \
|
||||
$$PWD/diagnostic.h \
|
||||
$$PWD/fastindexer.h \
|
||||
$$PWD/pchinfo.h \
|
||||
$$PWD/pchmanager.h \
|
||||
$$PWD/raii/scopedclangoptions.h \
|
||||
$$PWD/semanticmarker.h \
|
||||
$$PWD/sourcelocation.h \
|
||||
$$PWD/sourcemarker.h \
|
||||
$$PWD/symbol.h \
|
||||
$$PWD/unit.h \
|
||||
$$PWD/unsavedfiledata.h \
|
||||
$$PWD/utils.h \
|
||||
$$PWD/utils_p.h
|
||||
activationsequenceprocessor.h \
|
||||
clangassistproposal.h \
|
||||
clangassistproposalitem.h \
|
||||
clangassistproposalmodel.h \
|
||||
clangbackendipcintegration.h \
|
||||
clangcodemodelplugin.h \
|
||||
clangcompletionassistinterface.h \
|
||||
clangcompletionassistprocessor.h \
|
||||
clangcompletionassistprovider.h \
|
||||
clangcompletioncontextanalyzer.h \
|
||||
clangeditordocumentparser.h \
|
||||
clangeditordocumentprocessor.h \
|
||||
clangfunctionhintmodel.h \
|
||||
clang_global.h \
|
||||
clangmodelmanagersupport.h \
|
||||
clangprojectsettings.h \
|
||||
clangprojectsettingspropertiespage.h \
|
||||
clangutils.h \
|
||||
completionchunkstotextconverter.h \
|
||||
constants.h \
|
||||
cppcreatemarkers.h \
|
||||
cxprettyprinter.h \
|
||||
cxraii.h \
|
||||
diagnostic.h \
|
||||
fastindexer.h \
|
||||
pchinfo.h \
|
||||
pchmanager.h \
|
||||
raii/scopedclangoptions.h \
|
||||
semanticmarker.h \
|
||||
sourcelocation.h \
|
||||
sourcemarker.h \
|
||||
symbol.h \
|
||||
unit.h \
|
||||
unsavedfiledata.h \
|
||||
utils.h \
|
||||
utils_p.h
|
||||
|
||||
|
||||
contains(DEFINES, CLANG_INDEXING) {
|
||||
HEADERS += \
|
||||
$$PWD/clangindexer.h \
|
||||
$$PWD/index.h \
|
||||
$$PWD/indexer.h
|
||||
# $$PWD/dependencygraph.h \
|
||||
clangindexer.h \
|
||||
index.h \
|
||||
indexer.h
|
||||
# dependencygraph.h \
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/clangindexer.cpp \
|
||||
$$PWD/index.cpp \
|
||||
$$PWD/indexer.cpp
|
||||
# $$PWD/dependencygraph.cpp \
|
||||
clangindexer.cpp \
|
||||
index.cpp \
|
||||
indexer.cpp
|
||||
# dependencygraph.cpp \
|
||||
}
|
||||
|
||||
FORMS += $$PWD/clangprojectsettingspropertiespage.ui
|
||||
FORMS += clangprojectsettingspropertiespage.ui
|
||||
|
||||
equals(TEST, 1) {
|
||||
RESOURCES += \
|
||||
$$PWD/test/clang_tests_database.qrc
|
||||
test/clang_tests_database.qrc
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/test/clangcodecompletion_test.h \
|
||||
$$PWD/test/clangcompletioncontextanalyzertest.h \
|
||||
$$PWD/test/completiontesthelper.h
|
||||
test/clangcodecompletion_test.h \
|
||||
test/clangcompletioncontextanalyzertest.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/test/clangcodecompletion_test.cpp \
|
||||
$$PWD/test/clangcompletioncontextanalyzertest.cpp \
|
||||
$$PWD/test/clangcompletion_test.cpp \
|
||||
$$PWD/test/completiontesthelper.cpp
|
||||
test/clangcodecompletion_test.cpp \
|
||||
test/clangcompletioncontextanalyzertest.cpp
|
||||
|
||||
|
||||
DISTFILES += \
|
||||
$$PWD/test/mysource.cpp \
|
||||
$$PWD/test/myheader.cpp \
|
||||
$$PWD/test/completionWithProject.cpp \
|
||||
$$PWD/test/memberCompletion.cpp \
|
||||
$$PWD/test/doxygenKeywordsCompletion.cpp \
|
||||
$$PWD/test/preprocessorKeywordsCompletion.cpp \
|
||||
$$PWD/test/includeDirectiveCompletion.cpp \
|
||||
$$PWD/test/cxx_regression_1.cpp \
|
||||
$$PWD/test/cxx_regression_2.cpp \
|
||||
$$PWD/test/cxx_regression_3.cpp \
|
||||
$$PWD/test/cxx_regression_4.cpp \
|
||||
$$PWD/test/cxx_regression_5.cpp \
|
||||
$$PWD/test/cxx_regression_6.cpp \
|
||||
$$PWD/test/cxx_regression_7.cpp \
|
||||
$$PWD/test/cxx_regression_8.cpp \
|
||||
$$PWD/test/cxx_regression_9.cpp \
|
||||
$$PWD/test/cxx_snippets_1.cpp \
|
||||
$$PWD/test/cxx_snippets_2.cpp \
|
||||
$$PWD/test/cxx_snippets_3.cpp \
|
||||
$$PWD/test/cxx_snippets_4.cpp \
|
||||
$$PWD/test/objc_messages_1.mm \
|
||||
$$PWD/test/objc_messages_2.mm \
|
||||
$$PWD/test/objc_messages_3.mm
|
||||
test/mysource.cpp \
|
||||
test/myheader.cpp \
|
||||
test/completionWithProject.cpp \
|
||||
test/memberCompletion.cpp \
|
||||
test/doxygenKeywordsCompletion.cpp \
|
||||
test/preprocessorKeywordsCompletion.cpp \
|
||||
test/includeDirectiveCompletion.cpp
|
||||
}
|
||||
|
||||
macx {
|
||||
|
@@ -53,12 +53,22 @@ QtcPlugin {
|
||||
name: "Completion support"
|
||||
condition: product.clangCompletion
|
||||
files: [
|
||||
"clangcompleter.cpp",
|
||||
"clangcompleter.h",
|
||||
"clangcompletion.cpp",
|
||||
"clangcompletion.h",
|
||||
"completionproposalsbuilder.cpp",
|
||||
"completionproposalsbuilder.h",
|
||||
"activationsequenceprocessor.cpp",
|
||||
"activationsequenceprocessor.h",
|
||||
"clangassistproposal.cpp",
|
||||
"clangassistproposal.h",
|
||||
"clangassistproposalitem.cpp",
|
||||
"clangassistproposalitem.h",
|
||||
"clangassistproposalmodel.cpp",
|
||||
"clangassistproposalmodel.h",
|
||||
"clangcompletionassistinterface.cpp",
|
||||
"clangcompletionassistinterface.h",
|
||||
"clangcompletionassistprocessor.cpp",
|
||||
"clangcompletionassistprocessor.h",
|
||||
"clangcompletionassistprovider.cpp",
|
||||
"clangcompletionassistprovider.h",
|
||||
"clangfunctionhintmodel.cpp",
|
||||
"clangfunctionhintmodel.h",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -92,9 +102,6 @@ QtcPlugin {
|
||||
prefix: "test/"
|
||||
files: [
|
||||
"clang_tests_database.qrc",
|
||||
"clangcompletion_test.cpp",
|
||||
"completiontesthelper.cpp",
|
||||
"completiontesthelper.h",
|
||||
"clangcodecompletion_test.cpp",
|
||||
"clangcodecompletion_test.h",
|
||||
"clangcompletioncontextanalyzertest.cpp",
|
||||
@@ -114,19 +121,6 @@ QtcPlugin {
|
||||
"doxygenKeywordsCompletion.cpp",
|
||||
"preprocessorKeywordsCompletion.cpp",
|
||||
"includeDirectiveCompletion.cpp",
|
||||
"cxx_regression_1.cpp",
|
||||
"cxx_regression_2.cpp",
|
||||
"cxx_regression_3.cpp",
|
||||
"cxx_regression_4.cpp",
|
||||
"cxx_regression_5.cpp",
|
||||
"cxx_regression_6.cpp",
|
||||
"cxx_regression_7.cpp",
|
||||
"cxx_regression_8.cpp",
|
||||
"cxx_regression_9.cpp",
|
||||
"cxx_snippets_1.cpp",
|
||||
"cxx_snippets_2.cpp",
|
||||
"cxx_snippets_3.cpp",
|
||||
"cxx_snippets_4.cpp",
|
||||
"objc_messages_1.mm",
|
||||
"objc_messages_2.mm",
|
||||
"objc_messages_3.mm",
|
||||
|
@@ -61,14 +61,6 @@ private:
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
QList<QObject *> createTestObjects() const;
|
||||
|
||||
private slots:
|
||||
void test_CXX_regressions();
|
||||
void test_CXX_regressions_data();
|
||||
void test_CXX_snippets();
|
||||
void test_CXX_snippets_data();
|
||||
void test_ObjC_hints();
|
||||
void test_ObjC_hints_data();
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@@ -1,5 +1,7 @@
|
||||
INCLUDEPATH += $$PWD
|
||||
|
||||
SOURCES += $$PWD/completionchunkstotextconverter.cpp
|
||||
SOURCES += $$PWD/completionchunkstotextconverter.cpp \
|
||||
$$PWD/activationsequenceprocessor.cpp
|
||||
|
||||
HEADERS += $$PWD/completionchunkstotextconverter.h
|
||||
HEADERS += $$PWD/completionchunkstotextconverter.h \
|
||||
$$PWD/activationsequenceprocessor.h
|
||||
|
@@ -1,213 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "clangcompleter.h"
|
||||
#include "sourcemarker.h"
|
||||
#include "unsavedfiledata.h"
|
||||
#include "utils_p.h"
|
||||
#include "completionproposalsbuilder.h"
|
||||
#include "raii/scopedclangoptions.h"
|
||||
#include "unit.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
#include <QTime>
|
||||
|
||||
#include <clang-c/Index.h>
|
||||
|
||||
//#define TIME_COMPLETION
|
||||
|
||||
using namespace ClangCodeModel::Internal;
|
||||
|
||||
namespace ClangCodeModel {
|
||||
|
||||
class ClangCompleter::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData()
|
||||
: m_mutex(QMutex::Recursive)
|
||||
, m_unit(Unit::create())
|
||||
, m_isSignalSlotCompletion(false)
|
||||
{
|
||||
}
|
||||
|
||||
~PrivateData()
|
||||
{
|
||||
}
|
||||
|
||||
bool parseFromFile(const UnsavedFiles &unsavedFiles)
|
||||
{
|
||||
Q_ASSERT(!m_unit->isLoaded());
|
||||
if (m_unit->fileName().isEmpty())
|
||||
return false;
|
||||
|
||||
unsigned opts = clang_defaultEditingTranslationUnitOptions();
|
||||
#if defined(CINDEX_VERSION) && (CINDEX_VERSION > 5)
|
||||
opts |= CXTranslationUnit_CacheCompletionResults;
|
||||
opts |= CXTranslationUnit_IncludeBriefCommentsInCodeCompletion;
|
||||
#endif
|
||||
m_unit->setManagementOptions(opts);
|
||||
|
||||
m_unit->setUnsavedFiles(unsavedFiles);
|
||||
m_unit->parse();
|
||||
return m_unit->isLoaded();
|
||||
}
|
||||
|
||||
public:
|
||||
QMutex m_mutex;
|
||||
Unit::Ptr m_unit;
|
||||
bool m_isSignalSlotCompletion;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Constructs with highest possible priority
|
||||
*/
|
||||
CodeCompletionResult::CodeCompletionResult()
|
||||
: m_priority(SHRT_MAX)
|
||||
, m_completionKind(Other)
|
||||
, m_availability(Available)
|
||||
, m_hasParameters(false)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Constructs with given priority
|
||||
* @param priority Will be reversed, because clang's highest priority is 0,
|
||||
* but inside QtCreator it is the lowest priority
|
||||
*/
|
||||
CodeCompletionResult::CodeCompletionResult(unsigned priority)
|
||||
: m_priority(SHRT_MAX - priority)
|
||||
, m_completionKind(Other)
|
||||
, m_availability(Available)
|
||||
, m_hasParameters(false)
|
||||
{
|
||||
}
|
||||
|
||||
ClangCompleter::ClangCompleter()
|
||||
: d(new PrivateData)
|
||||
{
|
||||
}
|
||||
|
||||
ClangCompleter::~ClangCompleter()
|
||||
{
|
||||
}
|
||||
|
||||
QString ClangCompleter::fileName() const
|
||||
{
|
||||
return d->m_unit->fileName();
|
||||
}
|
||||
|
||||
void ClangCompleter::setFileName(const QString &fileName)
|
||||
{
|
||||
if (d->m_unit->fileName() != fileName) {
|
||||
d->m_unit = Unit::create(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
QStringList ClangCompleter::options() const
|
||||
{
|
||||
return d->m_unit->compilationOptions();
|
||||
}
|
||||
|
||||
void ClangCompleter::setOptions(const QStringList &options) const
|
||||
{
|
||||
if (d->m_unit->compilationOptions() != options) {
|
||||
d->m_unit->setCompilationOptions(options);
|
||||
d->m_unit->unload();
|
||||
}
|
||||
}
|
||||
|
||||
bool ClangCompleter::isSignalSlotCompletion() const
|
||||
{
|
||||
return d->m_isSignalSlotCompletion;
|
||||
}
|
||||
|
||||
void ClangCompleter::setSignalSlotCompletion(bool isSignalSlot)
|
||||
{
|
||||
d->m_isSignalSlotCompletion = isSignalSlot;
|
||||
}
|
||||
|
||||
bool ClangCompleter::reparse(const UnsavedFiles &unsavedFiles)
|
||||
{
|
||||
if (!d->m_unit->isLoaded())
|
||||
return d->parseFromFile(unsavedFiles);
|
||||
|
||||
d->m_unit->setUnsavedFiles(unsavedFiles);
|
||||
d->m_unit->reparse();
|
||||
return d->m_unit->isLoaded();
|
||||
}
|
||||
|
||||
QList<CodeCompletionResult> ClangCompleter::codeCompleteAt(unsigned line,
|
||||
unsigned column,
|
||||
const UnsavedFiles &unsavedFiles)
|
||||
{
|
||||
#ifdef TIME_COMPLETION
|
||||
QTime t;t.start();
|
||||
#endif // TIME_COMPLETION
|
||||
|
||||
if (!d->m_unit->isLoaded())
|
||||
if (!d->parseFromFile(unsavedFiles))
|
||||
return QList<CodeCompletionResult>();
|
||||
|
||||
ScopedCXCodeCompleteResults results;
|
||||
d->m_unit->setUnsavedFiles(unsavedFiles);
|
||||
d->m_unit->codeCompleteAt(line, column, results);
|
||||
|
||||
QList<CodeCompletionResult> completions;
|
||||
if (results) {
|
||||
const quint64 contexts = clang_codeCompleteGetContexts(results);
|
||||
CompletionProposalsBuilder builder(completions, contexts, d->m_isSignalSlotCompletion);
|
||||
for (unsigned i = 0; i < results.size(); ++i)
|
||||
builder(results.completionAt(i));
|
||||
}
|
||||
|
||||
#ifdef TIME_COMPLETION
|
||||
qDebug() << "Completion timing:" << completions.size() << "results in" << t.elapsed() << "ms.";
|
||||
#endif // TIME_COMPLETION
|
||||
|
||||
return completions;
|
||||
}
|
||||
|
||||
bool ClangCompleter::objcEnabled() const
|
||||
{
|
||||
static const QString objcppOption = QLatin1String("-ObjC++");
|
||||
static const QString objcOption = QLatin1String("-ObjC");
|
||||
|
||||
QStringList options = d->m_unit->compilationOptions();
|
||||
return options.contains(objcOption) || options.contains(objcppOption);
|
||||
}
|
||||
|
||||
QMutex *ClangCompleter::mutex() const
|
||||
{
|
||||
return &d->m_mutex;
|
||||
}
|
||||
|
||||
} // namespace ClangCodeModel
|
@@ -1,224 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CLANGCOMPLETER_H
|
||||
#define CLANGCOMPLETER_H
|
||||
|
||||
#include "clang_global.h"
|
||||
#include "diagnostic.h"
|
||||
#include "sourcelocation.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QMutex>
|
||||
#include <QPair>
|
||||
#include <QSharedPointer>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QVariant>
|
||||
|
||||
namespace ClangCodeModel {
|
||||
|
||||
class SourceMarker;
|
||||
|
||||
class CLANG_EXPORT CodeCompletionResult
|
||||
{
|
||||
public:
|
||||
enum Kind {
|
||||
Other = 0,
|
||||
FunctionCompletionKind,
|
||||
ConstructorCompletionKind,
|
||||
DestructorCompletionKind,
|
||||
VariableCompletionKind,
|
||||
ClassCompletionKind,
|
||||
EnumCompletionKind,
|
||||
EnumeratorCompletionKind,
|
||||
NamespaceCompletionKind,
|
||||
PreProcessorCompletionKind,
|
||||
SignalCompletionKind,
|
||||
SlotCompletionKind,
|
||||
ObjCMessageCompletionKind,
|
||||
KeywordCompletionKind,
|
||||
ClangSnippetKind
|
||||
};
|
||||
|
||||
enum Availability {
|
||||
Available,
|
||||
Deprecated,
|
||||
NotAvailable,
|
||||
NotAccessible
|
||||
};
|
||||
|
||||
public:
|
||||
CodeCompletionResult();
|
||||
CodeCompletionResult(unsigned priority);
|
||||
|
||||
unsigned priority() const
|
||||
{ return m_priority; }
|
||||
|
||||
bool isValid() const
|
||||
{ return !m_text.isEmpty(); }
|
||||
|
||||
QString text() const
|
||||
{ return m_text; }
|
||||
void setText(const QString &text)
|
||||
{ m_text = text; }
|
||||
|
||||
QString hint() const
|
||||
{ return m_hint; }
|
||||
void setHint(const QString &hint)
|
||||
{ m_hint = hint; }
|
||||
|
||||
QString snippet() const
|
||||
{ return m_snippet; }
|
||||
void setSnippet(const QString &snippet)
|
||||
{ m_snippet = snippet; }
|
||||
|
||||
Kind completionKind() const
|
||||
{ return m_completionKind; }
|
||||
void setCompletionKind(Kind type)
|
||||
{ m_completionKind = type; }
|
||||
|
||||
int compare(const CodeCompletionResult &other) const
|
||||
{
|
||||
if (m_priority < other.m_priority)
|
||||
return -1;
|
||||
else if (m_priority > other.m_priority)
|
||||
return 1;
|
||||
|
||||
if (m_completionKind < other.m_completionKind)
|
||||
return -1;
|
||||
else if (m_completionKind > other.m_completionKind)
|
||||
return 1;
|
||||
|
||||
if (m_text < other.m_text)
|
||||
return -1;
|
||||
else if (m_text > other.m_text)
|
||||
return 1;
|
||||
|
||||
if (m_hint < other.m_hint)
|
||||
return -1;
|
||||
else if (m_hint > other.m_hint)
|
||||
return 1;
|
||||
|
||||
if (!m_hasParameters && other.m_hasParameters)
|
||||
return -1;
|
||||
else if (m_hasParameters && !other.m_hasParameters)
|
||||
return 1;
|
||||
|
||||
if (m_availability < other.m_availability)
|
||||
return -1;
|
||||
else if (m_availability > other.m_availability)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool hasParameters() const
|
||||
{ return m_hasParameters; }
|
||||
void setHasParameters(bool hasParameters)
|
||||
{ m_hasParameters = hasParameters; }
|
||||
|
||||
Availability availability() const
|
||||
{ return m_availability; }
|
||||
void setAvailability(Availability availability)
|
||||
{ m_availability = availability; }
|
||||
|
||||
private:
|
||||
unsigned m_priority;
|
||||
Kind m_completionKind;
|
||||
QString m_text;
|
||||
QString m_hint;
|
||||
QString m_snippet;
|
||||
Availability m_availability;
|
||||
bool m_hasParameters;
|
||||
};
|
||||
|
||||
inline CLANG_EXPORT uint qHash(const CodeCompletionResult &ccr)
|
||||
{ return ccr.completionKind() ^ qHash(ccr.text()); }
|
||||
|
||||
inline CLANG_EXPORT bool operator==(const CodeCompletionResult &ccr1, const CodeCompletionResult &ccr2)
|
||||
{ return ccr1.compare(ccr2) == 0; }
|
||||
|
||||
inline CLANG_EXPORT bool operator<(const CodeCompletionResult &ccr1, const CodeCompletionResult &ccr2)
|
||||
{
|
||||
return ccr1.compare(ccr2) < 0;
|
||||
}
|
||||
|
||||
class CLANG_EXPORT ClangCompleter
|
||||
{
|
||||
Q_DISABLE_COPY(ClangCompleter)
|
||||
|
||||
class PrivateData;
|
||||
|
||||
public: // data structures
|
||||
typedef QSharedPointer<ClangCompleter> Ptr;
|
||||
|
||||
public: // methods
|
||||
ClangCompleter();
|
||||
~ClangCompleter();
|
||||
|
||||
QString fileName() const;
|
||||
void setFileName(const QString &fileName);
|
||||
|
||||
QStringList options() const;
|
||||
void setOptions(const QStringList &options) const;
|
||||
|
||||
bool isSignalSlotCompletion() const;
|
||||
void setSignalSlotCompletion(bool isSignalSlot);
|
||||
|
||||
bool reparse(const Internal::UnsavedFiles &unsavedFiles);
|
||||
|
||||
/**
|
||||
* Do code-completion at the specified position.
|
||||
*
|
||||
* \param line The line number on which to do code-completion. The first
|
||||
* line of a file has line number 1.
|
||||
* \param column The column number where to do code-completion. Column
|
||||
* numbers start with 1.
|
||||
*/
|
||||
QList<CodeCompletionResult> codeCompleteAt(unsigned line,
|
||||
unsigned column,
|
||||
const Internal::UnsavedFiles &unsavedFiles);
|
||||
|
||||
bool objcEnabled() const;
|
||||
|
||||
QMutex *mutex() const;
|
||||
|
||||
private: // instance fields
|
||||
QScopedPointer<PrivateData> d;
|
||||
};
|
||||
|
||||
} // namespace Clang
|
||||
|
||||
Q_DECLARE_METATYPE(ClangCodeModel::CodeCompletionResult)
|
||||
|
||||
#endif // CLANGCOMPLETER_H
|
@@ -1,197 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CPPEDITOR_INTERNAL_CLANGCOMPLETION_H
|
||||
#define CPPEDITOR_INTERNAL_CLANGCOMPLETION_H
|
||||
|
||||
#include "clangcompleter.h"
|
||||
#include "clangbackendipcintegration.h"
|
||||
|
||||
#include <cpptools/cppcompletionassistprocessor.h>
|
||||
#include <cpptools/cppcompletionassistprovider.h>
|
||||
#include <cpptools/cppmodelmanager.h>
|
||||
|
||||
#include <texteditor/codeassist/assistinterface.h>
|
||||
#include <texteditor/codeassist/assistproposalitem.h>
|
||||
#include <texteditor/codeassist/completionassistprovider.h>
|
||||
#include <texteditor/codeassist/ifunctionhintproposalmodel.h>
|
||||
|
||||
#include <clangbackendipc/codecompletion.h>
|
||||
|
||||
#include <QStringList>
|
||||
#include <QTextCursor>
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
using CodeCompletions = QVector<ClangBackEnd::CodeCompletion>;
|
||||
|
||||
class ClangAssistProposalModel;
|
||||
|
||||
class ClangCompletionAssistProvider : public CppTools::CppCompletionAssistProvider
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ClangCompletionAssistProvider(IpcCommunicator &ipcCommunicator);
|
||||
|
||||
IAssistProvider::RunType runType() const override;
|
||||
|
||||
TextEditor::IAssistProcessor *createProcessor() const override;
|
||||
TextEditor::AssistInterface *createAssistInterface(
|
||||
const QString &filePath,
|
||||
const TextEditor::TextEditorWidget *textEditorWidget,
|
||||
const CPlusPlus::LanguageFeatures &languageFeatures,
|
||||
int position,
|
||||
TextEditor::AssistReason reason) const override;
|
||||
|
||||
private:
|
||||
IpcCommunicator &m_ipcCommunicator;
|
||||
};
|
||||
|
||||
class ClangAssistProposalItem : public TextEditor::AssistProposalItem
|
||||
{
|
||||
public:
|
||||
ClangAssistProposalItem() {}
|
||||
|
||||
bool prematurelyApplies(const QChar &c) const override;
|
||||
void applyContextualContent(TextEditor::TextEditorWidget *editorWidget, int basePosition) const override;
|
||||
|
||||
void keepCompletionOperator(unsigned compOp) { m_completionOperator = compOp; }
|
||||
|
||||
bool isOverloaded() const;
|
||||
void addOverload(const ClangBackEnd::CodeCompletion &ccr);
|
||||
|
||||
ClangBackEnd::CodeCompletion originalItem() const;
|
||||
|
||||
bool isCodeCompletion() const;
|
||||
|
||||
private:
|
||||
unsigned m_completionOperator;
|
||||
mutable QChar m_typedChar;
|
||||
QList<ClangBackEnd::CodeCompletion> m_overloads;
|
||||
};
|
||||
|
||||
class ClangFunctionHintModel : public TextEditor::IFunctionHintProposalModel
|
||||
{
|
||||
public:
|
||||
ClangFunctionHintModel(const CodeCompletions &functionSymbols);
|
||||
|
||||
void reset() override {}
|
||||
int size() const override { return m_functionSymbols.size(); }
|
||||
QString text(int index) const override;
|
||||
int activeArgument(const QString &prefix) const override;
|
||||
|
||||
private:
|
||||
CodeCompletions m_functionSymbols;
|
||||
mutable int m_currentArg;
|
||||
};
|
||||
|
||||
class ClangCompletionAssistInterface: public TextEditor::AssistInterface
|
||||
{
|
||||
public:
|
||||
ClangCompletionAssistInterface(ClangCodeModel::Internal::IpcCommunicator &ipcCommunicator,
|
||||
const TextEditor::TextEditorWidget *textEditorWidget,
|
||||
int position,
|
||||
const QString &fileName,
|
||||
TextEditor::AssistReason reason,
|
||||
const CppTools::ProjectPart::HeaderPaths &headerPaths,
|
||||
const Internal::PchInfo::Ptr &pchInfo,
|
||||
const CPlusPlus::LanguageFeatures &features);
|
||||
|
||||
ClangCodeModel::Internal::IpcCommunicator &ipcCommunicator() const;
|
||||
const ClangCodeModel::Internal::UnsavedFiles &unsavedFiles() const;
|
||||
bool objcEnabled() const;
|
||||
const CppTools::ProjectPart::HeaderPaths &headerPaths() const;
|
||||
CPlusPlus::LanguageFeatures languageFeatures() const;
|
||||
const TextEditor::TextEditorWidget *textEditorWidget() const;
|
||||
|
||||
void setHeaderPaths(const CppTools::ProjectPart::HeaderPaths &headerPaths); // For tests
|
||||
|
||||
private:
|
||||
ClangCodeModel::Internal::IpcCommunicator &m_ipcCommunicator;
|
||||
ClangCodeModel::Internal::UnsavedFiles m_unsavedFiles;
|
||||
QStringList m_options;
|
||||
CppTools::ProjectPart::HeaderPaths m_headerPaths;
|
||||
Internal::PchInfo::Ptr m_savedPchPointer;
|
||||
CPlusPlus::LanguageFeatures m_languageFeatures;
|
||||
const TextEditor::TextEditorWidget *m_textEditorWidget;
|
||||
};
|
||||
|
||||
class ClangCompletionAssistProcessor : public CppTools::CppCompletionAssistProcessor
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(ClangCodeModel::Internal::ClangCompletionAssistProcessor)
|
||||
|
||||
public:
|
||||
ClangCompletionAssistProcessor();
|
||||
~ClangCompletionAssistProcessor();
|
||||
|
||||
TextEditor::IAssistProposal *perform(const TextEditor::AssistInterface *interface) override;
|
||||
|
||||
void asyncCompletionsAvailable(const CodeCompletions &completions);
|
||||
|
||||
const TextEditor::TextEditorWidget *textEditorWidget() const;
|
||||
|
||||
private:
|
||||
TextEditor::IAssistProposal *startCompletionHelper();
|
||||
int startOfOperator(int pos, unsigned *kind, bool wantFunctionCall) const;
|
||||
int findStartOfName(int pos = -1) const;
|
||||
bool accepts() const;
|
||||
|
||||
TextEditor::IAssistProposal *createProposal() const;
|
||||
|
||||
bool completeInclude(const QTextCursor &cursor);
|
||||
bool completeInclude(int position);
|
||||
void completeIncludePath(const QString &realPath, const QStringList &suffixes);
|
||||
bool completePreprocessorDirectives();
|
||||
bool completeDoxygenKeywords();
|
||||
void addCompletionItem(const QString &text,
|
||||
const QIcon &icon = QIcon(),
|
||||
int order = 0,
|
||||
const QVariant &data = QVariant());
|
||||
|
||||
void sendFileContent(const QString &projectFilePath, const QByteArray &modifiedFileContent);
|
||||
void sendCompletionRequest(int position, const QByteArray &modifiedFileContent);
|
||||
|
||||
void onCompletionsAvailable(const CodeCompletions &completions);
|
||||
void onFunctionHintCompletionsAvailable(const CodeCompletions &completions);
|
||||
|
||||
private:
|
||||
QScopedPointer<const ClangCompletionAssistInterface> m_interface;
|
||||
unsigned m_completionOperator;
|
||||
enum CompletionRequestType { NormalCompletion, FunctionHintCompletion } m_sentRequestType;
|
||||
QString m_functionName; // For type == Type::FunctionHintCompletion
|
||||
bool m_addSnippets = false; // For type == Type::NormalCompletion
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Clang
|
||||
|
||||
#endif // CPPEDITOR_INTERNAL_CLANGCOMPLETION_H
|
101
src/plugins/clangcodemodel/clangcompletionassistinterface.cpp
Normal file
101
src/plugins/clangcodemodel/clangcompletionassistinterface.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "clangcompletionassistinterface.h"
|
||||
|
||||
#include "clangutils.h"
|
||||
|
||||
#include <cpptools/cppmodelmanager.h>
|
||||
#include <cpptools/cppworkingcopy.h>
|
||||
|
||||
#include <texteditor/texteditor.h>
|
||||
|
||||
#include <cplusplus/Token.h>
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
ClangCompletionAssistInterface::ClangCompletionAssistInterface(
|
||||
IpcCommunicator &ipcCommunicator,
|
||||
const TextEditor::TextEditorWidget *textEditorWidget,
|
||||
int position,
|
||||
const QString &fileName,
|
||||
TextEditor::AssistReason reason,
|
||||
const CppTools::ProjectPart::HeaderPaths &headerPaths,
|
||||
const PchInfo::Ptr &pchInfo,
|
||||
const CPlusPlus::LanguageFeatures &features)
|
||||
: AssistInterface(textEditorWidget->document(), position, fileName, reason)
|
||||
, m_ipcCommunicator(ipcCommunicator)
|
||||
, m_headerPaths(headerPaths)
|
||||
, m_savedPchPointer(pchInfo)
|
||||
, m_languageFeatures(features)
|
||||
, m_textEditorWidget(textEditorWidget)
|
||||
{
|
||||
m_unsavedFiles = Utils::createUnsavedFiles(CppTools::CppModelManager::instance()->workingCopy());
|
||||
}
|
||||
|
||||
bool ClangCompletionAssistInterface::objcEnabled() const
|
||||
{
|
||||
return true; // TODO:
|
||||
}
|
||||
|
||||
const CppTools::ProjectPart::HeaderPaths &ClangCompletionAssistInterface::headerPaths() const
|
||||
{
|
||||
return m_headerPaths;
|
||||
}
|
||||
|
||||
CPlusPlus::LanguageFeatures ClangCompletionAssistInterface::languageFeatures() const
|
||||
{
|
||||
return m_languageFeatures;
|
||||
}
|
||||
|
||||
void ClangCompletionAssistInterface::setHeaderPaths(const CppTools::ProjectPart::HeaderPaths &headerPaths)
|
||||
{
|
||||
m_headerPaths = headerPaths;
|
||||
}
|
||||
|
||||
const TextEditor::TextEditorWidget *ClangCompletionAssistInterface::textEditorWidget() const
|
||||
{
|
||||
return m_textEditorWidget;
|
||||
}
|
||||
|
||||
IpcCommunicator &ClangCompletionAssistInterface::ipcCommunicator() const
|
||||
{
|
||||
return m_ipcCommunicator;
|
||||
}
|
||||
|
||||
const UnsavedFiles &ClangCompletionAssistInterface::unsavedFiles() const
|
||||
{
|
||||
return m_unsavedFiles;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
|
79
src/plugins/clangcodemodel/clangcompletionassistinterface.h
Normal file
79
src/plugins/clangcodemodel/clangcompletionassistinterface.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CLANGCODEMODEL_INTERNAL_CLANGCOMPLETIONASSISTINTERFACE_H
|
||||
#define CLANGCODEMODEL_INTERNAL_CLANGCOMPLETIONASSISTINTERFACE_H
|
||||
|
||||
#include "clangbackendipcintegration.h"
|
||||
#include "pchinfo.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <cpptools/cppcompletionassistprovider.h>
|
||||
|
||||
#include <texteditor/codeassist/assistinterface.h>
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
class ClangCompletionAssistInterface: public TextEditor::AssistInterface
|
||||
{
|
||||
public:
|
||||
ClangCompletionAssistInterface(IpcCommunicator &ipcCommunicator,
|
||||
const TextEditor::TextEditorWidget *textEditorWidget,
|
||||
int position,
|
||||
const QString &fileName,
|
||||
TextEditor::AssistReason reason,
|
||||
const CppTools::ProjectPart::HeaderPaths &headerPaths,
|
||||
const PchInfo::Ptr &pchInfo,
|
||||
const CPlusPlus::LanguageFeatures &features);
|
||||
|
||||
IpcCommunicator &ipcCommunicator() const;
|
||||
const UnsavedFiles &unsavedFiles() const;
|
||||
bool objcEnabled() const;
|
||||
const CppTools::ProjectPart::HeaderPaths &headerPaths() const;
|
||||
CPlusPlus::LanguageFeatures languageFeatures() const;
|
||||
const TextEditor::TextEditorWidget *textEditorWidget() const;
|
||||
|
||||
void setHeaderPaths(const CppTools::ProjectPart::HeaderPaths &headerPaths); // For tests
|
||||
|
||||
private:
|
||||
IpcCommunicator &m_ipcCommunicator;
|
||||
UnsavedFiles m_unsavedFiles;
|
||||
QStringList m_options;
|
||||
CppTools::ProjectPart::HeaderPaths m_headerPaths;
|
||||
Internal::PchInfo::Ptr m_savedPchPointer;
|
||||
CPlusPlus::LanguageFeatures m_languageFeatures;
|
||||
const TextEditor::TextEditorWidget *m_textEditorWidget;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
|
||||
#endif // CLANGCODEMODEL_INTERNAL_CLANGCOMPLETIONASSISTINTERFACE_H
|
@@ -28,133 +28,44 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "clangcompletion.h"
|
||||
#include "clangcompletioncontextanalyzer.h"
|
||||
#include "clangutils.h"
|
||||
#include "completionchunkstotextconverter.h"
|
||||
#include "pchmanager.h"
|
||||
#include "clangassistproposalitem.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/idocument.h>
|
||||
#include "activationsequenceprocessor.h"
|
||||
#include "clangassistproposal.h"
|
||||
#include "clangassistproposalmodel.h"
|
||||
#include "clangcompletionassistprocessor.h"
|
||||
#include "clangcompletioncontextanalyzer.h"
|
||||
#include "clangfunctionhintmodel.h"
|
||||
#include "clangutils.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <texteditor/codeassist/assistproposalitem.h>
|
||||
#include <texteditor/codeassist/functionhintproposal.h>
|
||||
#include <texteditor/codeassist/ifunctionhintproposalmodel.h>
|
||||
#include <texteditor/convenience.h>
|
||||
|
||||
#include <cpptools/cppdoxygen.h>
|
||||
|
||||
#include <cplusplus/BackwardsScanner.h>
|
||||
#include <cplusplus/ExpressionUnderCursor.h>
|
||||
#include <cplusplus/Token.h>
|
||||
#include <cplusplus/MatchingText.h>
|
||||
#include <cplusplus/SimpleLexer.h>
|
||||
|
||||
#include <cppeditor/cppeditorconstants.h>
|
||||
|
||||
#include <cpptools/baseeditordocumentparser.h>
|
||||
#include <cpptools/cppdoxygen.h>
|
||||
#include <cpptools/cppmodelmanager.h>
|
||||
#include <cpptools/cppworkingcopy.h>
|
||||
|
||||
#include <texteditor/texteditor.h>
|
||||
#include <texteditor/convenience.h>
|
||||
#include <texteditor/codeassist/genericproposalmodel.h>
|
||||
#include <texteditor/codeassist/assistproposalitem.h>
|
||||
#include <texteditor/codeassist/functionhintproposal.h>
|
||||
#include <texteditor/codeassist/genericproposal.h>
|
||||
#include <texteditor/texteditorsettings.h>
|
||||
#include <texteditor/completionsettings.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/mimetypes/mimedatabase.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDirIterator>
|
||||
#include <QLoggingCategory>
|
||||
#include <QTextCursor>
|
||||
#include <QTextDocument>
|
||||
#include <QTextBlock>
|
||||
#include <filecontainer.h>
|
||||
|
||||
using namespace ClangBackEnd;
|
||||
using namespace ClangCodeModel;
|
||||
using namespace ClangCodeModel::Internal;
|
||||
using namespace CPlusPlus;
|
||||
using namespace CppTools;
|
||||
using namespace TextEditor;
|
||||
#include <utils/mimetypes/mimedatabase.h>
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
using TextEditor::AssistProposalItem;
|
||||
|
||||
namespace {
|
||||
|
||||
const char SNIPPET_ICON_PATH[] = ":/texteditor/images/snippet.png";
|
||||
|
||||
int activationSequenceChar(const QChar &ch,
|
||||
const QChar &ch2,
|
||||
const QChar &ch3,
|
||||
unsigned *kind,
|
||||
bool wantFunctionCall)
|
||||
{
|
||||
int referencePosition = 0;
|
||||
int completionKind = T_EOF_SYMBOL;
|
||||
switch (ch.toLatin1()) {
|
||||
case '.':
|
||||
if (ch2 != QLatin1Char('.')) {
|
||||
completionKind = T_DOT;
|
||||
referencePosition = 1;
|
||||
}
|
||||
break;
|
||||
case ',':
|
||||
completionKind = T_COMMA;
|
||||
referencePosition = 1;
|
||||
break;
|
||||
case '(':
|
||||
if (wantFunctionCall) {
|
||||
completionKind = T_LPAREN;
|
||||
referencePosition = 1;
|
||||
}
|
||||
break;
|
||||
case ':':
|
||||
if (ch3 != QLatin1Char(':') && ch2 == QLatin1Char(':')) {
|
||||
completionKind = T_COLON_COLON;
|
||||
referencePosition = 2;
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
if (ch2 == QLatin1Char('-')) {
|
||||
completionKind = T_ARROW;
|
||||
referencePosition = 2;
|
||||
}
|
||||
break;
|
||||
case '*':
|
||||
if (ch2 == QLatin1Char('.')) {
|
||||
completionKind = T_DOT_STAR;
|
||||
referencePosition = 2;
|
||||
} else if (ch3 == QLatin1Char('-') && ch2 == QLatin1Char('>')) {
|
||||
completionKind = T_ARROW_STAR;
|
||||
referencePosition = 3;
|
||||
}
|
||||
break;
|
||||
case '\\':
|
||||
case '@':
|
||||
if (ch2.isNull() || ch2.isSpace()) {
|
||||
completionKind = T_DOXY_COMMENT;
|
||||
referencePosition = 1;
|
||||
}
|
||||
break;
|
||||
case '<':
|
||||
completionKind = T_ANGLE_STRING_LITERAL;
|
||||
referencePosition = 1;
|
||||
break;
|
||||
case '"':
|
||||
completionKind = T_STRING_LITERAL;
|
||||
referencePosition = 1;
|
||||
break;
|
||||
case '/':
|
||||
completionKind = T_SLASH;
|
||||
referencePosition = 1;
|
||||
break;
|
||||
case '#':
|
||||
completionKind = T_POUND;
|
||||
referencePosition = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (kind)
|
||||
*kind = completionKind;
|
||||
|
||||
return referencePosition;
|
||||
}
|
||||
|
||||
QList<AssistProposalItem *> toAssistProposalItems(const CodeCompletions &completions)
|
||||
{
|
||||
@@ -194,6 +105,9 @@ QList<AssistProposalItem *> toAssistProposalItems(const CodeCompletions &complet
|
||||
}
|
||||
|
||||
// FIXME: show the effective accessebility instead of availability
|
||||
using ClangBackEnd::CodeCompletion;
|
||||
using CPlusPlus::Icons;
|
||||
|
||||
switch (ccr.completionKind()) {
|
||||
case CodeCompletion::ClassCompletionKind:
|
||||
case CodeCompletion::TemplateClassCompletionKind:
|
||||
@@ -293,382 +207,8 @@ QVector<CodeCompletion> matchingFunctionCompletions(const QVector<CodeCompletion
|
||||
|
||||
} // Anonymous
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
// -----------------------------
|
||||
// ClangCompletionAssistProvider
|
||||
// -----------------------------
|
||||
ClangCompletionAssistProvider::ClangCompletionAssistProvider(IpcCommunicator &ipcCommunicator)
|
||||
: m_ipcCommunicator(ipcCommunicator)
|
||||
{
|
||||
}
|
||||
|
||||
IAssistProvider::RunType ClangCompletionAssistProvider::runType() const
|
||||
{
|
||||
return Asynchronous;
|
||||
}
|
||||
|
||||
IAssistProcessor *ClangCompletionAssistProvider::createProcessor() const
|
||||
{
|
||||
return new ClangCompletionAssistProcessor;
|
||||
}
|
||||
|
||||
AssistInterface *ClangCompletionAssistProvider::createAssistInterface(
|
||||
const QString &filePath,
|
||||
const TextEditorWidget *textEditorWidget,
|
||||
const LanguageFeatures &languageFeatures,
|
||||
int position,
|
||||
AssistReason reason) const
|
||||
{
|
||||
Q_UNUSED(languageFeatures);
|
||||
const ProjectPart::Ptr part = Utils::projectPartForFile(filePath);
|
||||
QTC_ASSERT(!part.isNull(), return 0);
|
||||
|
||||
const PchInfo::Ptr pchInfo = PchManager::instance()->pchInfo(part);
|
||||
return new ClangCompletionAssistInterface(m_ipcCommunicator,
|
||||
textEditorWidget,
|
||||
position,
|
||||
filePath,
|
||||
reason,
|
||||
part->headerPaths,
|
||||
pchInfo,
|
||||
part->languageFeatures);
|
||||
}
|
||||
|
||||
// ------------------------
|
||||
// ClangAssistProposalModel
|
||||
// ------------------------
|
||||
class ClangAssistProposalModel : public GenericProposalModel
|
||||
{
|
||||
public:
|
||||
ClangAssistProposalModel()
|
||||
: m_sortable(false)
|
||||
, m_completionOperator(T_EOF_SYMBOL)
|
||||
, m_replaceDotForArrow(false)
|
||||
{}
|
||||
|
||||
virtual bool isSortable(const QString &prefix) const;
|
||||
bool m_sortable;
|
||||
unsigned m_completionOperator;
|
||||
bool m_replaceDotForArrow;
|
||||
};
|
||||
|
||||
// -------------------
|
||||
// ClangAssistProposal
|
||||
// -------------------
|
||||
class ClangAssistProposal : public GenericProposal
|
||||
{
|
||||
public:
|
||||
ClangAssistProposal(int cursorPos, GenericProposalModel *model)
|
||||
: GenericProposal(cursorPos, model)
|
||||
, m_replaceDotForArrow(static_cast<ClangAssistProposalModel *>(model)->m_replaceDotForArrow)
|
||||
{}
|
||||
|
||||
virtual bool isCorrective() const { return m_replaceDotForArrow; }
|
||||
virtual void makeCorrection(TextEditorWidget *editorWidget)
|
||||
{
|
||||
editorWidget->setCursorPosition(basePosition() - 1);
|
||||
editorWidget->replace(1, QLatin1String("->"));
|
||||
moveBasePosition(1);
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_replaceDotForArrow;
|
||||
};
|
||||
|
||||
// ----------------------
|
||||
// ClangFunctionHintModel
|
||||
// ----------------------
|
||||
|
||||
ClangFunctionHintModel::ClangFunctionHintModel(const CodeCompletions &functionSymbols)
|
||||
: m_functionSymbols(functionSymbols)
|
||||
, m_currentArg(-1)
|
||||
{}
|
||||
|
||||
QString ClangFunctionHintModel::text(int index) const
|
||||
{
|
||||
#if 0
|
||||
// TODO: add the boldening to the result
|
||||
Overview overview;
|
||||
overview.setShowReturnTypes(true);
|
||||
overview.setShowArgumentNames(true);
|
||||
overview.setMarkedArgument(m_currentArg + 1);
|
||||
Function *f = m_functionSymbols.at(index);
|
||||
|
||||
const QString prettyMethod = overview(f->type(), f->name());
|
||||
const int begin = overview.markedArgumentBegin();
|
||||
const int end = overview.markedArgumentEnd();
|
||||
|
||||
QString hintText;
|
||||
hintText += prettyMethod.left(begin).toHtmlEscaped());
|
||||
hintText += "<b>";
|
||||
hintText += prettyMethod.mid(begin, end - begin).toHtmlEscaped());
|
||||
hintText += "</b>";
|
||||
hintText += prettyMethod.mid(end).toHtmlEscaped());
|
||||
return hintText;
|
||||
#endif
|
||||
return CompletionChunksToTextConverter::convert(m_functionSymbols.at(index).chunks());
|
||||
}
|
||||
|
||||
int ClangFunctionHintModel::activeArgument(const QString &prefix) const
|
||||
{
|
||||
int argnr = 0;
|
||||
int parcount = 0;
|
||||
SimpleLexer tokenize;
|
||||
Tokens tokens = tokenize(prefix);
|
||||
for (int i = 0; i < tokens.count(); ++i) {
|
||||
const Token &tk = tokens.at(i);
|
||||
if (tk.is(T_LPAREN))
|
||||
++parcount;
|
||||
else if (tk.is(T_RPAREN))
|
||||
--parcount;
|
||||
else if (! parcount && tk.is(T_COMMA))
|
||||
++argnr;
|
||||
}
|
||||
|
||||
if (parcount < 0)
|
||||
return -1;
|
||||
|
||||
if (argnr != m_currentArg)
|
||||
m_currentArg = argnr;
|
||||
|
||||
return argnr;
|
||||
}
|
||||
|
||||
/// @return True, because clang always returns priorities for sorting
|
||||
bool ClangAssistProposalModel::isSortable(const QString &prefix) const
|
||||
{
|
||||
Q_UNUSED(prefix)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClangAssistProposalItem::prematurelyApplies(const QChar &typedChar) const
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT)
|
||||
ok = QString::fromLatin1("(,").contains(typedChar);
|
||||
else if (m_completionOperator == T_STRING_LITERAL || m_completionOperator == T_ANGLE_STRING_LITERAL)
|
||||
ok = (typedChar == QLatin1Char('/')) && text().endsWith(QLatin1Char('/'));
|
||||
else if (!isCodeCompletion())
|
||||
ok = (typedChar == QLatin1Char('(')); /* && data().canConvert<CompleteFunctionDeclaration>()*/ //###
|
||||
else if (originalItem().completionKind() == CodeCompletion::ObjCMessageCompletionKind)
|
||||
ok = QString::fromLatin1(";.,").contains(typedChar);
|
||||
else
|
||||
ok = QString::fromLatin1(";.,:(").contains(typedChar);
|
||||
|
||||
if (ok)
|
||||
m_typedChar = typedChar;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void ClangAssistProposalItem::applyContextualContent(TextEditorWidget *editorWidget,
|
||||
int basePosition) const
|
||||
{
|
||||
const CodeCompletion ccr = originalItem();
|
||||
|
||||
QString toInsert = text();
|
||||
QString extraChars;
|
||||
int extraLength = 0;
|
||||
int cursorOffset = 0;
|
||||
|
||||
bool autoParenthesesEnabled = true;
|
||||
if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
|
||||
extraChars += QLatin1Char(')');
|
||||
if (m_typedChar == QLatin1Char('(')) // Eat the opening parenthesis
|
||||
m_typedChar = QChar();
|
||||
} else if (m_completionOperator == T_STRING_LITERAL || m_completionOperator == T_ANGLE_STRING_LITERAL) {
|
||||
if (!toInsert.endsWith(QLatin1Char('/'))) {
|
||||
extraChars += QLatin1Char((m_completionOperator == T_ANGLE_STRING_LITERAL) ? '>' : '"');
|
||||
} else {
|
||||
if (m_typedChar == QLatin1Char('/')) // Eat the slash
|
||||
m_typedChar = QChar();
|
||||
}
|
||||
} else if (!ccr.text().isEmpty()) {
|
||||
const CompletionSettings &completionSettings =
|
||||
TextEditorSettings::instance()->completionSettings();
|
||||
const bool autoInsertBrackets = completionSettings.m_autoInsertBrackets;
|
||||
|
||||
if (autoInsertBrackets &&
|
||||
(ccr.completionKind() == CodeCompletion::FunctionCompletionKind
|
||||
|| ccr.completionKind() == CodeCompletion::DestructorCompletionKind
|
||||
|| ccr.completionKind() == CodeCompletion::SignalCompletionKind
|
||||
|| ccr.completionKind() == CodeCompletion::SlotCompletionKind)) {
|
||||
// When the user typed the opening parenthesis, he'll likely also type the closing one,
|
||||
// in which case it would be annoying if we put the cursor after the already automatically
|
||||
// inserted closing parenthesis.
|
||||
const bool skipClosingParenthesis = m_typedChar != QLatin1Char('(');
|
||||
|
||||
if (completionSettings.m_spaceAfterFunctionName)
|
||||
extraChars += QLatin1Char(' ');
|
||||
extraChars += QLatin1Char('(');
|
||||
if (m_typedChar == QLatin1Char('('))
|
||||
m_typedChar = QChar();
|
||||
|
||||
// If the function doesn't return anything, automatically place the semicolon,
|
||||
// unless we're doing a scope completion (then it might be function definition).
|
||||
const QChar characterAtCursor = editorWidget->characterAt(editorWidget->position());
|
||||
bool endWithSemicolon = m_typedChar == QLatin1Char(';')/*
|
||||
|| (function->returnType()->isVoidType() && m_completionOperator != T_COLON_COLON)*/; //###
|
||||
const QChar semicolon = m_typedChar.isNull() ? QLatin1Char(';') : m_typedChar;
|
||||
|
||||
if (endWithSemicolon && characterAtCursor == semicolon) {
|
||||
endWithSemicolon = false;
|
||||
m_typedChar = QChar();
|
||||
}
|
||||
|
||||
// If the function takes no arguments, automatically place the closing parenthesis
|
||||
if (!isOverloaded() && !ccr.hasParameters() && skipClosingParenthesis) {
|
||||
extraChars += QLatin1Char(')');
|
||||
if (endWithSemicolon) {
|
||||
extraChars += semicolon;
|
||||
m_typedChar = QChar();
|
||||
}
|
||||
} else if (autoParenthesesEnabled) {
|
||||
const QChar lookAhead = editorWidget->characterAt(editorWidget->position() + 1);
|
||||
if (MatchingText::shouldInsertMatchingText(lookAhead)) {
|
||||
extraChars += QLatin1Char(')');
|
||||
--cursorOffset;
|
||||
if (endWithSemicolon) {
|
||||
extraChars += semicolon;
|
||||
--cursorOffset;
|
||||
m_typedChar = QChar();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (autoInsertBrackets && data().canConvert<CompleteFunctionDeclaration>()) {
|
||||
if (m_typedChar == QLatin1Char('('))
|
||||
m_typedChar = QChar();
|
||||
|
||||
// everything from the closing parenthesis on are extra chars, to
|
||||
// make sure an auto-inserted ")" gets replaced by ") const" if necessary
|
||||
int closingParen = toInsert.lastIndexOf(QLatin1Char(')'));
|
||||
extraChars = toInsert.mid(closingParen);
|
||||
toInsert.truncate(closingParen);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Append an unhandled typed character, adjusting cursor offset when it had been adjusted before
|
||||
if (!m_typedChar.isNull()) {
|
||||
extraChars += m_typedChar;
|
||||
if (cursorOffset != 0)
|
||||
--cursorOffset;
|
||||
}
|
||||
|
||||
// Avoid inserting characters that are already there
|
||||
const int endsPosition = editorWidget->position(EndOfLinePosition);
|
||||
const QString existingText = editorWidget->textAt(editorWidget->position(), endsPosition - editorWidget->position());
|
||||
int existLength = 0;
|
||||
if (!existingText.isEmpty()) {
|
||||
// Calculate the exist length in front of the extra chars
|
||||
existLength = toInsert.length() - (editorWidget->position() - basePosition);
|
||||
while (!existingText.startsWith(toInsert.right(existLength))) {
|
||||
if (--existLength == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < extraChars.length(); ++i) {
|
||||
const QChar a = extraChars.at(i);
|
||||
const QChar b = editorWidget->characterAt(editorWidget->position() + i + existLength);
|
||||
if (a == b)
|
||||
++extraLength;
|
||||
else
|
||||
break;
|
||||
}
|
||||
toInsert += extraChars;
|
||||
|
||||
// Insert the remainder of the name
|
||||
const int length = editorWidget->position() - basePosition + existLength + extraLength;
|
||||
editorWidget->setCursorPosition(basePosition);
|
||||
editorWidget->replace(length, toInsert);
|
||||
if (cursorOffset)
|
||||
editorWidget->setCursorPosition(editorWidget->position() + cursorOffset);
|
||||
}
|
||||
|
||||
bool ClangAssistProposalItem::isOverloaded() const
|
||||
{
|
||||
return !m_overloads.isEmpty();
|
||||
}
|
||||
|
||||
void ClangAssistProposalItem::addOverload(const CodeCompletion &ccr)
|
||||
{
|
||||
m_overloads.append(ccr);
|
||||
}
|
||||
|
||||
CodeCompletion ClangAssistProposalItem::originalItem() const
|
||||
{
|
||||
const QVariant &value = data();
|
||||
if (value.canConvert<CodeCompletion>())
|
||||
return value.value<CodeCompletion>();
|
||||
else
|
||||
return CodeCompletion();
|
||||
}
|
||||
|
||||
bool ClangAssistProposalItem::isCodeCompletion() const
|
||||
{
|
||||
return data().canConvert<CodeCompletion>();
|
||||
}
|
||||
|
||||
bool ClangCompletionAssistInterface::objcEnabled() const
|
||||
{
|
||||
return true; // TODO:
|
||||
}
|
||||
|
||||
const ProjectPart::HeaderPaths &ClangCompletionAssistInterface::headerPaths() const
|
||||
{
|
||||
return m_headerPaths;
|
||||
}
|
||||
|
||||
LanguageFeatures ClangCompletionAssistInterface::languageFeatures() const
|
||||
{
|
||||
return m_languageFeatures;
|
||||
}
|
||||
|
||||
void ClangCompletionAssistInterface::setHeaderPaths(const ProjectPart::HeaderPaths &headerPaths)
|
||||
{
|
||||
m_headerPaths = headerPaths;
|
||||
}
|
||||
|
||||
const TextEditor::TextEditorWidget *ClangCompletionAssistInterface::textEditorWidget() const
|
||||
{
|
||||
return m_textEditorWidget;
|
||||
}
|
||||
|
||||
ClangCompletionAssistInterface::ClangCompletionAssistInterface(
|
||||
IpcCommunicator &ipcCommunicator,
|
||||
const TextEditorWidget *textEditorWidget,
|
||||
int position,
|
||||
const QString &fileName,
|
||||
AssistReason reason,
|
||||
const ProjectPart::HeaderPaths &headerPaths,
|
||||
const PchInfo::Ptr &pchInfo,
|
||||
const LanguageFeatures &features)
|
||||
: AssistInterface(textEditorWidget->document(), position, fileName, reason)
|
||||
, m_ipcCommunicator(ipcCommunicator)
|
||||
, m_headerPaths(headerPaths)
|
||||
, m_savedPchPointer(pchInfo)
|
||||
, m_languageFeatures(features)
|
||||
, m_textEditorWidget(textEditorWidget)
|
||||
{
|
||||
CppModelManager *mmi = CppModelManager::instance();
|
||||
m_unsavedFiles = Utils::createUnsavedFiles(mmi->workingCopy());
|
||||
}
|
||||
|
||||
IpcCommunicator &ClangCompletionAssistInterface::ipcCommunicator() const
|
||||
{
|
||||
return m_ipcCommunicator;
|
||||
}
|
||||
|
||||
const UnsavedFiles &ClangCompletionAssistInterface::unsavedFiles() const
|
||||
{
|
||||
return m_unsavedFiles;
|
||||
}
|
||||
using namespace CPlusPlus;
|
||||
using namespace TextEditor;
|
||||
|
||||
ClangCompletionAssistProcessor::ClangCompletionAssistProcessor()
|
||||
: m_completionOperator(T_EOF_SYMBOL)
|
||||
@@ -806,18 +346,21 @@ IAssistProposal *ClangCompletionAssistProcessor::startCompletionHelper()
|
||||
}
|
||||
|
||||
// TODO: Extract duplicated logic from InternalCppCompletionAssistProcessor::startOfOperator
|
||||
int ClangCompletionAssistProcessor::startOfOperator(int pos,
|
||||
int ClangCompletionAssistProcessor::startOfOperator(int positionInDocument,
|
||||
unsigned *kind,
|
||||
bool wantFunctionCall) const
|
||||
{
|
||||
const QChar ch = pos > -1 ? m_interface->characterAt(pos - 1) : QChar();
|
||||
const QChar ch2 = pos > 0 ? m_interface->characterAt(pos - 2) : QChar();
|
||||
const QChar ch3 = pos > 1 ? m_interface->characterAt(pos - 3) : QChar();
|
||||
auto activationSequence = m_interface->textAt(positionInDocument - 3, 3);
|
||||
ActivationSequenceProcessor activationSequenceProcessor(activationSequence,
|
||||
positionInDocument,
|
||||
wantFunctionCall);
|
||||
|
||||
int start = pos - activationSequenceChar(ch, ch2, ch3, kind, wantFunctionCall);
|
||||
if (start != pos) {
|
||||
*kind = activationSequenceProcessor.completionKind();
|
||||
|
||||
int start = activationSequenceProcessor.position();
|
||||
if (start != positionInDocument) {
|
||||
QTextCursor tc(m_interface->textDocument());
|
||||
tc.setPosition(pos);
|
||||
tc.setPosition(positionInDocument);
|
||||
|
||||
// Include completion: make sure the quote character is the first one on the line
|
||||
if (*kind == T_STRING_LITERAL) {
|
||||
@@ -826,7 +369,7 @@ int ClangCompletionAssistProcessor::startOfOperator(int pos,
|
||||
QString sel = s.selectedText();
|
||||
if (sel.indexOf(QLatin1Char('"')) < sel.length() - 1) {
|
||||
*kind = T_EOF_SYMBOL;
|
||||
start = pos;
|
||||
start = positionInDocument;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -834,7 +377,7 @@ int ClangCompletionAssistProcessor::startOfOperator(int pos,
|
||||
ExpressionUnderCursor expressionUnderCursor(m_interface->languageFeatures());
|
||||
if (expressionUnderCursor.startOfFunctionCall(tc) == -1) {
|
||||
*kind = T_EOF_SYMBOL;
|
||||
start = pos;
|
||||
start = positionInDocument;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -847,7 +390,7 @@ int ClangCompletionAssistProcessor::startOfOperator(int pos,
|
||||
|
||||
if (*kind == T_DOXY_COMMENT && !(tk.is(T_DOXY_COMMENT) || tk.is(T_CPP_DOXY_COMMENT))) {
|
||||
*kind = T_EOF_SYMBOL;
|
||||
start = pos;
|
||||
start = positionInDocument;
|
||||
}
|
||||
// Don't complete in comments or strings, but still check for include completion
|
||||
else if (tk.is(T_COMMENT) || tk.is(T_CPP_COMMENT)
|
||||
@@ -856,12 +399,12 @@ int ClangCompletionAssistProcessor::startOfOperator(int pos,
|
||||
&& *kind != T_ANGLE_STRING_LITERAL
|
||||
&& *kind != T_SLASH))) {
|
||||
*kind = T_EOF_SYMBOL;
|
||||
start = pos;
|
||||
start = positionInDocument;
|
||||
}
|
||||
// Include completion: can be triggered by slash, but only in a string
|
||||
else if (*kind == T_SLASH && (tk.isNot(T_STRING_LITERAL) && tk.isNot(T_ANGLE_STRING_LITERAL))) {
|
||||
*kind = T_EOF_SYMBOL;
|
||||
start = pos;
|
||||
start = positionInDocument;
|
||||
}
|
||||
else if (*kind == T_LPAREN) {
|
||||
if (tokenIdx > 0) {
|
||||
@@ -876,7 +419,7 @@ int ClangCompletionAssistProcessor::startOfOperator(int pos,
|
||||
default:
|
||||
// that's a bad token :)
|
||||
*kind = T_EOF_SYMBOL;
|
||||
start = pos;
|
||||
start = positionInDocument;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -899,7 +442,7 @@ int ClangCompletionAssistProcessor::startOfOperator(int pos,
|
||||
|
||||
if (!include) {
|
||||
*kind = T_EOF_SYMBOL;
|
||||
start = pos;
|
||||
start = positionInDocument;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1006,9 +549,9 @@ bool ClangCompletionAssistProcessor::completeInclude(const QTextCursor &cursor)
|
||||
}
|
||||
|
||||
// Make completion for all relevant includes
|
||||
ProjectPart::HeaderPaths headerPaths = m_interface->headerPaths();
|
||||
const ProjectPart::HeaderPath currentFilePath(QFileInfo(m_interface->fileName()).path(),
|
||||
ProjectPart::HeaderPath::IncludePath);
|
||||
CppTools::ProjectPart::HeaderPaths headerPaths = m_interface->headerPaths();
|
||||
const CppTools::ProjectPart::HeaderPath currentFilePath(QFileInfo(m_interface->fileName()).path(),
|
||||
CppTools::ProjectPart::HeaderPath::IncludePath);
|
||||
if (!headerPaths.contains(currentFilePath))
|
||||
headerPaths.append(currentFilePath);
|
||||
|
||||
@@ -1016,7 +559,7 @@ bool ClangCompletionAssistProcessor::completeInclude(const QTextCursor &cursor)
|
||||
const ::Utils::MimeType mimeType = mdb.mimeTypeForName(QLatin1String("text/x-c++hdr"));
|
||||
const QStringList suffixes = mimeType.suffixes();
|
||||
|
||||
foreach (const ProjectPart::HeaderPath &headerPath, headerPaths) {
|
||||
foreach (const CppTools::ProjectPart::HeaderPath &headerPath, headerPaths) {
|
||||
QString realPath = headerPath.path;
|
||||
if (!directoryPrefix.isEmpty()) {
|
||||
realPath += QLatin1Char('/');
|
||||
@@ -1082,8 +625,8 @@ bool ClangCompletionAssistProcessor::completePreprocessorDirectives()
|
||||
|
||||
bool ClangCompletionAssistProcessor::completeDoxygenKeywords()
|
||||
{
|
||||
for (int i = 1; i < T_DOXY_LAST_TAG; ++i)
|
||||
addCompletionItem(QString::fromLatin1(doxygenTagSpell(i)), m_icons.keywordIcon());
|
||||
for (int i = 1; i < CppTools::T_DOXY_LAST_TAG; ++i)
|
||||
addCompletionItem(QString::fromLatin1(CppTools::doxygenTagSpell(i)), m_icons.keywordIcon());
|
||||
return !m_completions.isEmpty();
|
||||
}
|
||||
|
||||
@@ -1112,7 +655,7 @@ void ClangCompletionAssistProcessor::sendFileContent(const QString &projectFileP
|
||||
|
||||
IpcCommunicator &ipcCommunicator = m_interface->ipcCommunicator();
|
||||
ipcCommunicator.registerFilesForCodeCompletion(
|
||||
{FileContainer(filePath,
|
||||
{ClangBackEnd::FileContainer(filePath,
|
||||
projectFilePath,
|
||||
Utf8String::fromByteArray(unsavedContent),
|
||||
hasUnsavedContent)});
|
||||
@@ -1122,7 +665,7 @@ void ClangCompletionAssistProcessor::sendCompletionRequest(int position,
|
||||
const QByteArray &modifiedFileContent)
|
||||
{
|
||||
int line, column;
|
||||
Convenience::convertPosition(m_interface->textDocument(), position, &line, &column);
|
||||
TextEditor::Convenience::convertPosition(m_interface->textDocument(), position, &line, &column);
|
||||
++column;
|
||||
|
||||
const QString filePath = m_interface->fileName();
|
||||
@@ -1156,8 +699,8 @@ void ClangCompletionAssistProcessor::onFunctionHintCompletionsAvailable(
|
||||
const auto relevantCompletions = matchingFunctionCompletions(completions, m_functionName);
|
||||
|
||||
if (!relevantCompletions.isEmpty()) {
|
||||
IFunctionHintProposalModel *model = new ClangFunctionHintModel(relevantCompletions);
|
||||
FunctionHintProposal *proposal = new FunctionHintProposal(m_positionForProposal, model);
|
||||
TextEditor::IFunctionHintProposalModel *model = new ClangFunctionHintModel(relevantCompletions);
|
||||
TextEditor::FunctionHintProposal *proposal = new FunctionHintProposal(m_positionForProposal, model);
|
||||
|
||||
setAsyncProposalAvailable(proposal);
|
||||
} else {
|
||||
@@ -1168,3 +711,4 @@ void ClangCompletionAssistProcessor::onFunctionHintCompletionsAvailable(
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
|
101
src/plugins/clangcodemodel/clangcompletionassistprocessor.h
Normal file
101
src/plugins/clangcodemodel/clangcompletionassistprocessor.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CLANGCODEMODEL_INTERNAL_CLANGCOMPLETIONASSISTPROCESSOR_H
|
||||
#define CLANGCODEMODEL_INTERNAL_CLANGCOMPLETIONASSISTPROCESSOR_H
|
||||
|
||||
#include "clangcompletionassistinterface.h"
|
||||
|
||||
#include <cpptools/cppcompletionassistprocessor.h>
|
||||
|
||||
#include <texteditor/texteditor.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
class CodeCompletion;
|
||||
}
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
using CodeCompletions = QVector<ClangBackEnd::CodeCompletion>;
|
||||
using ClangBackEnd::CodeCompletion;
|
||||
|
||||
class ClangCompletionAssistProcessor : public CppTools::CppCompletionAssistProcessor
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(ClangCodeModel::Internal::ClangCompletionAssistProcessor)
|
||||
|
||||
public:
|
||||
ClangCompletionAssistProcessor();
|
||||
~ClangCompletionAssistProcessor();
|
||||
|
||||
TextEditor::IAssistProposal *perform(const TextEditor::AssistInterface *interface) override;
|
||||
|
||||
void asyncCompletionsAvailable(const CodeCompletions &completions);
|
||||
|
||||
const TextEditor::TextEditorWidget *textEditorWidget() const;
|
||||
|
||||
private:
|
||||
TextEditor::IAssistProposal *startCompletionHelper();
|
||||
int startOfOperator(int pos, unsigned *kind, bool wantFunctionCall) const;
|
||||
int findStartOfName(int pos = -1) const;
|
||||
bool accepts() const;
|
||||
|
||||
TextEditor::IAssistProposal *createProposal() const;
|
||||
|
||||
bool completeInclude(const QTextCursor &cursor);
|
||||
bool completeInclude(int position);
|
||||
void completeIncludePath(const QString &realPath, const QStringList &suffixes);
|
||||
bool completePreprocessorDirectives();
|
||||
bool completeDoxygenKeywords();
|
||||
void addCompletionItem(const QString &text,
|
||||
const QIcon &icon = QIcon(),
|
||||
int order = 0,
|
||||
const QVariant &data = QVariant());
|
||||
|
||||
void sendFileContent(const QString &projectFilePath, const QByteArray &modifiedFileContent);
|
||||
void sendCompletionRequest(int position, const QByteArray &modifiedFileContent);
|
||||
|
||||
void onCompletionsAvailable(const CodeCompletions &completions);
|
||||
void onFunctionHintCompletionsAvailable(const CodeCompletions &completions);
|
||||
|
||||
private:
|
||||
QScopedPointer<const ClangCompletionAssistInterface> m_interface;
|
||||
unsigned m_completionOperator;
|
||||
enum CompletionRequestType { NormalCompletion, FunctionHintCompletion } m_sentRequestType;
|
||||
QString m_functionName; // For type == Type::FunctionHintCompletion
|
||||
bool m_addSnippets = false; // For type == Type::NormalCompletion
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
|
||||
#endif // CLANGCODEMODEL_INTERNAL_CLANGCOMPLETIONASSISTPROCESSOR_H
|
88
src/plugins/clangcodemodel/clangcompletionassistprovider.cpp
Normal file
88
src/plugins/clangcodemodel/clangcompletionassistprovider.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "clangcompletionassistprovider.h"
|
||||
|
||||
#include "clangcompletionassistprocessor.h"
|
||||
#include "clangutils.h"
|
||||
#include "pchmanager.h"
|
||||
|
||||
#include <cplusplus/Token.h>
|
||||
#include <cpptools/cppcompletionassistprocessor.h>
|
||||
#include <cpptools/cppprojects.h>
|
||||
|
||||
#include <texteditor/codeassist/assistinterface.h>
|
||||
#include <texteditor/codeassist/iassistprocessor.h>
|
||||
#include <texteditor/codeassist/iassistprovider.h>
|
||||
#include <texteditor/texteditor.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
ClangCompletionAssistProvider::ClangCompletionAssistProvider(IpcCommunicator &ipcCommunicator)
|
||||
: m_ipcCommunicator(ipcCommunicator)
|
||||
{
|
||||
}
|
||||
|
||||
TextEditor::IAssistProvider::RunType ClangCompletionAssistProvider::runType() const
|
||||
{
|
||||
return Asynchronous;
|
||||
}
|
||||
|
||||
TextEditor::IAssistProcessor *ClangCompletionAssistProvider::createProcessor() const
|
||||
{
|
||||
return new ClangCompletionAssistProcessor;
|
||||
}
|
||||
|
||||
TextEditor::AssistInterface *ClangCompletionAssistProvider::createAssistInterface(
|
||||
const QString &filePath,
|
||||
const TextEditor::TextEditorWidget *textEditorWidget,
|
||||
const CPlusPlus::LanguageFeatures &/*languageFeatures*/,
|
||||
int position,
|
||||
TextEditor::AssistReason reason) const
|
||||
{
|
||||
const CppTools::ProjectPart::Ptr projectPart = Utils::projectPartForFile(filePath);
|
||||
QTC_ASSERT(!projectPart.isNull(), return 0);
|
||||
|
||||
const PchInfo::Ptr pchInfo = PchManager::instance()->pchInfo(projectPart);
|
||||
return new ClangCompletionAssistInterface(m_ipcCommunicator,
|
||||
textEditorWidget,
|
||||
position,
|
||||
filePath,
|
||||
reason,
|
||||
projectPart->headerPaths,
|
||||
pchInfo,
|
||||
projectPart->languageFeatures);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
@@ -28,55 +28,40 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CLANGCODEMODEL_TESTS_COMPLETIONTESTHELPER_H
|
||||
#define CLANGCODEMODEL_TESTS_COMPLETIONTESTHELPER_H
|
||||
#ifndef CLANGCODEMODEL_INTERNAL_CLANGCOMPLETIONASSISTPROVIDER_H
|
||||
#define CLANGCODEMODEL_INTERNAL_CLANGCOMPLETIONASSISTPROVIDER_H
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
#include "clangbackendipcintegration.h"
|
||||
|
||||
#include "../clangcompleter.h"
|
||||
#include <cpptools/cppcompletionassistprovider.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QTextDocument>
|
||||
#include <texteditor/texteditor.h>
|
||||
#include <cplusplus/CppDocument.h>
|
||||
|
||||
namespace TextEditor { class IAssistProposal; }
|
||||
#include <texteditor/codeassist/assistinterface.h>
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
class CompletionTestHelper : public QObject
|
||||
class ClangCompletionAssistProvider : public CppTools::CppCompletionAssistProvider
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CompletionTestHelper(QObject *parent = 0);
|
||||
~CompletionTestHelper();
|
||||
ClangCompletionAssistProvider(IpcCommunicator &ipcCommunicator);
|
||||
|
||||
void operator <<(const QString &fileName);
|
||||
QStringList codeCompleteTexts();
|
||||
QList<CodeCompletionResult> codeComplete();
|
||||
IAssistProvider::RunType runType() const override;
|
||||
|
||||
int position() const;
|
||||
const QByteArray &source() const;
|
||||
|
||||
void addOption(const QString &option);
|
||||
TextEditor::IAssistProcessor *createProcessor() const override;
|
||||
TextEditor::AssistInterface *createAssistInterface(
|
||||
const QString &filePath,
|
||||
const TextEditor::TextEditorWidget *textEditorWidget,
|
||||
const CPlusPlus::LanguageFeatures &languageFeatures,
|
||||
int position,
|
||||
TextEditor::AssistReason reason) const override;
|
||||
|
||||
private:
|
||||
void findCompletionPos();
|
||||
|
||||
UnsavedFiles m_unsavedFiles;
|
||||
ClangCompleter::Ptr m_completer;
|
||||
QStringList m_clangOptions;
|
||||
|
||||
QByteArray m_sourceCode;
|
||||
int m_position;
|
||||
int m_line;
|
||||
int m_column;
|
||||
IpcCommunicator &m_ipcCommunicator;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
|
||||
#endif
|
||||
|
||||
#endif // CLANGCODEMODEL_TESTS_COMPLETIONTESTHELPER_H
|
||||
#endif // CLANGCODEMODEL_INTERNAL_CLANGCOMPLETIONASSISTPROVIDER_H
|
109
src/plugins/clangcodemodel/clangfunctionhintmodel.cpp
Normal file
109
src/plugins/clangcodemodel/clangfunctionhintmodel.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "clangfunctionhintmodel.h"
|
||||
|
||||
#include "completionchunkstotextconverter.h"
|
||||
|
||||
#include <cplusplus/SimpleLexer.h>
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
using namespace CPlusPlus;
|
||||
|
||||
ClangFunctionHintModel::ClangFunctionHintModel(const CodeCompletions &functionSymbols)
|
||||
: m_functionSymbols(functionSymbols)
|
||||
, m_currentArg(-1)
|
||||
{
|
||||
}
|
||||
|
||||
void ClangFunctionHintModel::reset()
|
||||
{
|
||||
}
|
||||
|
||||
int ClangFunctionHintModel::size() const
|
||||
{
|
||||
return m_functionSymbols.size();
|
||||
}
|
||||
|
||||
QString ClangFunctionHintModel::text(int index) const
|
||||
{
|
||||
#if 0
|
||||
// TODO: add the boldening to the result
|
||||
Overview overview;
|
||||
overview.setShowReturnTypes(true);
|
||||
overview.setShowArgumentNames(true);
|
||||
overview.setMarkedArgument(m_currentArg + 1);
|
||||
Function *f = m_functionSymbols.at(index);
|
||||
|
||||
const QString prettyMethod = overview(f->type(), f->name());
|
||||
const int begin = overview.markedArgumentBegin();
|
||||
const int end = overview.markedArgumentEnd();
|
||||
|
||||
QString hintText;
|
||||
hintText += prettyMethod.left(begin).toHtmlEscaped());
|
||||
hintText += "<b>";
|
||||
hintText += prettyMethod.mid(begin, end - begin).toHtmlEscaped());
|
||||
hintText += "</b>";
|
||||
hintText += prettyMethod.mid(end).toHtmlEscaped());
|
||||
return hintText;
|
||||
#endif
|
||||
return CompletionChunksToTextConverter::convert(m_functionSymbols.at(index).chunks());
|
||||
}
|
||||
|
||||
int ClangFunctionHintModel::activeArgument(const QString &prefix) const
|
||||
{
|
||||
int argnr = 0;
|
||||
int parcount = 0;
|
||||
SimpleLexer tokenize;
|
||||
Tokens tokens = tokenize(prefix);
|
||||
for (int i = 0; i < tokens.count(); ++i) {
|
||||
const Token &tk = tokens.at(i);
|
||||
if (tk.is(T_LPAREN))
|
||||
++parcount;
|
||||
else if (tk.is(T_RPAREN))
|
||||
--parcount;
|
||||
else if (! parcount && tk.is(T_COMMA))
|
||||
++argnr;
|
||||
}
|
||||
|
||||
if (parcount < 0)
|
||||
return -1;
|
||||
|
||||
if (argnr != m_currentArg)
|
||||
m_currentArg = argnr;
|
||||
|
||||
return argnr;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
|
@@ -28,24 +28,34 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Expected: 'OwningPtr'
|
||||
*/
|
||||
#ifndef CLANGCODEMODEL_INTERNAL_CLANGFUNCTIONHINTMODEL_H
|
||||
#define CLANGCODEMODEL_INTERNAL_CLANGFUNCTIONHINTMODEL_H
|
||||
|
||||
namespace llvm {
|
||||
class OwningPtr;
|
||||
}
|
||||
#include <codecompletion.h>
|
||||
|
||||
namespace clang {
|
||||
using llvm::OwningPtr;
|
||||
}
|
||||
#include <texteditor/codeassist/ifunctionhintproposalmodel.h>
|
||||
|
||||
class llvm::OwningPtr
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
using CodeCompletions = QVector<ClangBackEnd::CodeCompletion>;
|
||||
|
||||
class ClangFunctionHintModel : public TextEditor::IFunctionHintProposalModel
|
||||
{
|
||||
public:
|
||||
ClangFunctionHintModel(const CodeCompletions &functionSymbols);
|
||||
|
||||
void reset() override;
|
||||
int size() const override;
|
||||
QString text(int index) const override;
|
||||
int activeArgument(const QString &prefix) const override;
|
||||
|
||||
private:
|
||||
CodeCompletions m_functionSymbols;
|
||||
mutable int m_currentArg;
|
||||
};
|
||||
|
||||
void foo()
|
||||
{
|
||||
clang::<<<< ptr;
|
||||
(void)ptr;
|
||||
}
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
|
||||
#endif // CLANGCODEMODEL_INTERNAL_CLANGFUNCTIONHINTMODEL_H
|
@@ -31,7 +31,6 @@
|
||||
#include "clangmodelmanagersupport.h"
|
||||
|
||||
#include "constants.h"
|
||||
#include "clangcompletion.h"
|
||||
#include "clangeditordocumentprocessor.h"
|
||||
#include "clangutils.h"
|
||||
|
||||
@@ -50,7 +49,7 @@
|
||||
using namespace ClangCodeModel;
|
||||
using namespace ClangCodeModel::Internal;
|
||||
|
||||
static ModelManagerSupportClang *m_instance = 0;
|
||||
static ModelManagerSupportClang *m_instance_forTestsOnly = 0;
|
||||
|
||||
static CppTools::CppModelManager *cppModelManager()
|
||||
{
|
||||
@@ -60,8 +59,8 @@ static CppTools::CppModelManager *cppModelManager()
|
||||
ModelManagerSupportClang::ModelManagerSupportClang()
|
||||
: m_completionAssistProvider(m_ipcCommunicator)
|
||||
{
|
||||
QTC_CHECK(!m_instance);
|
||||
m_instance = this;
|
||||
QTC_CHECK(!m_instance_forTestsOnly);
|
||||
m_instance_forTestsOnly = this;
|
||||
|
||||
Core::EditorManager *editorManager = Core::EditorManager::instance();
|
||||
connect(editorManager, &Core::EditorManager::currentEditorChanged,
|
||||
@@ -78,7 +77,7 @@ ModelManagerSupportClang::ModelManagerSupportClang()
|
||||
|
||||
ModelManagerSupportClang::~ModelManagerSupportClang()
|
||||
{
|
||||
m_instance = 0;
|
||||
m_instance_forTestsOnly = 0;
|
||||
}
|
||||
|
||||
CppTools::CppCompletionAssistProvider *ModelManagerSupportClang::completionAssistProvider()
|
||||
@@ -176,10 +175,12 @@ void ModelManagerSupportClang::onProjectPartsRemoved(const QStringList &projectF
|
||||
m_ipcCommunicator.unregisterProjectPartsForCodeCompletion(projectFiles);
|
||||
}
|
||||
|
||||
ModelManagerSupportClang *ModelManagerSupportClang::instance()
|
||||
#ifdef QT_TESTLIB_LIB
|
||||
ModelManagerSupportClang *ModelManagerSupportClang::instance_forTestsOnly()
|
||||
{
|
||||
return m_instance;
|
||||
return m_instance_forTestsOnly;
|
||||
}
|
||||
#endif
|
||||
|
||||
IpcCommunicator &ModelManagerSupportClang::ipcCommunicator()
|
||||
{
|
||||
|
@@ -31,7 +31,7 @@
|
||||
#ifndef CLANGCODEMODEL_INTERNAL_CLANGMODELMANAGERSUPPORT_H
|
||||
#define CLANGCODEMODEL_INTERNAL_CLANGMODELMANAGERSUPPORT_H
|
||||
|
||||
#include "clangcompletion.h"
|
||||
#include "clangcompletionassistprovider.h"
|
||||
|
||||
#include <cpptools/cppmodelmanagersupport.h>
|
||||
|
||||
@@ -48,7 +48,6 @@ class ModelManagerSupportClang:
|
||||
public CppTools::ModelManagerSupport
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(ModelManagerSupportClang)
|
||||
|
||||
public:
|
||||
ModelManagerSupportClang();
|
||||
@@ -60,8 +59,9 @@ public:
|
||||
|
||||
IpcCommunicator &ipcCommunicator();
|
||||
|
||||
public: // for tests
|
||||
static ModelManagerSupportClang *instance();
|
||||
#ifdef QT_TESTLIB_LIB
|
||||
static ModelManagerSupportClang *instance_forTestsOnly();
|
||||
#endif
|
||||
|
||||
private:
|
||||
void onEditorOpened(Core::IEditor *editor);
|
||||
|
@@ -1,750 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "completionproposalsbuilder.h"
|
||||
#include "utils_p.h"
|
||||
|
||||
#include <QTextDocument>
|
||||
#include <QCoreApplication>
|
||||
|
||||
enum PriorityFixes {
|
||||
PriorityFix_ExplicitDestructorCall = 10
|
||||
};
|
||||
|
||||
namespace ClangCodeModel {
|
||||
|
||||
namespace {
|
||||
struct ObjCMessagePart {
|
||||
QString text;
|
||||
int signatureLen; // length of "setScale:" in "setScale: 13"
|
||||
|
||||
ObjCMessagePart() : signatureLen(0) {}
|
||||
|
||||
ObjCMessagePart(const QString &signature, int &indentBonus)
|
||||
: text(signature)
|
||||
, signatureLen(signature.length() + indentBonus)
|
||||
{
|
||||
indentBonus = 0;
|
||||
}
|
||||
|
||||
void addToSignature(const QString &signature)
|
||||
{
|
||||
text += signature;
|
||||
signatureLen += signature.length();
|
||||
}
|
||||
};
|
||||
} // anonymous namespace
|
||||
|
||||
/**
|
||||
* @class ClangCodeModel::CompletionProposalsBuilder
|
||||
* @brief Captures completion lists and than processes sequence of completion chunks
|
||||
*
|
||||
* Can produce several completion proposals for one CXCompletionResult, if and
|
||||
* only if result contains chunks with kind 'Optional'
|
||||
* Different proposals can have the same text, it's normal behavior.
|
||||
*
|
||||
* @note Unit tests are in \a clangcompletion_test.cpp
|
||||
*
|
||||
* @note Unresolved problems:
|
||||
* Function hint not appear after space: "foo(1, ";
|
||||
* Slot can have optional arguments, that produces 2 slots.
|
||||
*
|
||||
*/
|
||||
|
||||
CompletionProposalsBuilder::CompletionProposalsBuilder(QList<CodeCompletionResult> &results, quint64 contexts, bool isSignalSlotCompletion)
|
||||
: m_results(results)
|
||||
, m_contexts(contexts)
|
||||
, m_isSignalSlotCompletion(isSignalSlotCompletion)
|
||||
{
|
||||
}
|
||||
|
||||
void CompletionProposalsBuilder::operator ()(const CXCompletionResult &cxResult)
|
||||
{
|
||||
resetWithResult(cxResult);
|
||||
|
||||
#if defined(CINDEX_VERSION) && (CINDEX_VERSION > 5)
|
||||
const QString brief = Internal::getQString(clang_getCompletionBriefComment(cxResult.CompletionString));
|
||||
if (!brief.isEmpty())
|
||||
m_comment += QString(QLatin1String("<b>Brief:</b> ") + brief).toHtmlEscaped();
|
||||
#endif
|
||||
|
||||
if (m_resultAvailability == CodeCompletionResult::Deprecated) {
|
||||
m_comment += QLatin1String("<b>@note</b> ");
|
||||
//: deprecated C++ symbol
|
||||
m_comment += tr("Is deprecated");
|
||||
}
|
||||
|
||||
m_hint = QLatin1String("<p>");
|
||||
switch (m_resultKind) {
|
||||
case CodeCompletionResult::ObjCMessageCompletionKind:
|
||||
concatChunksForObjectiveCMessage(cxResult);
|
||||
break;
|
||||
case CodeCompletionResult::ClassCompletionKind:
|
||||
case CodeCompletionResult::NamespaceCompletionKind:
|
||||
case CodeCompletionResult::EnumeratorCompletionKind:
|
||||
concatChunksForNestedName(cxResult.CompletionString);
|
||||
break;
|
||||
case CodeCompletionResult::ClangSnippetKind:
|
||||
concatChunksAsSnippet(cxResult.CompletionString);
|
||||
break;
|
||||
case CodeCompletionResult::SlotCompletionKind:
|
||||
case CodeCompletionResult::SignalCompletionKind:
|
||||
if (m_isSignalSlotCompletion)
|
||||
concatSlotSignalSignature(cxResult.CompletionString);
|
||||
else
|
||||
concatChunksOnlyTypedText(cxResult.CompletionString);
|
||||
break;
|
||||
default:
|
||||
concatChunksOnlyTypedText(cxResult.CompletionString);
|
||||
break;
|
||||
}
|
||||
m_hint += QLatin1String("</p>");
|
||||
m_hint += m_comment;
|
||||
|
||||
finalize();
|
||||
foreach (const OptionalChunk &chunk, m_optionalChunks) {
|
||||
m_hint.insert(chunk.positionInHint, chunk.hint);
|
||||
finalize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Internal ClangCodeModel's completion kind, that affects further postprocessing
|
||||
*/
|
||||
CodeCompletionResult::Kind CompletionProposalsBuilder::getKind(const CXCompletionResult &cxResult)
|
||||
{
|
||||
CXCompletionString complStr = cxResult.CompletionString;
|
||||
CXCursorKind cursorKind = cxResult.CursorKind;
|
||||
|
||||
switch (cursorKind) {
|
||||
case CXCursor_Constructor:
|
||||
return CodeCompletionResult::ConstructorCompletionKind;
|
||||
|
||||
case CXCursor_Destructor:
|
||||
return CodeCompletionResult::DestructorCompletionKind;
|
||||
|
||||
case CXCursor_CXXMethod: {
|
||||
const unsigned numAnnotations = clang_getCompletionNumAnnotations(complStr);
|
||||
bool isSignal = false, isSlot = false;
|
||||
for (unsigned i = 0; i < numAnnotations && !isSignal && !isSlot; ++i) {
|
||||
CXString cxAnn = clang_getCompletionAnnotation(complStr, i);
|
||||
QString ann = Internal::getQString(cxAnn);
|
||||
isSignal = ann == QLatin1String("qt_signal");
|
||||
isSlot = ann == QLatin1String("qt_slot");
|
||||
}
|
||||
if (isSignal)
|
||||
return CodeCompletionResult::SignalCompletionKind;
|
||||
if (isSlot)
|
||||
return CodeCompletionResult::SlotCompletionKind;
|
||||
} // intentional fall-through!
|
||||
case CXCursor_ConversionFunction:
|
||||
case CXCursor_FunctionDecl:
|
||||
case CXCursor_FunctionTemplate:
|
||||
case CXCursor_MemberRef:
|
||||
case CXCursor_MemberRefExpr:
|
||||
return CodeCompletionResult::FunctionCompletionKind;
|
||||
break;
|
||||
|
||||
case CXCursor_FieldDecl:
|
||||
case CXCursor_VarDecl:
|
||||
case CXCursor_ParmDecl:
|
||||
case CXCursor_ObjCIvarDecl:
|
||||
case CXCursor_ObjCPropertyDecl:
|
||||
case CXCursor_ObjCSynthesizeDecl:
|
||||
case CXCursor_NonTypeTemplateParameter:
|
||||
return CodeCompletionResult::VariableCompletionKind;
|
||||
|
||||
case CXCursor_Namespace:
|
||||
case CXCursor_NamespaceAlias:
|
||||
case CXCursor_NamespaceRef:
|
||||
return CodeCompletionResult::NamespaceCompletionKind;
|
||||
|
||||
case CXCursor_StructDecl:
|
||||
case CXCursor_UnionDecl:
|
||||
case CXCursor_ClassDecl:
|
||||
case CXCursor_TypeRef:
|
||||
case CXCursor_TemplateRef:
|
||||
case CXCursor_TypedefDecl:
|
||||
case CXCursor_ClassTemplate:
|
||||
case CXCursor_ClassTemplatePartialSpecialization:
|
||||
case CXCursor_ObjCClassRef:
|
||||
case CXCursor_ObjCInterfaceDecl:
|
||||
case CXCursor_ObjCImplementationDecl:
|
||||
case CXCursor_ObjCCategoryDecl:
|
||||
case CXCursor_ObjCCategoryImplDecl:
|
||||
case CXCursor_ObjCProtocolDecl:
|
||||
case CXCursor_ObjCProtocolRef:
|
||||
case CXCursor_TemplateTypeParameter:
|
||||
case CXCursor_TemplateTemplateParameter:
|
||||
return CodeCompletionResult::ClassCompletionKind;
|
||||
|
||||
case CXCursor_EnumConstantDecl:
|
||||
return CodeCompletionResult::EnumeratorCompletionKind;
|
||||
|
||||
case CXCursor_EnumDecl:
|
||||
return CodeCompletionResult::EnumCompletionKind;
|
||||
|
||||
case CXCursor_MacroDefinition: {
|
||||
const unsigned numChunks = clang_getNumCompletionChunks(complStr);
|
||||
for (unsigned i = 0; i < numChunks; ++i) {
|
||||
CXCompletionChunkKind kind = clang_getCompletionChunkKind(complStr, i);
|
||||
if (kind == CXCompletionChunk_Placeholder) {
|
||||
return CodeCompletionResult::FunctionCompletionKind;
|
||||
}
|
||||
}
|
||||
return CodeCompletionResult::PreProcessorCompletionKind;
|
||||
}
|
||||
|
||||
case CXCursor_PreprocessingDirective:
|
||||
case CXCursor_MacroExpansion:
|
||||
case CXCursor_InclusionDirective:
|
||||
return CodeCompletionResult::PreProcessorCompletionKind;
|
||||
|
||||
case CXCursor_ObjCClassMethodDecl:
|
||||
case CXCursor_ObjCInstanceMethodDecl:
|
||||
return CodeCompletionResult::ObjCMessageCompletionKind;
|
||||
|
||||
case CXCursor_NotImplemented: {
|
||||
const unsigned numChunks = clang_getNumCompletionChunks(complStr);
|
||||
for (unsigned i = 0; i < numChunks; ++i) {
|
||||
CXCompletionChunkKind kind = clang_getCompletionChunkKind(complStr, i);
|
||||
if (kind == CXCompletionChunk_Placeholder) {
|
||||
return CodeCompletionResult::ClangSnippetKind;
|
||||
}
|
||||
}
|
||||
return CodeCompletionResult::KeywordCompletionKind;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return CodeCompletionResult::Other;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Symbol availability, which is almost unused
|
||||
*/
|
||||
CodeCompletionResult::Availability CompletionProposalsBuilder::getAvailability(const CXCompletionResult &cxResult)
|
||||
{
|
||||
CXCompletionString complStr = cxResult.CompletionString;
|
||||
switch (clang_getCompletionAvailability(complStr)) {
|
||||
case CXAvailability_Deprecated:
|
||||
return CodeCompletionResult::Deprecated;
|
||||
|
||||
case CXAvailability_NotAvailable:
|
||||
return CodeCompletionResult::NotAvailable;
|
||||
|
||||
case CXAvailability_NotAccessible:
|
||||
return CodeCompletionResult::NotAccessible;
|
||||
|
||||
default:
|
||||
return CodeCompletionResult::Available;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Start index of name, which is unused in Qt signal/slot signature
|
||||
* @param text Text of Placeholder completion string chunk
|
||||
*/
|
||||
int CompletionProposalsBuilder::findNameInPlaceholder(const QString &text)
|
||||
{
|
||||
bool firstIdPassed = false;
|
||||
bool isInIdentifier = false;
|
||||
int bracesCounter = 0;
|
||||
int idStart = 0;
|
||||
|
||||
for (int i = 0, n = text.size(); i < n; ++i) {
|
||||
const QChar ch = text[i];
|
||||
|
||||
if (ch == QLatin1Char(':')) {
|
||||
firstIdPassed = false;
|
||||
isInIdentifier = false;
|
||||
}
|
||||
|
||||
if (ch == QLatin1Char('<') || ch == QLatin1Char('(')) {
|
||||
if (isInIdentifier && text.mid(idStart, i - idStart) == QLatin1String("const"))
|
||||
firstIdPassed = false;
|
||||
++bracesCounter;
|
||||
isInIdentifier = false;
|
||||
} else if (ch == QLatin1Char('>') || ch == QLatin1Char(')')) {
|
||||
if (isInIdentifier && text.mid(idStart, i - idStart) == QLatin1String("const"))
|
||||
firstIdPassed = false;
|
||||
--bracesCounter;
|
||||
isInIdentifier = false;
|
||||
} else if (bracesCounter == 0) {
|
||||
if (isInIdentifier) {
|
||||
isInIdentifier = ch.isLetterOrNumber() || (ch == QLatin1Char('_'));
|
||||
if (!isInIdentifier && text.mid(idStart, i - idStart) == QLatin1String("const"))
|
||||
firstIdPassed = false;
|
||||
} else if (ch.isLetter() || (ch == QLatin1Char('_'))) {
|
||||
if (firstIdPassed)
|
||||
return i;
|
||||
isInIdentifier = true;
|
||||
idStart = i;
|
||||
firstIdPassed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return text.size();
|
||||
}
|
||||
|
||||
void CompletionProposalsBuilder::resetWithResult(const CXCompletionResult &cxResult)
|
||||
{
|
||||
m_priority = clang_getCompletionPriority(cxResult.CompletionString);
|
||||
m_resultKind = getKind(cxResult);
|
||||
m_resultAvailability = getAvailability(cxResult);
|
||||
m_hasParameters = false;
|
||||
m_hint.clear();
|
||||
m_text.clear();
|
||||
m_snippet.clear();
|
||||
m_comment.clear();
|
||||
m_optionalChunks.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Appends completion proposal initialized with collected data
|
||||
*/
|
||||
void CompletionProposalsBuilder::finalize()
|
||||
{
|
||||
// Fixes code completion: operator and destructor cases
|
||||
if (m_contexts & (CXCompletionContext_DotMemberAccess
|
||||
| CXCompletionContext_ArrowMemberAccess
|
||||
| CXCompletionContext_AnyValue)) {
|
||||
if (m_resultKind == CodeCompletionResult::DestructorCompletionKind)
|
||||
m_priority *= PriorityFix_ExplicitDestructorCall;
|
||||
else if (m_resultKind == CodeCompletionResult::FunctionCompletionKind
|
||||
&& m_text.startsWith(QLatin1String("operator")))
|
||||
return;
|
||||
}
|
||||
|
||||
CodeCompletionResult ccr(m_priority);
|
||||
ccr.setCompletionKind(m_resultKind);
|
||||
ccr.setAvailability(m_resultAvailability);
|
||||
ccr.setHasParameters(m_hasParameters);
|
||||
ccr.setHint(m_hint);
|
||||
ccr.setText(m_text);
|
||||
ccr.setSnippet(m_snippet);
|
||||
m_results.append(ccr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates text, hint and snippet
|
||||
*
|
||||
* Text is just signature, e.g. 'length' for [NSString length] or 'respondsToSelector:'
|
||||
* for [id respondsToSelector:(SEL)sel].
|
||||
* Snippet is actual text, where any message parameter becames snippet part:
|
||||
* 'respondsToSelector:$(SEL)sel$'.
|
||||
* Hint consists of snippet preview and doxygen 'return' entry with returned type.
|
||||
*/
|
||||
void CompletionProposalsBuilder::concatChunksForObjectiveCMessage(const CXCompletionResult &cxResult)
|
||||
{
|
||||
CXCompletionString cxString = cxResult.CompletionString;
|
||||
const unsigned count = clang_getNumCompletionChunks(cxString);
|
||||
unsigned index = 0;
|
||||
QString hintPrefix;
|
||||
if (cxResult.CursorKind == CXCursor_ObjCClassMethodDecl)
|
||||
hintPrefix += QLatin1Char('+');
|
||||
else
|
||||
hintPrefix += QLatin1Char('-');
|
||||
int indentBonus = 1;
|
||||
|
||||
bool addSpaceAtPrefixEnd = true;
|
||||
for (; index < count; ++index) {
|
||||
CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxString, index);
|
||||
if (chunkKind == CXCompletionChunk_TypedText || chunkKind == CXCompletionChunk_Informative) {
|
||||
break;
|
||||
}
|
||||
const QString text = Internal::getQString(clang_getCompletionChunkText(cxString, index), false);
|
||||
if (chunkKind == CXCompletionChunk_ResultType) {
|
||||
hintPrefix += QLatin1Char('(');
|
||||
hintPrefix += text.toHtmlEscaped();
|
||||
hintPrefix += QLatin1String(") ");
|
||||
indentBonus += 3 + text.length();
|
||||
addSpaceAtPrefixEnd = false;
|
||||
} else {
|
||||
hintPrefix += text.toHtmlEscaped();
|
||||
indentBonus += text.length();
|
||||
m_snippet += text;
|
||||
}
|
||||
}
|
||||
if (addSpaceAtPrefixEnd) {
|
||||
m_snippet += QLatin1Char(' ');
|
||||
hintPrefix += QLatin1Char(' ');
|
||||
indentBonus += 1;
|
||||
}
|
||||
|
||||
m_hint += hintPrefix;
|
||||
|
||||
QList<ObjCMessagePart> parts;
|
||||
bool previousWasTypedText = false;
|
||||
for (; index < count; ++index) {
|
||||
CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxString, index);
|
||||
const QString text = Internal::getQString(clang_getCompletionChunkText(cxString, index), false);
|
||||
|
||||
switch (chunkKind) {
|
||||
case CXCompletionChunk_TypedText:
|
||||
if (previousWasTypedText)
|
||||
parts.back().addToSignature(text);
|
||||
else
|
||||
parts.append(ObjCMessagePart(text, indentBonus));
|
||||
m_snippet += text;
|
||||
m_text += text;
|
||||
break;
|
||||
case CXCompletionChunk_Informative:
|
||||
parts.append(ObjCMessagePart(text, indentBonus));
|
||||
break;
|
||||
case CXCompletionChunk_Text:
|
||||
case CXCompletionChunk_LeftParen:
|
||||
case CXCompletionChunk_RightParen:
|
||||
case CXCompletionChunk_Comma:
|
||||
case CXCompletionChunk_HorizontalSpace:
|
||||
m_snippet += text;
|
||||
parts.back().text += text.toHtmlEscaped();
|
||||
break;
|
||||
case CXCompletionChunk_Placeholder:
|
||||
appendSnippet(text);
|
||||
parts.back().text += QLatin1String("<b>");
|
||||
parts.back().text += text.toHtmlEscaped();
|
||||
parts.back().text += QLatin1String("</b>");
|
||||
break;
|
||||
case CXCompletionChunk_LeftAngle:
|
||||
m_snippet += text;
|
||||
parts.back().text += QLatin1String("<");
|
||||
break;
|
||||
case CXCompletionChunk_RightAngle:
|
||||
m_snippet += text;
|
||||
parts.back().text += QLatin1String(">");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
previousWasTypedText = (chunkKind == CXCompletionChunk_TypedText);
|
||||
}
|
||||
|
||||
int indent = 0;
|
||||
foreach (const ObjCMessagePart &part, parts)
|
||||
indent = qMax(indent, part.signatureLen);
|
||||
bool isFirstPart = true;
|
||||
foreach (const ObjCMessagePart &part, parts) {
|
||||
if (!isFirstPart)
|
||||
m_hint += QLatin1String("<br/>");
|
||||
isFirstPart = false;
|
||||
for (int i = 0; i < indent - part.signatureLen; ++i)
|
||||
m_hint += QLatin1String(" ");
|
||||
m_hint += part.text;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates entries like 'MyClass', 'MyNamespace::', 'MyEnumClass::Value1'
|
||||
*/
|
||||
void CompletionProposalsBuilder::concatChunksForNestedName(const CXCompletionString &cxString)
|
||||
{
|
||||
bool hasPlaceholder = false;
|
||||
unsigned count = clang_getNumCompletionChunks(cxString);
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxString, i);
|
||||
QString text = Internal::getQString(clang_getCompletionChunkText(cxString, i), false);
|
||||
|
||||
switch (chunkKind) {
|
||||
case CXCompletionChunk_TypedText:
|
||||
case CXCompletionChunk_Text:
|
||||
m_text += text;
|
||||
m_snippet += text;
|
||||
m_hint += text;
|
||||
break;
|
||||
|
||||
case CXCompletionChunk_LeftAngle:
|
||||
case CXCompletionChunk_RightAngle:
|
||||
case CXCompletionChunk_Comma:
|
||||
case CXCompletionChunk_HorizontalSpace:
|
||||
m_snippet += text;
|
||||
m_hint += text.toHtmlEscaped();
|
||||
break;
|
||||
|
||||
case CXCompletionChunk_Placeholder:
|
||||
hasPlaceholder = true;
|
||||
appendSnippet(text);
|
||||
appendHintBold(text);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasPlaceholder)
|
||||
m_snippet.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates text, snippet and hint for snippet preview
|
||||
*
|
||||
* Text is copy of snippet without '$' marks.
|
||||
* Hint also have 'return' doxygen entry if applicable (e.g. 'typeid...')
|
||||
*/
|
||||
void CompletionProposalsBuilder::concatChunksAsSnippet(const CXCompletionString &cxString)
|
||||
{
|
||||
unsigned count = clang_getNumCompletionChunks(cxString);
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxString, i);
|
||||
const QString text = Internal::getQString(clang_getCompletionChunkText(cxString, i), false);
|
||||
|
||||
switch (chunkKind) {
|
||||
case CXCompletionChunk_ResultType:
|
||||
attachResultTypeToComment(text);
|
||||
break;
|
||||
|
||||
case CXCompletionChunk_Placeholder:
|
||||
m_text += text;
|
||||
appendSnippet(text);
|
||||
appendHintBold(text);
|
||||
break;
|
||||
case CXCompletionChunk_LeftAngle:
|
||||
m_snippet += text;
|
||||
m_text += text;
|
||||
m_hint += QLatin1String("<");
|
||||
break;
|
||||
case CXCompletionChunk_RightAngle:
|
||||
m_snippet += text;
|
||||
m_text += text;
|
||||
m_hint += QLatin1String(">");
|
||||
break;
|
||||
|
||||
case CXCompletionChunk_VerticalSpace:
|
||||
m_snippet += QLatin1Char('\n');
|
||||
m_text += QLatin1Char(' ');
|
||||
m_hint += QLatin1String("<br/>");
|
||||
break;
|
||||
|
||||
default:
|
||||
m_snippet += text;
|
||||
m_text += text;
|
||||
m_hint += text;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates short text and hint with details
|
||||
*
|
||||
* Text is just function or variable name. Hint also contains function signature
|
||||
* or variable type.
|
||||
*/
|
||||
void CompletionProposalsBuilder::concatChunksOnlyTypedText(const CXCompletionString &cxString)
|
||||
{
|
||||
bool previousChunkWasLParen = false;
|
||||
bool isInsideTemplateSpec = false;
|
||||
|
||||
unsigned count = clang_getNumCompletionChunks(cxString);
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxString, i);
|
||||
QString text = Internal::getQString(clang_getCompletionChunkText(cxString, i), false);
|
||||
|
||||
switch (chunkKind) {
|
||||
case CXCompletionChunk_LeftParen:
|
||||
case CXCompletionChunk_RightParen:
|
||||
case CXCompletionChunk_Text:
|
||||
case CXCompletionChunk_LeftAngle:
|
||||
case CXCompletionChunk_RightAngle:
|
||||
m_hint += text.toHtmlEscaped();
|
||||
break;
|
||||
|
||||
case CXCompletionChunk_HorizontalSpace:
|
||||
case CXCompletionChunk_Comma:
|
||||
if (isInsideTemplateSpec) {
|
||||
m_snippet += text;
|
||||
}
|
||||
m_hint += text.toHtmlEscaped();
|
||||
break;
|
||||
|
||||
case CXCompletionChunk_Placeholder:
|
||||
if (isInsideTemplateSpec) {
|
||||
appendSnippet(text);
|
||||
}
|
||||
m_hint += text.toHtmlEscaped();
|
||||
break;
|
||||
|
||||
case CXCompletionChunk_TypedText:
|
||||
m_text = text;
|
||||
appendHintBold(text);
|
||||
break;
|
||||
|
||||
case CXCompletionChunk_ResultType: {
|
||||
m_hint += text.toHtmlEscaped();
|
||||
QChar last = text[text.size() - 1];
|
||||
if (last != QLatin1Char('*') && last != QLatin1Char('&'))
|
||||
m_hint += QLatin1Char(' ');
|
||||
}
|
||||
break;
|
||||
|
||||
case CXCompletionChunk_Informative:
|
||||
if (text == QLatin1String(" const"))
|
||||
m_hint += text;
|
||||
break;
|
||||
|
||||
case CXCompletionChunk_Optional:
|
||||
appendOptionalChunks(clang_getCompletionChunkCompletionString(cxString, i),
|
||||
m_hint.size());
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (chunkKind == CXCompletionChunk_RightParen && previousChunkWasLParen)
|
||||
m_hasParameters = false;
|
||||
|
||||
if (chunkKind == CXCompletionChunk_LeftParen) {
|
||||
previousChunkWasLParen = true;
|
||||
m_hasParameters = true;
|
||||
} else {
|
||||
previousChunkWasLParen = false;
|
||||
}
|
||||
|
||||
if (chunkKind == CXCompletionChunk_LeftAngle) {
|
||||
m_snippet = m_text;
|
||||
m_snippet += text;
|
||||
isInsideTemplateSpec = true;
|
||||
} else if (chunkKind == CXCompletionChunk_RightAngle) {
|
||||
isInsideTemplateSpec = false;
|
||||
m_snippet += text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Produces signal/slot signatures for 'connect' methods family
|
||||
*/
|
||||
void CompletionProposalsBuilder::concatSlotSignalSignature(const CXCompletionString &cxString)
|
||||
{
|
||||
QString resultType;
|
||||
|
||||
unsigned count = clang_getNumCompletionChunks(cxString);
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxString, i);
|
||||
QString text = Internal::getQString(clang_getCompletionChunkText(cxString, i), false);
|
||||
|
||||
switch (chunkKind) {
|
||||
case CXCompletionChunk_Placeholder:
|
||||
text.truncate(findNameInPlaceholder(text));
|
||||
// fall-through
|
||||
case CXCompletionChunk_TypedText:
|
||||
case CXCompletionChunk_LeftParen:
|
||||
case CXCompletionChunk_RightParen:
|
||||
case CXCompletionChunk_Comma:
|
||||
case CXCompletionChunk_Text:
|
||||
m_text += text;
|
||||
break;
|
||||
case CXCompletionChunk_ResultType:
|
||||
resultType += text;
|
||||
resultType += QLatin1Char(' ');
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const QString parent = Internal::getQString(clang_getCompletionParent(cxString, NULL));
|
||||
if (m_resultKind == CodeCompletionResult::SlotCompletionKind)
|
||||
m_hint += tr("Slot of %1, returns %2").arg(parent, resultType);
|
||||
else
|
||||
m_hint += tr("Signal of %1, returns %2").arg(parent, resultType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stores optional part for further postprocessing in \a finalize()
|
||||
* @param insertionIndex Index where to insert optional chunk into hint
|
||||
*/
|
||||
void CompletionProposalsBuilder::appendOptionalChunks(const CXCompletionString &cxString,
|
||||
int insertionIndex)
|
||||
{
|
||||
OptionalChunk chunk;
|
||||
chunk.positionInHint = insertionIndex;
|
||||
|
||||
unsigned count = clang_getNumCompletionChunks(cxString);
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxString, i);
|
||||
QString text = Internal::getQString(clang_getCompletionChunkText(cxString, i), false);
|
||||
|
||||
switch (chunkKind) {
|
||||
case CXCompletionChunk_Placeholder:
|
||||
chunk.hint += text.toHtmlEscaped();
|
||||
break;
|
||||
|
||||
case CXCompletionChunk_Comma:
|
||||
chunk.hint += text;
|
||||
chunk.hint += QLatin1Char(' ');
|
||||
break;
|
||||
|
||||
case CXCompletionChunk_Optional:
|
||||
m_optionalChunks.append(chunk);
|
||||
appendOptionalChunks(clang_getCompletionChunkCompletionString(cxString, i),
|
||||
insertionIndex + chunk.hint.size());
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_optionalChunks.append(chunk);
|
||||
}
|
||||
|
||||
void CompletionProposalsBuilder::attachResultTypeToComment(const QString &resultType)
|
||||
{
|
||||
if (resultType.isEmpty())
|
||||
return;
|
||||
|
||||
if (!m_comment.isEmpty())
|
||||
m_comment += QLatin1String("<br/>");
|
||||
|
||||
m_comment += QLatin1String("<b>@return</b> ");
|
||||
m_comment += resultType;
|
||||
}
|
||||
|
||||
void CompletionProposalsBuilder::appendSnippet(const QString &text)
|
||||
{
|
||||
m_snippet += QLatin1Char('$');
|
||||
m_snippet += text;
|
||||
m_snippet += QLatin1Char('$');
|
||||
}
|
||||
|
||||
void CompletionProposalsBuilder::appendHintBold(const QString &text)
|
||||
{
|
||||
m_hint += QLatin1String("<b>");
|
||||
m_hint += text.toHtmlEscaped();
|
||||
m_hint += QLatin1String("</b>");
|
||||
}
|
||||
|
||||
} // namespace ClangCodeModel
|
@@ -1,93 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CLANGCODEMODEL_COMPLETIONPROPOSALSBUILDER_H
|
||||
#define CLANGCODEMODEL_COMPLETIONPROPOSALSBUILDER_H
|
||||
|
||||
#include "clangcompleter.h"
|
||||
#include "clang_global.h"
|
||||
#include <clang-c/Index.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
namespace ClangCodeModel {
|
||||
|
||||
class CLANG_EXPORT CompletionProposalsBuilder
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(ClangCodeModel::CompletionProposalsBuilder)
|
||||
|
||||
public:
|
||||
CompletionProposalsBuilder(QList<CodeCompletionResult> &results, quint64 contexts, bool isSignalSlotCompletion);
|
||||
void operator ()(const CXCompletionResult &cxResult);
|
||||
|
||||
private:
|
||||
struct OptionalChunk {
|
||||
int positionInHint;
|
||||
QString hint;
|
||||
|
||||
OptionalChunk() : positionInHint(0) {}
|
||||
};
|
||||
|
||||
static CodeCompletionResult::Kind getKind(const CXCompletionResult &cxResult);
|
||||
static CodeCompletionResult::Availability getAvailability(const CXCompletionResult &cxResult);
|
||||
static int findNameInPlaceholder(const QString &text);
|
||||
void resetWithResult(const CXCompletionResult &cxResult);
|
||||
void finalize();
|
||||
|
||||
void concatChunksForObjectiveCMessage(const CXCompletionResult &cxResult);
|
||||
void concatChunksForNestedName(const CXCompletionString &cxString);
|
||||
void concatChunksAsSnippet(const CXCompletionString &cxString);
|
||||
void concatChunksOnlyTypedText(const CXCompletionString &cxString);
|
||||
void concatSlotSignalSignature(const CXCompletionString &cxString);
|
||||
void appendOptionalChunks(const CXCompletionString &cxString,
|
||||
int insertionIndex);
|
||||
void attachResultTypeToComment(const QString &text);
|
||||
|
||||
void appendSnippet(const QString &text);
|
||||
void appendHintBold(const QString &text);
|
||||
|
||||
QList<CodeCompletionResult> &m_results;
|
||||
const quint64 m_contexts;
|
||||
const bool m_isSignalSlotCompletion;
|
||||
|
||||
unsigned m_priority;
|
||||
CodeCompletionResult::Kind m_resultKind;
|
||||
CodeCompletionResult::Availability m_resultAvailability;
|
||||
bool m_hasParameters;
|
||||
QString m_hint;
|
||||
QString m_text;
|
||||
QString m_snippet;
|
||||
QString m_comment;
|
||||
QList<OptionalChunk> m_optionalChunks;
|
||||
};
|
||||
|
||||
} // namespace ClangCodeModel
|
||||
|
||||
#endif // CLANGCODEMODEL_COMPLETIONPROPOSALSBUILDER_H
|
@@ -1,18 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/unittests/ClangCodeModel">
|
||||
<file>cxx_regression_1.cpp</file>
|
||||
<file>cxx_regression_2.cpp</file>
|
||||
<file>cxx_regression_3.cpp</file>
|
||||
<file>cxx_regression_4.cpp</file>
|
||||
<file>cxx_regression_5.cpp</file>
|
||||
<file>cxx_regression_6.cpp</file>
|
||||
<file>cxx_regression_7.cpp</file>
|
||||
<file>cxx_regression_8.cpp</file>
|
||||
<file>cxx_regression_9.cpp</file>
|
||||
<file>cxx_snippets_1.cpp</file>
|
||||
<file>cxx_snippets_2.cpp</file>
|
||||
<file>cxx_snippets_3.cpp</file>
|
||||
<file>cxx_snippets_4.cpp</file>
|
||||
<file>objc_messages_1.mm</file>
|
||||
<file>objc_messages_2.mm</file>
|
||||
<file>objc_messages_3.mm</file>
|
||||
|
@@ -31,9 +31,9 @@
|
||||
#include "clangcodecompletion_test.h"
|
||||
|
||||
#include "../clangbackendipcintegration.h"
|
||||
#include "../clangcompletionassistinterface.h"
|
||||
#include "../clangmodelmanagersupport.h"
|
||||
|
||||
#include <clangcodemodel/clangcompletion.h>
|
||||
#include <clangcodemodel/constants.h>
|
||||
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <cpptools/cpptoolstestcase.h>
|
||||
#include <cpptools/modelmanagertesthelper.h>
|
||||
#include <texteditor/codeassist/assistinterface.h>
|
||||
#include <texteditor/codeassist/assistproposalitem.h>
|
||||
#include <texteditor/codeassist/completionassistprovider.h>
|
||||
#include <texteditor/codeassist/genericproposalmodel.h>
|
||||
#include <texteditor/codeassist/iassistprocessor.h>
|
||||
@@ -241,12 +242,14 @@ class ChangeIpcSender
|
||||
public:
|
||||
ChangeIpcSender(IpcSenderInterface *ipcSender)
|
||||
{
|
||||
m_previousSender = ModelManagerSupportClang::instance()->ipcCommunicator().setIpcSender(ipcSender);
|
||||
auto &ipc = ModelManagerSupportClang::instance_forTestsOnly()->ipcCommunicator();
|
||||
m_previousSender = ipc.setIpcSender(ipcSender);
|
||||
}
|
||||
|
||||
~ChangeIpcSender()
|
||||
{
|
||||
ModelManagerSupportClang::instance()->ipcCommunicator().setIpcSender(m_previousSender);
|
||||
auto &ipc = ModelManagerSupportClang::instance_forTestsOnly()->ipcCommunicator();
|
||||
ipc.setIpcSender(m_previousSender);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -940,7 +943,7 @@ void ClangCodeCompletionTest::testUpdateBackendAfterRestart()
|
||||
spy.senderLog.clear();
|
||||
|
||||
// Kill backend process...
|
||||
IpcCommunicator &ipcCommunicator = ModelManagerSupportClang::instance()->ipcCommunicator();
|
||||
auto &ipcCommunicator = ModelManagerSupportClang::instance_forTestsOnly()->ipcCommunicator();
|
||||
ipcCommunicator.killBackendProcess();
|
||||
QSignalSpy waitForReinitializedBackend(&ipcCommunicator,
|
||||
SIGNAL(backendReinitialized()));
|
||||
|
@@ -1,393 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @file clangcompletion_test.cpp
|
||||
* @brief Performs test for C/C++ code completion
|
||||
*
|
||||
* All test cases given as strings with @ character that points to completion
|
||||
* location.
|
||||
*/
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
|
||||
// Disabled because there still no tool to detect system Objective-C headers
|
||||
#define ENABLE_OBJC_TESTS 0
|
||||
|
||||
#include <QtTest>
|
||||
#include <QDebug>
|
||||
#undef interface // Canceling "#DEFINE interface struct" on Windows
|
||||
|
||||
#include "completiontesthelper.h"
|
||||
#include "../clangcodemodelplugin.h"
|
||||
|
||||
using namespace ClangCodeModel;
|
||||
using namespace ClangCodeModel::Internal;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Test cases
|
||||
|
||||
/**
|
||||
* \defgroup Regression tests
|
||||
*
|
||||
* This group tests possible regressions in non-standard completion chunks
|
||||
* handling: for example, macro arguments and clang's code snippets.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
void ClangCodeModelPlugin::test_CXX_regressions()
|
||||
{
|
||||
QFETCH(QString, file);
|
||||
QFETCH(QStringList, unexpected);
|
||||
QFETCH(QStringList, mustHave);
|
||||
|
||||
CompletionTestHelper helper;
|
||||
helper << file;
|
||||
|
||||
QStringList proposals = helper.codeCompleteTexts();
|
||||
|
||||
foreach (const QString &p, unexpected)
|
||||
QTEST_ASSERT(false == proposals.contains(p));
|
||||
|
||||
foreach (const QString &p, mustHave)
|
||||
QTEST_ASSERT(true == proposals.contains(p));
|
||||
}
|
||||
|
||||
void ClangCodeModelPlugin::test_CXX_regressions_data()
|
||||
{
|
||||
QTest::addColumn<QString>("file");
|
||||
QTest::addColumn<QStringList>("unexpected");
|
||||
QTest::addColumn<QStringList>("mustHave");
|
||||
|
||||
QString file;
|
||||
QStringList unexpected;
|
||||
QStringList mustHave;
|
||||
|
||||
file = QLatin1String("cxx_regression_1.cpp");
|
||||
mustHave << QLatin1String("sqr");
|
||||
mustHave << QLatin1String("~Math");
|
||||
unexpected << QLatin1String("operator=");
|
||||
QTest::newRow("case 1: method call completion") << file << unexpected << mustHave;
|
||||
mustHave.clear();
|
||||
unexpected.clear();
|
||||
|
||||
file = QLatin1String("cxx_regression_2.cpp");
|
||||
unexpected << QLatin1String("i_second");
|
||||
unexpected << QLatin1String("c_second");
|
||||
unexpected << QLatin1String("f_second");
|
||||
mustHave << QLatin1String("i_first");
|
||||
mustHave << QLatin1String("c_first");
|
||||
QTest::newRow("case 2: multiple anonymous structs") << file << unexpected << mustHave;
|
||||
mustHave.clear();
|
||||
unexpected.clear();
|
||||
|
||||
file = QLatin1String("cxx_regression_3.cpp");
|
||||
mustHave << QLatin1String("i8");
|
||||
mustHave << QLatin1String("i64");
|
||||
mustHave << QLatin1String("~Priv");
|
||||
unexpected << QLatin1String("operator=");
|
||||
QTest::newRow("case 3: nested class resolution") << file << unexpected << mustHave;
|
||||
mustHave.clear();
|
||||
unexpected.clear();
|
||||
|
||||
file = QLatin1String("cxx_regression_4.cpp");
|
||||
mustHave << QLatin1String("action");
|
||||
QTest::newRow("case 4: local (in function) class resolution") << file << unexpected << mustHave;
|
||||
mustHave.clear();
|
||||
unexpected.clear();
|
||||
|
||||
file = QLatin1String("cxx_regression_5.cpp");
|
||||
mustHave << QLatin1String("doB");
|
||||
unexpected << QLatin1String("doA");
|
||||
QTest::newRow("case 5: nested template class resolution") << file << unexpected << mustHave;
|
||||
mustHave.clear();
|
||||
unexpected.clear();
|
||||
|
||||
file = QLatin1String("cxx_regression_6.cpp");
|
||||
mustHave << QLatin1String("OwningPtr");
|
||||
QTest::newRow("case 6: using particular symbol from namespace") << file << unexpected << mustHave;
|
||||
mustHave.clear();
|
||||
unexpected.clear();
|
||||
|
||||
file = QLatin1String("cxx_regression_7.cpp");
|
||||
mustHave << QLatin1String("dataMember");
|
||||
mustHave << QLatin1String("anotherMember");
|
||||
QTest::newRow("case 7: template class inherited from template parameter") << file << unexpected << mustHave;
|
||||
mustHave.clear();
|
||||
unexpected.clear();
|
||||
|
||||
file = QLatin1String("cxx_regression_8.cpp");
|
||||
mustHave << QLatin1String("utils::");
|
||||
unexpected << QLatin1String("utils");
|
||||
QTest::newRow("case 8: namespace completion in function body") << file << unexpected << mustHave;
|
||||
mustHave.clear();
|
||||
unexpected.clear();
|
||||
|
||||
file = QLatin1String("cxx_regression_9.cpp");
|
||||
mustHave << QLatin1String("EnumScoped::Value1");
|
||||
mustHave << QLatin1String("EnumScoped::Value2");
|
||||
mustHave << QLatin1String("EnumScoped::Value3");
|
||||
unexpected << QLatin1String("Value1");
|
||||
unexpected << QLatin1String("EnumScoped");
|
||||
QTest::newRow("case 9: c++11 enum class, value used in switch and 'case' completed")
|
||||
<< file << unexpected << mustHave;
|
||||
mustHave.clear();
|
||||
unexpected.clear();
|
||||
}
|
||||
|
||||
void ClangCodeModelPlugin::test_CXX_snippets()
|
||||
{
|
||||
QFETCH(QString, file);
|
||||
QFETCH(QStringList, texts);
|
||||
QFETCH(QStringList, snippets);
|
||||
Q_ASSERT(texts.size() == snippets.size());
|
||||
|
||||
CompletionTestHelper helper;
|
||||
helper << file;
|
||||
|
||||
QList<CodeCompletionResult> proposals = helper.codeComplete();
|
||||
|
||||
for (int i = 0, n = texts.size(); i < n; ++i) {
|
||||
const QString &text = texts[i];
|
||||
const QString &snippet = snippets[i];
|
||||
const QString snippetError =
|
||||
QLatin1String("Text and snippet mismatch: text '") + text
|
||||
+ QLatin1String("', snippet '") + snippet
|
||||
+ QLatin1String("', got snippet \"%1\"");
|
||||
|
||||
bool hasText = false;
|
||||
foreach (const CodeCompletionResult &ccr, proposals) {
|
||||
if (ccr.text() != text)
|
||||
continue;
|
||||
hasText = true;
|
||||
QVERIFY2(snippet == ccr.snippet(), snippetError.arg(ccr.snippet()).toLatin1());
|
||||
}
|
||||
const QString textError(QLatin1String("Text not found:") + text);
|
||||
QVERIFY2(hasText, textError.toLatin1());
|
||||
}
|
||||
}
|
||||
|
||||
void ClangCodeModelPlugin::test_CXX_snippets_data()
|
||||
{
|
||||
QTest::addColumn<QString>("file");
|
||||
QTest::addColumn<QStringList>("texts");
|
||||
QTest::addColumn<QStringList>("snippets");
|
||||
|
||||
QString file;
|
||||
QStringList texts;
|
||||
QStringList snippets;
|
||||
|
||||
file = QLatin1String("cxx_snippets_1.cpp");
|
||||
texts << QLatin1String("reinterpret_cast<type>(expression)");
|
||||
snippets << QLatin1String("reinterpret_cast<$type$>($expression$)");
|
||||
|
||||
texts << QLatin1String("static_cast<type>(expression)");
|
||||
snippets << QLatin1String("static_cast<$type$>($expression$)");
|
||||
|
||||
texts << QLatin1String("new type(expressions)");
|
||||
snippets << QLatin1String("new $type$($expressions$)");
|
||||
|
||||
QTest::newRow("case: snippets for var declaration") << file << texts << snippets;
|
||||
texts.clear();
|
||||
snippets.clear();
|
||||
|
||||
file = QLatin1String("cxx_snippets_2.cpp");
|
||||
texts << QLatin1String("private");
|
||||
snippets << QLatin1String("");
|
||||
|
||||
texts << QLatin1String("protected");
|
||||
snippets << QLatin1String("");
|
||||
|
||||
texts << QLatin1String("public");
|
||||
snippets << QLatin1String("");
|
||||
|
||||
texts << QLatin1String("friend");
|
||||
snippets << QLatin1String("");
|
||||
|
||||
texts << QLatin1String("virtual");
|
||||
snippets << QLatin1String("");
|
||||
|
||||
texts << QLatin1String("typedef type name");
|
||||
snippets << QLatin1String("typedef $type$ $name$");
|
||||
|
||||
QTest::newRow("case: snippets inside class declaration") << file << texts << snippets;
|
||||
texts.clear();
|
||||
snippets.clear();
|
||||
|
||||
file = QLatin1String("cxx_snippets_3.cpp");
|
||||
texts << QLatin1String("List");
|
||||
snippets << QLatin1String("List<$class Item$>");
|
||||
|
||||
texts << QLatin1String("Tuple");
|
||||
snippets << QLatin1String("Tuple<$class First$, $class Second$, $typename Third$>");
|
||||
|
||||
QTest::newRow("case: template class insertion as snippet") << file << texts << snippets;
|
||||
texts.clear();
|
||||
snippets.clear();
|
||||
|
||||
file = QLatin1String("cxx_snippets_4.cpp");
|
||||
texts << QLatin1String("clamp");
|
||||
snippets << QLatin1String("");
|
||||
|
||||
texts << QLatin1String("perform");
|
||||
snippets << QLatin1String("perform<$class T$>");
|
||||
|
||||
QTest::newRow("case: template function insertion as snippet") << file << texts << snippets;
|
||||
texts.clear();
|
||||
snippets.clear();
|
||||
}
|
||||
|
||||
void ClangCodeModelPlugin::test_ObjC_hints()
|
||||
{
|
||||
QFETCH(QString, file);
|
||||
QFETCH(QStringList, texts);
|
||||
QFETCH(QStringList, snippets);
|
||||
QFETCH(QStringList, hints);
|
||||
Q_ASSERT(texts.size() == snippets.size());
|
||||
Q_ASSERT(texts.size() == hints.size());
|
||||
|
||||
CompletionTestHelper helper;
|
||||
helper << file;
|
||||
|
||||
QList<CodeCompletionResult> proposals = helper.codeComplete();
|
||||
|
||||
for (int i = 0, n = texts.size(); i < n; ++i) {
|
||||
const QString &text = texts[i];
|
||||
const QString &snippet = snippets[i];
|
||||
const QString &hint = hints[i];
|
||||
const QString snippetError =
|
||||
QLatin1String("Text and snippet mismatch: text '") + text
|
||||
+ QLatin1String("', snippet '") + snippet
|
||||
+ QLatin1String("', got snippet \"%1\"");
|
||||
const QString hintError =
|
||||
QLatin1String("Text and hint mismatch: text '") + text
|
||||
+ QLatin1String("', hint\n'") + hint
|
||||
+ QLatin1String(", got hint\n\"%1\"");
|
||||
|
||||
bool hasText = false;
|
||||
QStringList texts;
|
||||
foreach (const CodeCompletionResult &ccr, proposals) {
|
||||
texts << ccr.text();
|
||||
if (ccr.text() != text)
|
||||
continue;
|
||||
hasText = true;
|
||||
QVERIFY2(snippet == ccr.snippet(), snippetError.arg(ccr.snippet()).toLatin1());
|
||||
QVERIFY2(hint == ccr.hint(), hintError.arg(ccr.hint()).toLatin1());
|
||||
}
|
||||
const QString textError(QString::fromLatin1("Text \"%1\" not found in set %2")
|
||||
.arg(text).arg(texts.join(QLatin1Char(','))));
|
||||
QVERIFY2(hasText, textError.toLatin1());
|
||||
}
|
||||
}
|
||||
|
||||
static QString makeObjCHint(const char *cHintPattern)
|
||||
{
|
||||
QString hintPattern(QString::fromUtf8(cHintPattern));
|
||||
QStringList lines = hintPattern.split(QLatin1Char('\n'));
|
||||
QString hint = QLatin1String("<p>");
|
||||
bool prependNewline = false;
|
||||
foreach (const QString &line, lines) {
|
||||
if (prependNewline)
|
||||
hint += QLatin1String("<br/>");
|
||||
prependNewline = true;
|
||||
int i = 0;
|
||||
while (i < line.size() && line[i] == QLatin1Char(' ')) {
|
||||
++i;
|
||||
hint += QLatin1String(" ");
|
||||
}
|
||||
hint += line.mid(i);
|
||||
}
|
||||
hint += QLatin1String("</p>");
|
||||
return hint;
|
||||
}
|
||||
|
||||
void ClangCodeModelPlugin::test_ObjC_hints_data()
|
||||
{
|
||||
QTest::addColumn<QString>("file");
|
||||
QTest::addColumn<QStringList>("texts");
|
||||
QTest::addColumn<QStringList>("snippets");
|
||||
QTest::addColumn<QStringList>("hints");
|
||||
|
||||
QString file;
|
||||
QStringList texts;
|
||||
QStringList snippets;
|
||||
QStringList hints;
|
||||
|
||||
file = QLatin1String("objc_messages_1.mm");
|
||||
texts << QLatin1String("spectacleQuality:");
|
||||
snippets << QLatin1String("spectacleQuality:$(bool)$");
|
||||
hints << makeObjCHint("-(int) spectacleQuality:<b>(bool)</b>");
|
||||
texts << QLatin1String("desiredAmountForDramaDose:andPersonsCount:");
|
||||
snippets << QLatin1String("desiredAmountForDramaDose:$(int)$ andPersonsCount:$(int)$");
|
||||
hints << makeObjCHint("-(int) desiredAmountForDramaDose:<b>(int)</b> \n"
|
||||
" andPersonsCount:<b>(int)</b>");
|
||||
|
||||
QTest::newRow("case: objective-c instance messages call") << file << texts << snippets << hints;
|
||||
texts.clear();
|
||||
snippets.clear();
|
||||
hints.clear();
|
||||
|
||||
file = QLatin1String("objc_messages_2.mm");
|
||||
texts << QLatin1String("eatenAmount");
|
||||
snippets << QLatin1String("(int) eatenAmount");
|
||||
hints << makeObjCHint("+(int) eatenAmount");
|
||||
texts << QLatin1String("desiredAmountForDramaDose:andPersonsCount:");
|
||||
snippets << QLatin1String("(int) desiredAmountForDramaDose:(int)dose andPersonsCount:(int)count");
|
||||
hints << makeObjCHint("+(int) desiredAmountForDramaDose:(int)dose \n"
|
||||
" andPersonsCount:(int)count");
|
||||
|
||||
QTest::newRow("case: objective-c class messages in @implementation") << file << texts << snippets << hints;
|
||||
texts.clear();
|
||||
snippets.clear();
|
||||
hints.clear();
|
||||
|
||||
file = QLatin1String("objc_messages_3.mm");
|
||||
texts << QLatin1String("eatenAmount");
|
||||
snippets << QLatin1String("(int) eatenAmount");
|
||||
hints << makeObjCHint("-(int) eatenAmount");
|
||||
texts << QLatin1String("spectacleQuality");
|
||||
snippets << QLatin1String("(int) spectacleQuality");
|
||||
hints << makeObjCHint("-(int) spectacleQuality");
|
||||
texts << QLatin1String("desiredAmountForDramaDose:andPersonsCount:");
|
||||
snippets << QLatin1String("(int) desiredAmountForDramaDose:(int)dose andPersonsCount:(int)count");
|
||||
hints << makeObjCHint("-(int) desiredAmountForDramaDose:(int)dose \n"
|
||||
" andPersonsCount:(int)count");
|
||||
texts << QLatin1String("initWithOldTracker:");
|
||||
snippets << QLatin1String("(id) initWithOldTracker:(Bbbb<Aaaa> *)aabb");
|
||||
hints << makeObjCHint("-(id) initWithOldTracker:(Bbbb<Aaaa> *)aabb");
|
||||
|
||||
QTest::newRow("case: objective-c class messages from base class") << file << texts << snippets << hints;
|
||||
texts.clear();
|
||||
snippets.clear();
|
||||
hints.clear();
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,148 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
|
||||
#include "completiontesthelper.h"
|
||||
#include "../clangcompletion.h"
|
||||
#include "../clangcompleter.h"
|
||||
#include "../clangcodemodelplugin.h"
|
||||
|
||||
#include <cpptools/cppcompletionassist.h>
|
||||
|
||||
#include <texteditor/textdocument.h>
|
||||
#include <texteditor/texteditor.h>
|
||||
#include <texteditor/codeassist/iassistproposal.h>
|
||||
#include <texteditor/codeassist/genericproposalmodel.h>
|
||||
|
||||
#include <utils/fileutils.h>
|
||||
#include <utils/changeset.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QtTest>
|
||||
|
||||
using namespace ClangCodeModel;
|
||||
using namespace ClangCodeModel::Internal;
|
||||
using namespace TextEditor;
|
||||
using namespace CPlusPlus;
|
||||
using namespace CppTools::Internal;
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
CompletionTestHelper::CompletionTestHelper(QObject *parent) :
|
||||
QObject(parent),
|
||||
m_completer(new ClangCompleter()),
|
||||
m_position(0),
|
||||
m_line(0),
|
||||
m_column(0)
|
||||
{
|
||||
m_clangOptions << QLatin1String("-std=c++0x")
|
||||
<< QLatin1String("-ObjC++");
|
||||
}
|
||||
|
||||
CompletionTestHelper::~CompletionTestHelper()
|
||||
{
|
||||
}
|
||||
|
||||
void CompletionTestHelper::operator <<(const QString &fileName)
|
||||
{
|
||||
QResource res(QLatin1String(":/unittests/ClangCodeModel/") + fileName);
|
||||
m_sourceCode = QByteArray(reinterpret_cast<const char*>(res.data()), res.size());
|
||||
findCompletionPos();
|
||||
|
||||
QString path = QDir::tempPath() + QLatin1String("/file.h");
|
||||
::Utils::FileSaver srcSaver(path);
|
||||
srcSaver.write(m_sourceCode);
|
||||
srcSaver.finalize();
|
||||
|
||||
m_completer->setFileName(path);
|
||||
m_completer->setOptions(m_clangOptions);
|
||||
}
|
||||
|
||||
QStringList CompletionTestHelper::codeCompleteTexts()
|
||||
{
|
||||
QList<CodeCompletionResult> results =
|
||||
m_completer->codeCompleteAt(m_line, m_column, m_unsavedFiles);
|
||||
|
||||
QStringList completions;
|
||||
foreach (const CodeCompletionResult& ccr, results)
|
||||
completions << ccr.text();
|
||||
return completions;
|
||||
}
|
||||
|
||||
QList<CodeCompletionResult> CompletionTestHelper::codeComplete()
|
||||
{
|
||||
return m_completer->codeCompleteAt(m_line, m_column, m_unsavedFiles);
|
||||
}
|
||||
|
||||
int CompletionTestHelper::position() const
|
||||
{
|
||||
return m_position;
|
||||
}
|
||||
|
||||
const QByteArray &CompletionTestHelper::source() const
|
||||
{
|
||||
return m_sourceCode;
|
||||
}
|
||||
|
||||
void CompletionTestHelper::addOption(const QString &option)
|
||||
{
|
||||
m_clangOptions << option;
|
||||
}
|
||||
|
||||
void CompletionTestHelper::findCompletionPos()
|
||||
{
|
||||
m_position = m_sourceCode.indexOf("<<<<");
|
||||
QVERIFY(m_position != -1);
|
||||
m_sourceCode[m_position] = ' ';
|
||||
m_sourceCode[m_position + 1] = ' ';
|
||||
m_sourceCode[m_position + 2] = ' ';
|
||||
m_sourceCode[m_position + 3] = ' ';
|
||||
|
||||
// substring from 0 to '@' position
|
||||
QByteArray substr(m_sourceCode.data(), m_position);
|
||||
|
||||
m_line = 1;
|
||||
m_column = 1;
|
||||
for (int i = 0; i < substr.size(); ++i) {
|
||||
if (substr[i] == '\n') {
|
||||
++m_line;
|
||||
m_column = 1;
|
||||
} else {
|
||||
++m_column;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
|
||||
#endif
|
@@ -1,45 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Expected: 'sqr'
|
||||
* Not expected: '~Math', 'operator='s
|
||||
*/
|
||||
|
||||
class Math
|
||||
{
|
||||
int sqr(int a);
|
||||
};
|
||||
|
||||
void foo()
|
||||
{
|
||||
Math math;
|
||||
int sqr = math.<<<<;
|
||||
}
|
@@ -1,51 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Expected: 'i_first' 'c_first'
|
||||
* Not expected: 'i_second' 'c_second' 'f_second'
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
int i_first;
|
||||
char c_first;
|
||||
} S1;
|
||||
|
||||
typedef struct {
|
||||
int i_second;
|
||||
char c_second;
|
||||
float f_second;
|
||||
} S2;
|
||||
|
||||
void foo()
|
||||
{
|
||||
S1 s;
|
||||
s.<<<<;
|
||||
}
|
@@ -1,42 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Expected: 'action'
|
||||
*/
|
||||
|
||||
void func()
|
||||
{
|
||||
struct impl
|
||||
{
|
||||
static void action() {}
|
||||
};
|
||||
impl::<<<<;
|
||||
}
|
@@ -1,48 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Expected: 'dataMember', 'anotherMember'
|
||||
*/
|
||||
|
||||
class Data {
|
||||
int dataMember;
|
||||
};
|
||||
|
||||
template <class T> class Other : public T
|
||||
{
|
||||
int anotherMember;
|
||||
};
|
||||
|
||||
void func()
|
||||
{
|
||||
Other<Data> c;
|
||||
c.<<<<;
|
||||
}
|
@@ -1,47 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Expected: 'utils::'
|
||||
* Not expected: 'utils'
|
||||
*/
|
||||
|
||||
namespace utils
|
||||
{
|
||||
int sqr(int a)
|
||||
{
|
||||
return a * a;
|
||||
}
|
||||
}
|
||||
|
||||
void foo()
|
||||
{
|
||||
<<<<
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Expected: 'EnumScoped::Value1', 'EnumScoped::Value2', 'EnumScoped::Value3'
|
||||
* Unexpected: 'Value1'
|
||||
*/
|
||||
|
||||
enum class EnumScoped
|
||||
{
|
||||
Value1,
|
||||
Value2,
|
||||
Value3
|
||||
};
|
||||
|
||||
class ClassOwnsEnum
|
||||
{
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
EnumScoped scoped = ;
|
||||
switch (scoped) {
|
||||
default:
|
||||
break;
|
||||
case <<<<
|
||||
}
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
Expected:
|
||||
text 'reinterpret_cast<type>(expression)'
|
||||
snippet 'reinterpret_cast<$type$>($expression$)'
|
||||
|
||||
text 'static_cast<type>(expression)'
|
||||
snippet 'static_cast<$type$>($expression$)'
|
||||
|
||||
text 'new type(expressions)'
|
||||
snippet 'new $type$($expressions$)'
|
||||
*/
|
||||
|
||||
void foo()
|
||||
{
|
||||
int data[] = {
|
||||
1, 2, 3
|
||||
};
|
||||
char *cdata = <<<<;
|
||||
}
|
@@ -1,45 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://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 http://www.qt.io/terms-conditions. For further information
|
||||
** use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
Expected:
|
||||
text 'private',
|
||||
text 'protected',
|
||||
text 'public',
|
||||
text 'friend',
|
||||
text 'virtual'
|
||||
|
||||
text 'typedef type name', snippet 'typedef $type$ $name$'
|
||||
*/
|
||||
|
||||
class A
|
||||
{
|
||||
<<<<
|
||||
};
|
@@ -88,12 +88,12 @@ void SettingsPageWidget::setSettings(const ClearCaseSettings &s)
|
||||
if (extDiffAvailable) {
|
||||
m_ui.diffWarningLabel->setVisible(false);
|
||||
} else {
|
||||
QString diffWarning = tr("In order to use External diff, 'diff' command needs to be accessible.");
|
||||
QString diffWarning = tr("In order to use External diff, \"diff\" command needs to be accessible.");
|
||||
if (HostOsInfo::isWindowsHost()) {
|
||||
diffWarning += QLatin1Char(' ');
|
||||
diffWarning.append(tr("DiffUtils is available for free download "
|
||||
"<a href=\"http://gnuwin32.sourceforge.net/packages/diffutils.htm\">here</a>. "
|
||||
"Please extract it to a directory in your PATH."));
|
||||
diffWarning.append(tr("DiffUtils is available for free download at"
|
||||
"http://gnuwin32.sourceforge.net/packages/diffutils.htm."
|
||||
"Extract it to a directory in your PATH."));
|
||||
}
|
||||
m_ui.diffWarningLabel->setText(diffWarning);
|
||||
m_ui.externalDiffRadioButton->setEnabled(false);
|
||||
|
@@ -244,7 +244,7 @@ CMakeRunConfigurationWidget::CMakeRunConfigurationWidget(CMakeRunConfiguration *
|
||||
m_workingDirectoryEdit->setPromptDialogTitle(tr("Select Working Directory"));
|
||||
|
||||
QToolButton *resetButton = new QToolButton();
|
||||
resetButton->setToolTip(tr("Reset to default."));
|
||||
resetButton->setToolTip(tr("Reset to Default"));
|
||||
resetButton->setIcon(QIcon(QLatin1String(Core::Constants::ICON_RESET)));
|
||||
|
||||
QHBoxLayout *boxlayout = new QHBoxLayout();
|
||||
|
@@ -664,6 +664,7 @@ IEditor *EditorManagerPrivate::openEditor(EditorView *view, const QString &fileN
|
||||
|
||||
overrideCursor.reset();
|
||||
delete editor;
|
||||
editor = 0;
|
||||
|
||||
if (openResult == IDocument::OpenResult::ReadError) {
|
||||
QMessageBox msgbox(QMessageBox::Critical, EditorManager::tr("File Error"),
|
||||
|
@@ -490,7 +490,8 @@ void ManhattanStyle::drawPrimitive(PrimitiveElement element, const QStyleOption
|
||||
QColor shadow(0, 0, 0, 30);
|
||||
painter->setPen(shadow);
|
||||
if (pressed) {
|
||||
QColor shade(0, 0, 0, 40);
|
||||
QColor shade = option->palette.base().color();
|
||||
shade.setHsv(shade.hue(), shade.saturation(), 255 - shade.value(), 40);
|
||||
painter->fillRect(rect, shade);
|
||||
painter->drawLine(rect.topLeft() + QPoint(1, 0), rect.topRight() - QPoint(1, 0));
|
||||
painter->drawLine(rect.topLeft(), rect.bottomLeft());
|
||||
|
@@ -176,8 +176,13 @@ public:
|
||||
return m_variable;
|
||||
}
|
||||
|
||||
if (role == Qt::ToolTipRole)
|
||||
return m_expander->variableDescription(m_variable.toUtf8());
|
||||
if (role == Qt::ToolTipRole) {
|
||||
QString description = m_expander->variableDescription(m_variable.toUtf8());
|
||||
const QString value = m_expander->value(m_variable.toUtf8()).toHtmlEscaped();
|
||||
if (!value.isEmpty())
|
||||
description += QLatin1String("<p>") + VariableChooser::tr("Current Value: %1").arg(value);
|
||||
return description;
|
||||
}
|
||||
|
||||
if (role == UnexpandedTextRole)
|
||||
return QString(QLatin1String("%{") + m_variable + QLatin1Char('}'));
|
||||
@@ -229,8 +234,8 @@ void VariableTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
||||
|
||||
void VariableTreeView::currentChanged(const QModelIndex ¤t, const QModelIndex &previous)
|
||||
{
|
||||
Q_UNUSED(previous);
|
||||
m_target->updateDescription(current);
|
||||
QTreeView::currentChanged(current, previous);
|
||||
}
|
||||
|
||||
VariableChooserPrivate::VariableChooserPrivate(VariableChooser *parent)
|
||||
@@ -250,6 +255,7 @@ VariableChooserPrivate::VariableChooserPrivate(VariableChooser *parent)
|
||||
m_variableDescription->setAlignment(Qt::AlignLeft|Qt::AlignTop);
|
||||
m_variableDescription->setWordWrap(true);
|
||||
m_variableDescription->setAttribute(Qt::WA_MacSmallSize);
|
||||
m_variableDescription->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
|
||||
QVBoxLayout *verticalLayout = new QVBoxLayout(q);
|
||||
verticalLayout->setContentsMargins(3, 3, 3, 12);
|
||||
|
@@ -28,42 +28,30 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Expected: 'i8' 'i64'
|
||||
* Unexpected: 'Priv' 'operator='
|
||||
*/
|
||||
|
||||
class Example
|
||||
#ifndef CODEPASTERSERVICE_H
|
||||
#define CODEPASTERSERVICE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
namespace CodePaster {
|
||||
|
||||
class Service
|
||||
{
|
||||
public:
|
||||
Example();
|
||||
~Example();
|
||||
virtual ~Service() {}
|
||||
|
||||
private:
|
||||
class Priv;
|
||||
Priv *d;
|
||||
virtual void postText(const QString &text, const QString &mimeType) = 0;
|
||||
virtual void postCurrentEditor() = 0;
|
||||
virtual void postClipboard() = 0;
|
||||
};
|
||||
|
||||
class Example::Priv
|
||||
{
|
||||
public:
|
||||
int i8;
|
||||
int i64;
|
||||
} // CodePaster
|
||||
|
||||
Priv() : i8(8), i64(64) {}
|
||||
};
|
||||
QT_BEGIN_NAMESPACE
|
||||
Q_DECLARE_INTERFACE(CodePaster::Service, "CodePaster::Service")
|
||||
QT_END_NAMESPACE
|
||||
|
||||
Example::Example()
|
||||
: d(new Example::Priv())
|
||||
{
|
||||
d-><<<<;
|
||||
}
|
||||
#endif // CODEPASTERSERVICE_H
|
||||
|
||||
Example::~Example()
|
||||
{
|
||||
}
|
||||
|
||||
void f()
|
||||
{
|
||||
Example w;
|
||||
}
|
@@ -13,7 +13,8 @@ HEADERS += cpasterplugin.h \
|
||||
fileshareprotocol.h \
|
||||
fileshareprotocolsettingspage.h \
|
||||
kdepasteprotocol.h \
|
||||
urlopenprotocol.h
|
||||
urlopenprotocol.h \
|
||||
codepasterservice.h
|
||||
|
||||
SOURCES += cpasterplugin.cpp \
|
||||
settingspage.cpp \
|
||||
|
@@ -70,32 +70,29 @@ using namespace TextEditor;
|
||||
namespace CodePaster {
|
||||
|
||||
/*!
|
||||
\class CodePaster::CodePasterService
|
||||
\brief The CodePasterService class is a service registered with PluginManager
|
||||
\class CodePaster::Service
|
||||
\brief The CodePaster::Service class is a service registered with PluginManager
|
||||
that provides CodePaster \c post() functionality.
|
||||
|
||||
\sa ExtensionSystem::PluginManager::getObjectByClassName, ExtensionSystem::invoke
|
||||
\sa VcsBase::VcsBaseEditorWidget
|
||||
*/
|
||||
|
||||
CodePasterService::CodePasterService(QObject *parent) :
|
||||
CodePasterServiceImpl::CodePasterServiceImpl(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void CodePasterService::postText(const QString &text, const QString &mimeType)
|
||||
void CodePasterServiceImpl::postText(const QString &text, const QString &mimeType)
|
||||
{
|
||||
QTC_ASSERT(CodepasterPlugin::instance(), return);
|
||||
CodepasterPlugin::instance()->post(text, mimeType);
|
||||
}
|
||||
|
||||
void CodePasterService::postCurrentEditor()
|
||||
void CodePasterServiceImpl::postCurrentEditor()
|
||||
{
|
||||
QTC_ASSERT(CodepasterPlugin::instance(), return);
|
||||
CodepasterPlugin::instance()->post(CodepasterPlugin::PasteEditor);
|
||||
}
|
||||
|
||||
void CodePasterService::postClipboard()
|
||||
void CodePasterServiceImpl::postClipboard()
|
||||
{
|
||||
QTC_ASSERT(CodepasterPlugin::instance(), return);
|
||||
CodepasterPlugin::instance()->post(CodepasterPlugin::PasteClipboard);
|
||||
@@ -176,7 +173,7 @@ bool CodepasterPlugin::initialize(const QStringList &arguments, QString *errorMe
|
||||
connect(m_fetchUrlAction, &QAction::triggered, this, &CodepasterPlugin::fetchUrl);
|
||||
cpContainer->addAction(command);
|
||||
|
||||
addAutoReleasedObject(new CodePasterService);
|
||||
addAutoReleasedObject(new CodePasterServiceImpl);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@@ -31,6 +31,8 @@
|
||||
#ifndef CPASTERPLUGIN_H
|
||||
#define CPASTERPLUGIN_H
|
||||
|
||||
#include "codepasterservice.h"
|
||||
|
||||
#include <extensionsystem/iplugin.h>
|
||||
|
||||
#include <QStringList>
|
||||
@@ -46,16 +48,17 @@ class CustomPoster;
|
||||
struct Settings;
|
||||
class Protocol;
|
||||
|
||||
class CodePasterService : public QObject
|
||||
class CodePasterServiceImpl : public QObject, public CodePaster::Service
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(CodePaster::Service)
|
||||
public:
|
||||
explicit CodePasterService(QObject *parent = 0);
|
||||
explicit CodePasterServiceImpl(QObject *parent = 0);
|
||||
|
||||
public slots:
|
||||
void postText(const QString &text, const QString &mimeType);
|
||||
void postCurrentEditor();
|
||||
void postClipboard();
|
||||
void postText(const QString &text, const QString &mimeType) override;
|
||||
void postCurrentEditor() override;
|
||||
void postClipboard() override;
|
||||
};
|
||||
|
||||
class CodepasterPlugin : public ExtensionSystem::IPlugin
|
||||
|
@@ -206,7 +206,7 @@ BreakpointDialog::BreakpointDialog(Breakpoint b, QWidget *parent)
|
||||
m_labelOneShot->setBuddy(m_checkBoxOneShot);
|
||||
|
||||
const QString pathToolTip =
|
||||
tr("<html><head/><body><p>Determines how the path is specified "
|
||||
tr("<p>Determines how the path is specified "
|
||||
"when setting breakpoints:</p><ul>"
|
||||
"<li><i>Use Engine Default</i>: Preferred setting of the "
|
||||
"debugger engine.</li>"
|
||||
@@ -217,8 +217,7 @@ BreakpointDialog::BreakpointDialog(Breakpoint b, QWidget *parent)
|
||||
"useful when using a source tree whose location does "
|
||||
"not match the one used when building the modules. "
|
||||
"It is the engine default for GDB as using full paths can "
|
||||
"be slow with this engine.</li>"
|
||||
"</ul></body></html>");
|
||||
"be slow with this engine.</li></ul>");
|
||||
m_comboBoxPathUsage = new QComboBox(groupBoxAdvanced);
|
||||
m_comboBoxPathUsage->addItem(tr("Use Engine Default"));
|
||||
m_comboBoxPathUsage->addItem(tr("Use Full Path"));
|
||||
@@ -229,8 +228,8 @@ BreakpointDialog::BreakpointDialog(Breakpoint b, QWidget *parent)
|
||||
m_labelUseFullPath->setToolTip(pathToolTip);
|
||||
|
||||
const QString moduleToolTip =
|
||||
tr("Specifying the module (base name of the library or executable)\n"
|
||||
"for function or file type breakpoints can significantly speed up\n"
|
||||
tr("<p>Specifying the module (base name of the library or executable) "
|
||||
"for function or file type breakpoints can significantly speed up "
|
||||
"debugger start-up times (CDB, LLDB).");
|
||||
m_lineEditModule = new QLineEdit(groupBoxAdvanced);
|
||||
m_lineEditModule->setToolTip(moduleToolTip);
|
||||
@@ -239,7 +238,7 @@ BreakpointDialog::BreakpointDialog(Breakpoint b, QWidget *parent)
|
||||
m_labelModule->setToolTip(moduleToolTip);
|
||||
|
||||
const QString commandsToolTip =
|
||||
tr("Debugger commands to be executed when the breakpoint is hit.\n"
|
||||
tr("<p>Debugger commands to be executed when the breakpoint is hit. "
|
||||
"This feature is only available for GDB.");
|
||||
m_textEditCommands = new SmallTextEdit(groupBoxAdvanced);
|
||||
m_textEditCommands->setToolTip(commandsToolTip);
|
||||
|
@@ -547,10 +547,6 @@ void CdbEngine::setupEngine()
|
||||
{
|
||||
if (debug)
|
||||
qDebug(">setupEngine");
|
||||
// Nag to add symbol server and cache
|
||||
QStringList symbolPaths = stringListSetting(CdbSymbolPaths);
|
||||
if (CdbSymbolPathListEditor::promptToAddSymbolPaths(&symbolPaths))
|
||||
action(CdbSymbolPaths)->setValue(symbolPaths);
|
||||
|
||||
init();
|
||||
if (!m_logTime.elapsed())
|
||||
@@ -1344,7 +1340,7 @@ void CdbEngine::doUpdateLocals(const UpdateParameters &updateParameters)
|
||||
return;
|
||||
}
|
||||
|
||||
watchHandler()->notifyUpdateStarted();
|
||||
watchHandler()->notifyUpdateStarted(updateParameters.partialVariables());
|
||||
|
||||
/* Watchers: Forcibly discard old symbol group as switching from
|
||||
* thread 0/frame 0 -> thread 1/assembly -> thread 0/frame 0 will otherwise re-use it
|
||||
@@ -1779,7 +1775,6 @@ void CdbEngine::handleRegistersExt(const CdbResponse &response)
|
||||
|
||||
void CdbEngine::handleLocals(const CdbResponse &response, bool partialUpdate)
|
||||
{
|
||||
watchHandler()->notifyUpdateFinished();
|
||||
if (response.success) {
|
||||
if (boolSetting(VerboseLog))
|
||||
showMessage(QLatin1String("Locals: ") + QString::fromLatin1(response.extensionReply), LogDebug);
|
||||
@@ -1800,6 +1795,7 @@ void CdbEngine::handleLocals(const CdbResponse &response, bool partialUpdate)
|
||||
} else {
|
||||
showMessage(QString::fromLatin1(response.errorMessage), LogWarning);
|
||||
}
|
||||
watchHandler()->notifyUpdateFinished();
|
||||
}
|
||||
|
||||
void CdbEngine::handleExpandLocals(const CdbResponse &response)
|
||||
@@ -2353,6 +2349,8 @@ void CdbEngine::handleExtensionMessage(char t, int token, const QByteArray &what
|
||||
}
|
||||
|
||||
if (what == "event") {
|
||||
if (message.startsWith("Process exited"))
|
||||
notifyInferiorExited();
|
||||
showStatusMessage(QString::fromLatin1(message), 5000);
|
||||
return;
|
||||
}
|
||||
|
@@ -177,7 +177,7 @@ DebuggerSettings::DebuggerSettings()
|
||||
item->setCheckable(true);
|
||||
item->setDefaultValue(false);
|
||||
item->setIcon(QIcon(QLatin1String(":/debugger/images/debugger_singleinstructionmode.png")));
|
||||
item->setToolTip(tr("This switches the debugger to instruction-wise "
|
||||
item->setToolTip(tr("<p>This switches the debugger to instruction-wise "
|
||||
"operation mode. In this mode, stepping operates on single "
|
||||
"instructions and the source location view also shows the "
|
||||
"disassembled instructions."));
|
||||
@@ -189,7 +189,7 @@ DebuggerSettings::DebuggerSettings()
|
||||
item->setCheckable(true);
|
||||
item->setDefaultValue(true);
|
||||
item->setIcon(QIcon(QLatin1String(Core::Constants::ICON_LINK)));
|
||||
item->setToolTip(tr("This switches the debugger to native-mixed "
|
||||
item->setToolTip(tr("<p>This switches the debugger to native-mixed "
|
||||
"operation mode. In this mode, stepping and data display will "
|
||||
"be handled by the native debugger backend (GDB, LLDB or CDB) "
|
||||
"for C++, QML and JS sources."));
|
||||
@@ -201,7 +201,7 @@ DebuggerSettings::DebuggerSettings()
|
||||
item->setCheckable(true);
|
||||
item->setDefaultValue(true);
|
||||
item->setSettingsKey(debugModeGroup, QLatin1String("AutoDerefPointers"));
|
||||
item->setToolTip(tr("This switches the Locals&&Watchers view to "
|
||||
item->setToolTip(tr("<p>This switches the Locals&&Watchers view to "
|
||||
"automatically dereference pointers. This saves a level in the "
|
||||
"tree view, but also loses data for the now-missing intermediate "
|
||||
"level."));
|
||||
@@ -262,7 +262,7 @@ DebuggerSettings::DebuggerSettings()
|
||||
item->setSettingsKey(debugModeGroup, QLatin1String("ShowStandardNamespace"));
|
||||
item->setText(tr("Show \"std::\" Namespace in Types"));
|
||||
item->setDialogText(tr("Show \"std::\" namespace in types"));
|
||||
item->setToolTip(tr("Shows \"std::\" prefix for types from the standard library."));
|
||||
item->setToolTip(tr("<p>Shows \"std::\" prefix for types from the standard library."));
|
||||
item->setCheckable(true);
|
||||
item->setDefaultValue(true);
|
||||
item->setValue(true);
|
||||
@@ -272,7 +272,7 @@ DebuggerSettings::DebuggerSettings()
|
||||
item->setSettingsKey(debugModeGroup, QLatin1String("ShowQtNamespace"));
|
||||
item->setText(tr("Show Qt's Namespace in Types"));
|
||||
item->setDialogText(tr("Show Qt's namespace in types"));
|
||||
item->setToolTip(tr("Shows Qt namespace prefix for Qt types. This is only "
|
||||
item->setToolTip(tr("<p>Shows Qt namespace prefix for Qt types. This is only "
|
||||
"relevant if Qt was configured with \"-qtnamespace\"."));
|
||||
item->setCheckable(true);
|
||||
item->setDefaultValue(true);
|
||||
@@ -302,7 +302,7 @@ DebuggerSettings::DebuggerSettings()
|
||||
item = new SavedAction(this);
|
||||
item->setSettingsKey(debugModeGroup, QLatin1String("UseCodeModel"));
|
||||
item->setDialogText(tr("Use code model"));
|
||||
item->setToolTip(tr("Selecting this causes the C++ Code Model being asked "
|
||||
item->setToolTip(tr("<p>Selecting this causes the C++ Code Model being asked "
|
||||
"for variable scope information. This might result in slightly faster "
|
||||
"debugger operation but may fail for optimized code."));
|
||||
item->setCheckable(true);
|
||||
@@ -312,7 +312,7 @@ DebuggerSettings::DebuggerSettings()
|
||||
|
||||
item = new SavedAction(this);
|
||||
item->setSettingsKey(debugModeGroup, QLatin1String("ShowThreadNames"));
|
||||
item->setToolTip(tr("Displays names of QThread based threads."));
|
||||
item->setToolTip(tr("<p>Displays names of QThread based threads."));
|
||||
item->setDialogText(tr("Display thread names"));
|
||||
item->setCheckable(true);
|
||||
item->setDefaultValue(false);
|
||||
@@ -329,7 +329,7 @@ DebuggerSettings::DebuggerSettings()
|
||||
|
||||
item = new SavedAction(this);
|
||||
item->setText(tr("Adjust Breakpoint Locations"));
|
||||
item->setToolTip(tr("Not all source code lines generate "
|
||||
item->setToolTip(tr("<p>Not all source code lines generate "
|
||||
"executable code. Putting a breakpoint on such a line acts as "
|
||||
"if the breakpoint was set on the next line that generated code. "
|
||||
"Selecting 'Adjust Breakpoint Locations' shifts the red "
|
||||
@@ -514,7 +514,7 @@ DebuggerSettings::DebuggerSettings()
|
||||
item = new SavedAction(this);
|
||||
item->setSettingsKey(debugModeGroup, QLatin1String("UseToolTips"));
|
||||
item->setText(tr("Use tooltips in main editor when debugging"));
|
||||
item->setToolTip(tr("Checking this will enable tooltips for variable "
|
||||
item->setToolTip(tr("<p>Checking this will enable tooltips for variable "
|
||||
"values during debugging. Since this can slow down debugging and "
|
||||
"does not provide reliable information as it does not use scope "
|
||||
"information, it is switched off by default."));
|
||||
@@ -525,7 +525,7 @@ DebuggerSettings::DebuggerSettings()
|
||||
item = new SavedAction(this);
|
||||
item->setSettingsKey(debugModeGroup, QLatin1String("UseToolTipsInLocalsView"));
|
||||
item->setText(tr("Use Tooltips in Locals View when Debugging"));
|
||||
item->setToolTip(tr("Checking this will enable tooltips in the locals "
|
||||
item->setToolTip(tr("<p>Checking this will enable tooltips in the locals "
|
||||
"view during debugging."));
|
||||
item->setCheckable(true);
|
||||
item->setDefaultValue(false);
|
||||
@@ -534,7 +534,7 @@ DebuggerSettings::DebuggerSettings()
|
||||
item = new SavedAction(this);
|
||||
item->setSettingsKey(debugModeGroup, QLatin1String("UseToolTipsInBreakpointsView"));
|
||||
item->setText(tr("Use Tooltips in Breakpoints View when Debugging"));
|
||||
item->setToolTip(tr("Checking this will enable tooltips in the breakpoints "
|
||||
item->setToolTip(tr("<p>Checking this will enable tooltips in the breakpoints "
|
||||
"view during debugging."));
|
||||
item->setCheckable(true);
|
||||
item->setDefaultValue(false);
|
||||
@@ -543,7 +543,7 @@ DebuggerSettings::DebuggerSettings()
|
||||
item = new SavedAction(this);
|
||||
item->setSettingsKey(debugModeGroup, QLatin1String("UseToolTipsInBreakpointsView"));
|
||||
item->setText(tr("Use Tooltips in Stack View when Debugging"));
|
||||
item->setToolTip(tr("Checking this will enable tooltips in the stack "
|
||||
item->setToolTip(tr("<p>Checking this will enable tooltips in the stack "
|
||||
"view during debugging."));
|
||||
item->setCheckable(true);
|
||||
item->setDefaultValue(true);
|
||||
@@ -552,7 +552,7 @@ DebuggerSettings::DebuggerSettings()
|
||||
item = new SavedAction(this);
|
||||
item->setSettingsKey(debugModeGroup, QLatin1String("UseAddressInBreakpointsView"));
|
||||
item->setText(tr("Show Address Data in Breakpoints View when Debugging"));
|
||||
item->setToolTip(tr("Checking this will show a column with address "
|
||||
item->setToolTip(tr("<p>Checking this will show a column with address "
|
||||
"information in the breakpoint view during debugging."));
|
||||
item->setCheckable(true);
|
||||
item->setDefaultValue(false);
|
||||
@@ -561,7 +561,7 @@ DebuggerSettings::DebuggerSettings()
|
||||
item = new SavedAction(this);
|
||||
item->setSettingsKey(debugModeGroup, QLatin1String("UseAddressInStackView"));
|
||||
item->setText(tr("Show Address Data in Stack View when Debugging"));
|
||||
item->setToolTip(tr("Checking this will show a column with address "
|
||||
item->setToolTip(tr("<p>Checking this will show a column with address "
|
||||
"information in the stack view during debugging."));
|
||||
item->setCheckable(true);
|
||||
item->setDefaultValue(false);
|
||||
@@ -624,7 +624,7 @@ DebuggerSettings::DebuggerSettings()
|
||||
|
||||
item = new SavedAction(this);
|
||||
item->setSettingsKey(debugModeGroup, QLatin1String("DisplayStringLimit"));
|
||||
item->setToolTip(tr("The maximum length of string entries in the "
|
||||
item->setToolTip(tr("<p>The maximum length of string entries in the "
|
||||
"Locals and Expressions pane. Longer than that are cut off "
|
||||
"and displayed with an ellipsis attached."));
|
||||
item->setDefaultValue(100);
|
||||
@@ -632,7 +632,7 @@ DebuggerSettings::DebuggerSettings()
|
||||
|
||||
item = new SavedAction(this);
|
||||
item->setSettingsKey(debugModeGroup, QLatin1String("MaximalStringLength"));
|
||||
item->setToolTip(tr("The maximum length for strings in separated windows. "
|
||||
item->setToolTip(tr("<p>The maximum length for strings in separated windows. "
|
||||
"Longer strings are cut off and displayed with an ellipsis attached."));
|
||||
item->setDefaultValue(10000);
|
||||
insertItem(MaximalStringLength, item);
|
||||
|
@@ -136,36 +136,36 @@ enum DebuggerCloseMode
|
||||
|
||||
enum DebuggerCapabilities
|
||||
{
|
||||
ReverseSteppingCapability = 0x1,
|
||||
SnapshotCapability = 0x2,
|
||||
AutoDerefPointersCapability = 0x4,
|
||||
DisassemblerCapability = 0x8,
|
||||
RegisterCapability = 0x10,
|
||||
ShowMemoryCapability = 0x20,
|
||||
JumpToLineCapability = 0x40,
|
||||
ReloadModuleCapability = 0x80,
|
||||
ReloadModuleSymbolsCapability = 0x100,
|
||||
BreakOnThrowAndCatchCapability = 0x200,
|
||||
BreakConditionCapability = 0x400, //!< Conditional Breakpoints
|
||||
BreakModuleCapability = 0x800, //!< Breakpoint specification includes module
|
||||
TracePointCapability = 0x1000,
|
||||
ReturnFromFunctionCapability = 0x2000,
|
||||
CreateFullBacktraceCapability = 0x4000,
|
||||
AddWatcherCapability = 0x8000,
|
||||
AddWatcherWhileRunningCapability = 0x10000,
|
||||
WatchWidgetsCapability = 0x20000,
|
||||
WatchpointByAddressCapability = 0x40000,
|
||||
WatchpointByExpressionCapability = 0x80000,
|
||||
ShowModuleSymbolsCapability = 0x100000,
|
||||
CatchCapability = 0x200000, //!< fork, vfork, syscall
|
||||
OperateByInstructionCapability = 0x400000,
|
||||
RunToLineCapability = 0x800000,
|
||||
MemoryAddressCapability = 0x1000000,
|
||||
ShowModuleSectionsCapability = 0x200000,
|
||||
WatchComplexExpressionsCapability = 0x400000, // Used to filter out challenges for cdb.
|
||||
AdditionalQmlStackCapability = 0x800000, // C++ debugger engine is able to retrieve QML stack as well.
|
||||
ResetInferiorCapability = 0x1000000, //!< restart program while debugging
|
||||
NativeMixedCapability = 0x2000000
|
||||
ReverseSteppingCapability = 1 << 0,
|
||||
SnapshotCapability = 1 << 1,
|
||||
AutoDerefPointersCapability = 1 << 2,
|
||||
DisassemblerCapability = 1 << 3,
|
||||
RegisterCapability = 1 << 4,
|
||||
ShowMemoryCapability = 1 << 5,
|
||||
JumpToLineCapability = 1 << 6,
|
||||
ReloadModuleCapability = 1 << 7,
|
||||
ReloadModuleSymbolsCapability = 1 << 8,
|
||||
BreakOnThrowAndCatchCapability = 1 << 9,
|
||||
BreakConditionCapability = 1 << 10, //!< Conditional Breakpoints
|
||||
BreakModuleCapability = 1 << 11, //!< Breakpoint specification includes module
|
||||
TracePointCapability = 1 << 12,
|
||||
ReturnFromFunctionCapability = 1 << 13,
|
||||
CreateFullBacktraceCapability = 1 << 14,
|
||||
AddWatcherCapability = 1 << 15,
|
||||
AddWatcherWhileRunningCapability = 1 << 16,
|
||||
WatchWidgetsCapability = 1 << 17,
|
||||
WatchpointByAddressCapability = 1 << 18,
|
||||
WatchpointByExpressionCapability = 1 << 19,
|
||||
ShowModuleSymbolsCapability = 1 << 20,
|
||||
CatchCapability = 1 << 21, //!< fork, vfork, syscall
|
||||
OperateByInstructionCapability = 1 << 22,
|
||||
RunToLineCapability = 1 << 23,
|
||||
MemoryAddressCapability = 1 << 24,
|
||||
ShowModuleSectionsCapability = 1 << 25,
|
||||
WatchComplexExpressionsCapability = 1 << 26, // Used to filter out challenges for cdb.
|
||||
AdditionalQmlStackCapability = 1 << 27, //!< C++ debugger engine is able to retrieve QML stack as well.
|
||||
ResetInferiorCapability = 1 << 28, //!< restart program while debugging
|
||||
NativeMixedCapability = 1 << 29
|
||||
};
|
||||
|
||||
enum LogChannel
|
||||
|
@@ -1944,12 +1944,6 @@ void DebuggerEngine::updateLocalsView(const GdbMi &all)
|
||||
}
|
||||
}
|
||||
|
||||
QSet<QByteArray> toDelete;
|
||||
if (!partial) {
|
||||
foreach (WatchItem *item, handler->model()->itemsAtLevel<WatchItem *>(2))
|
||||
toDelete.insert(item->iname);
|
||||
}
|
||||
|
||||
GdbMi data = all["data"];
|
||||
foreach (const GdbMi &child, data.children()) {
|
||||
WatchItem *item = new WatchItem(child);
|
||||
@@ -1958,7 +1952,6 @@ void DebuggerEngine::updateLocalsView(const GdbMi &all)
|
||||
item->size = ti.size;
|
||||
|
||||
handler->insertItem(item);
|
||||
toDelete.remove(item->iname);
|
||||
}
|
||||
|
||||
GdbMi ns = all["qtnamespace"];
|
||||
@@ -1967,8 +1960,6 @@ void DebuggerEngine::updateLocalsView(const GdbMi &all)
|
||||
showMessage(_("FOUND NAMESPACED QT: " + ns.data()));
|
||||
}
|
||||
|
||||
handler->purgeOutdatedItems(toDelete);
|
||||
|
||||
static int count = 0;
|
||||
showMessage(_("<Rebuild Watchmodel %1 @ %2 >")
|
||||
.arg(++count).arg(LogWindow::logTimeStamp()), LogMiscInput);
|
||||
|
@@ -120,6 +120,14 @@ class UpdateParameters
|
||||
public:
|
||||
UpdateParameters() {}
|
||||
|
||||
QList<QByteArray> partialVariables() const
|
||||
{
|
||||
QList<QByteArray> result;
|
||||
if (!partialVariable.isEmpty())
|
||||
result.append(partialVariable);
|
||||
return result;
|
||||
}
|
||||
|
||||
QByteArray partialVariable;
|
||||
};
|
||||
|
||||
|
@@ -210,7 +210,7 @@ DebuggerSourcePathMappingWidget::DebuggerSourcePathMappingWidget(QWidget *parent
|
||||
m_targetChooser(new PathChooser(this))
|
||||
{
|
||||
setTitle(tr("Source Paths Mapping"));
|
||||
setToolTip(tr("<html><head/><body><p>Mappings of source file folders to "
|
||||
setToolTip(tr("<p>Mappings of source file folders to "
|
||||
"be used in the debugger can be entered here.</p>"
|
||||
"<p>This is useful when using a copy of the source tree "
|
||||
"at a location different from the one "
|
||||
@@ -220,8 +220,7 @@ DebuggerSourcePathMappingWidget::DebuggerSourcePathMappingWidget(QWidget *parent
|
||||
"open parenthesis, Qt Creator matches the paths in the ELF with the "
|
||||
"regular expression to automatically determine the source path.</p>"
|
||||
"<p>Example: <b>(/home/.*/Project)/KnownSubDir -> D:\\Project</b> will "
|
||||
"substitute ELF built by any user to your local project directory.</p>"
|
||||
"</body></html>"));
|
||||
"substitute ELF built by any user to your local project directory.</p>"));
|
||||
// Top list/left part.
|
||||
m_treeView->setRootIsDecorated(false);
|
||||
m_treeView->setUniformRowHeights(true);
|
||||
@@ -236,7 +235,7 @@ DebuggerSourcePathMappingWidget::DebuggerSourcePathMappingWidget(QWidget *parent
|
||||
buttonLayout->addWidget(m_addButton);
|
||||
buttonLayout->addWidget(m_addQtButton);
|
||||
m_addQtButton->setVisible(sizeof(qtBuildPaths) > 0);
|
||||
m_addQtButton->setToolTip(tr("Add a mapping for Qt's source folders "
|
||||
m_addQtButton->setToolTip(tr("<p>Add a mapping for Qt's source folders "
|
||||
"when using an unpatched version of Qt."));
|
||||
buttonLayout->addWidget(m_removeButton);
|
||||
connect(m_addButton, &QAbstractButton::clicked,
|
||||
@@ -260,7 +259,7 @@ DebuggerSourcePathMappingWidget::DebuggerSourcePathMappingWidget(QWidget *parent
|
||||
connect(m_targetChooser, &PathChooser::changed,
|
||||
this, &DebuggerSourcePathMappingWidget::slotEditTargetFieldChanged);
|
||||
auto editLayout = new QFormLayout;
|
||||
const QString sourceToolTip = tr("The source path contained in the "
|
||||
const QString sourceToolTip = tr("<p>The source path contained in the "
|
||||
"debug information of the executable as reported by the debugger");
|
||||
auto editSourceLabel = new QLabel(tr("&Source path:"));
|
||||
editSourceLabel->setToolTip(sourceToolTip);
|
||||
@@ -268,7 +267,7 @@ DebuggerSourcePathMappingWidget::DebuggerSourcePathMappingWidget(QWidget *parent
|
||||
editSourceLabel->setBuddy(m_sourceLineEdit);
|
||||
editLayout->addRow(editSourceLabel, m_sourceLineEdit);
|
||||
|
||||
const QString targetToolTip = tr("The actual location of the source "
|
||||
const QString targetToolTip = tr("<p>The actual location of the source "
|
||||
"tree on the local machine");
|
||||
auto editTargetLabel = new QLabel(tr("&Target path:"));
|
||||
editTargetLabel->setToolTip(targetToolTip);
|
||||
|
@@ -240,6 +240,7 @@ GdbEngine::GdbEngine(const DebuggerRunParameters &startParameters)
|
||||
m_terminalTrap = startParameters.useTerminal;
|
||||
m_fullStartDone = false;
|
||||
m_systemDumpersLoaded = false;
|
||||
m_rerunPending = false;
|
||||
|
||||
m_debugInfoTaskHandler = new DebugInfoTaskHandler(this);
|
||||
//ExtensionSystem::PluginManager::addObject(m_debugInfoTaskHandler);
|
||||
@@ -1972,8 +1973,12 @@ void GdbEngine::handleThreadGroupCreated(const GdbMi &result)
|
||||
void GdbEngine::handleThreadGroupExited(const GdbMi &result)
|
||||
{
|
||||
QByteArray groupId = result["id"].data();
|
||||
if (threadsHandler()->notifyGroupExited(groupId))
|
||||
notifyInferiorExited();
|
||||
if (threadsHandler()->notifyGroupExited(groupId)) {
|
||||
if (m_rerunPending)
|
||||
m_rerunPending = false;
|
||||
else
|
||||
notifyInferiorExited();
|
||||
}
|
||||
}
|
||||
|
||||
int GdbEngine::currentFrame() const
|
||||
@@ -4322,6 +4327,7 @@ void GdbEngine::resetInferior()
|
||||
}
|
||||
}
|
||||
}
|
||||
m_rerunPending = true;
|
||||
requestInterruptInferior();
|
||||
runEngine();
|
||||
}
|
||||
@@ -4660,7 +4666,7 @@ void GdbEngine::doUpdateLocals(const UpdateParameters ¶ms)
|
||||
{
|
||||
m_pendingBreakpointRequests = 0;
|
||||
|
||||
watchHandler()->notifyUpdateStarted();
|
||||
watchHandler()->notifyUpdateStarted(params.partialVariables());
|
||||
|
||||
DebuggerCommand cmd("showData");
|
||||
watchHandler()->appendFormatRequests(&cmd);
|
||||
@@ -4716,7 +4722,6 @@ void GdbEngine::doUpdateLocals(const UpdateParameters ¶ms)
|
||||
|
||||
void GdbEngine::handleStackFrame(const DebuggerResponse &response)
|
||||
{
|
||||
watchHandler()->notifyUpdateFinished();
|
||||
if (response.resultClass == ResultDone) {
|
||||
QByteArray out = response.consoleStreamOutput;
|
||||
while (out.endsWith(' ') || out.endsWith('\n'))
|
||||
@@ -4735,6 +4740,7 @@ void GdbEngine::handleStackFrame(const DebuggerResponse &response)
|
||||
} else {
|
||||
showMessage(_("DUMPER FAILED: " + response.toString()));
|
||||
}
|
||||
watchHandler()->notifyUpdateFinished();
|
||||
}
|
||||
|
||||
QString GdbEngine::msgPtraceError(DebuggerStartMode sm)
|
||||
|
@@ -211,6 +211,7 @@ private:
|
||||
CommandsDoneCallback m_commandsDoneCallback;
|
||||
|
||||
QList<DebuggerCommand> m_commandsToRunOnTemporaryBreak;
|
||||
bool m_rerunPending;
|
||||
|
||||
private: ////////// Gdb Output, State & Capability Handling //////////
|
||||
protected:
|
||||
|
@@ -447,8 +447,8 @@ void LldbEngine::handleResponse(const QByteArray &response)
|
||||
foreach (const GdbMi &item, all.children()) {
|
||||
const QByteArray name = item.name();
|
||||
if (name == "all") {
|
||||
watchHandler()->notifyUpdateFinished();
|
||||
updateLocalsView(item);
|
||||
watchHandler()->notifyUpdateFinished();
|
||||
} else if (name == "dumpers") {
|
||||
watchHandler()->addDumpers(item);
|
||||
setupInferiorStage2();
|
||||
@@ -864,7 +864,7 @@ void LldbEngine::doUpdateLocals(const UpdateParameters ¶ms)
|
||||
return;
|
||||
}
|
||||
|
||||
watchHandler()->notifyUpdateStarted();
|
||||
watchHandler()->notifyUpdateStarted(params.partialVariables());
|
||||
|
||||
DebuggerCommand cmd("updateData");
|
||||
cmd.arg("nativeMixed", isNativeMixedActive());
|
||||
|
@@ -572,17 +572,10 @@ void PdbEngine::refreshLocals(const GdbMi &vars)
|
||||
WatchHandler *handler = watchHandler();
|
||||
handler->resetValueCache();
|
||||
|
||||
QSet<QByteArray> toDelete;
|
||||
foreach (WatchItem *item, handler->model()->itemsAtLevel<WatchItem *>(2))
|
||||
toDelete.insert(item->iname);
|
||||
foreach (const GdbMi &child, vars.children())
|
||||
handler->insertItem(new WatchItem(child));
|
||||
|
||||
foreach (const GdbMi &child, vars.children()) {
|
||||
WatchItem *item = new WatchItem(child);
|
||||
handler->insertItem(item);
|
||||
toDelete.remove(item->iname);
|
||||
}
|
||||
|
||||
handler->purgeOutdatedItems(toDelete);
|
||||
handler->notifyUpdateFinished();
|
||||
|
||||
DebuggerToolTipManager::updateEngine(this);
|
||||
}
|
||||
|
@@ -1003,7 +1003,10 @@ void QmlEngine::updateWatchData(const QByteArray &iname)
|
||||
// qDebug() << "UPDATE WATCH DATA" << data.toString();
|
||||
//showStatusMessage(tr("Stopped."), 5000);
|
||||
const WatchItem *item = watchHandler()->findItem(iname);
|
||||
QTC_ASSERT(item, return);
|
||||
// invalid expressions or out of scope variables
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
if (item->isInspect()) {
|
||||
m_inspectorAdapter.agent()->updateWatchData(*item);
|
||||
} else {
|
||||
|
@@ -1443,6 +1443,7 @@ void QmlV8DebuggerClient::setCurrentFrameDetails(const QVariant &bodyVal, const
|
||||
|
||||
StackHandler *stackHandler = d->engine->stackHandler();
|
||||
WatchHandler * watchHandler = d->engine->watchHandler();
|
||||
watchHandler->notifyUpdateStarted();
|
||||
d->clearCache();
|
||||
|
||||
const int frameIndex = stackHandler->currentIndex();
|
||||
@@ -1454,7 +1455,6 @@ void QmlV8DebuggerClient::setCurrentFrameDetails(const QVariant &bodyVal, const
|
||||
if (item && item->isLocal())
|
||||
handlesToLookup.insert(item->id, iname);
|
||||
}
|
||||
watchHandler->removeAllData();
|
||||
if (frameIndex < 0)
|
||||
return;
|
||||
const StackFrame frame = stackHandler->currentFrame();
|
||||
@@ -1556,6 +1556,8 @@ void QmlV8DebuggerClient::updateScope(const QVariant &bodyVal, const QVariant &r
|
||||
|
||||
if (!handlesToLookup.isEmpty())
|
||||
d->lookup(handlesToLookup);
|
||||
else
|
||||
d->engine->watchHandler()->notifyUpdateFinished();
|
||||
}
|
||||
|
||||
QmlJS::ConsoleItem *constructLogItemTree(QmlJS::ConsoleItem *parent,
|
||||
@@ -1702,6 +1704,7 @@ void QmlV8DebuggerClient::expandLocalsAndWatchers(const QVariant &bodyVal, const
|
||||
d->engine->watchHandler()->insertItem(item);
|
||||
}
|
||||
}
|
||||
d->engine->watchHandler()->notifyUpdateFinished();
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::createWatchDataList(const WatchItem *parent,
|
||||
|
@@ -134,6 +134,11 @@ CdbSymbolPathListEditor::CdbSymbolPathListEditor(QWidget *parent) :
|
||||
addSymbolPath(SymbolCachePath);
|
||||
});
|
||||
button->setToolTip(tr("Uses a directory to cache symbols used by the debugger."));
|
||||
|
||||
button = insertButton(lastInsertButtonIndex + 1, tr("Setup Symbol Paths..."), this, [this](){
|
||||
setupSymbolPaths();
|
||||
});
|
||||
button->setToolTip(tr("Configure Symbol paths that are used to locate debug symbol files."));
|
||||
}
|
||||
|
||||
bool CdbSymbolPathListEditor::promptCacheDirectory(QWidget *parent, QString *cacheDirectory)
|
||||
@@ -153,6 +158,37 @@ void CdbSymbolPathListEditor::addSymbolPath(CdbSymbolPathListEditor::SymbolPathM
|
||||
insertPathAtCursor(CdbSymbolPathListEditor::symbolPath(cacheDir, mode));
|
||||
}
|
||||
|
||||
void CdbSymbolPathListEditor::setupSymbolPaths()
|
||||
{
|
||||
const QStringList ¤tPaths = pathList();
|
||||
const int indexOfSymbolServer = indexOfSymbolPath(currentPaths, SymbolServerPath);
|
||||
const int indexOfSymbolCache = indexOfSymbolPath(currentPaths, SymbolCachePath);
|
||||
|
||||
QString path;
|
||||
if (indexOfSymbolServer != -1)
|
||||
path = currentPaths.at(indexOfSymbolServer);
|
||||
if (path.isEmpty() && indexOfSymbolCache != -1)
|
||||
path = currentPaths.at(indexOfSymbolCache);
|
||||
if (path.isEmpty())
|
||||
path = QDir::tempPath() + QDir::separator() + QLatin1String("symbolcache");
|
||||
|
||||
bool useSymbolServer = true;
|
||||
bool useSymbolCache = true;
|
||||
bool addSymbolPaths = SymbolPathsDialog::useCommonSymbolPaths(useSymbolCache,
|
||||
useSymbolServer,
|
||||
path);
|
||||
if (!addSymbolPaths)
|
||||
return;
|
||||
|
||||
if (useSymbolCache) {
|
||||
insertPathAtCursor(CdbSymbolPathListEditor::symbolPath(path, SymbolCachePath));
|
||||
if (useSymbolServer)
|
||||
insertPathAtCursor(CdbSymbolPathListEditor::symbolPath(QString(), SymbolServerPath));
|
||||
} else if (useSymbolServer) {
|
||||
insertPathAtCursor(CdbSymbolPathListEditor::symbolPath(path, SymbolServerPath));
|
||||
}
|
||||
}
|
||||
|
||||
QString CdbSymbolPathListEditor::symbolPath(const QString &cacheDir,
|
||||
CdbSymbolPathListEditor::SymbolPathMode mode)
|
||||
{
|
||||
@@ -207,61 +243,5 @@ int CdbSymbolPathListEditor::indexOfSymbolPath(const QStringList &paths,
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool CdbSymbolPathListEditor::promptToAddSymbolPaths(QStringList *symbolPaths)
|
||||
{
|
||||
const int indexOfSymbolServer =
|
||||
CdbSymbolPathListEditor::indexOfSymbolPath(*symbolPaths, SymbolServerPath);
|
||||
const int indexOfSymbolCache =
|
||||
CdbSymbolPathListEditor::indexOfSymbolPath(*symbolPaths, SymbolCachePath);
|
||||
|
||||
if (!qgetenv("_NT_SYMBOL_PATH").isEmpty()
|
||||
|| (indexOfSymbolServer != -1 && indexOfSymbolCache != -1))
|
||||
return false;
|
||||
|
||||
const QString nagSymbolServerKey = QLatin1String("CDB2/NoPromptSymbolCache");
|
||||
bool noFurtherNagging = Core::ICore::settings()->value(nagSymbolServerKey, false).toBool();
|
||||
if (noFurtherNagging)
|
||||
return false;
|
||||
|
||||
QString path;
|
||||
if (indexOfSymbolServer != -1)
|
||||
path = symbolPaths->at(indexOfSymbolServer);
|
||||
if (path.isEmpty() && indexOfSymbolCache != -1)
|
||||
path = symbolPaths->at(indexOfSymbolCache);
|
||||
if (path.isEmpty())
|
||||
path = QDir::tempPath() + QDir::separator() + QLatin1String("symbolcache");
|
||||
|
||||
bool useSymbolServer = true;
|
||||
bool useSymbolCache = true;
|
||||
bool addSymbolPaths = SymbolPathsDialog::useCommonSymbolPaths(useSymbolCache,
|
||||
useSymbolServer,
|
||||
path, noFurtherNagging);
|
||||
Core::ICore::settings()->setValue(nagSymbolServerKey, noFurtherNagging);
|
||||
if (!addSymbolPaths)
|
||||
return false;
|
||||
|
||||
// remove old entries
|
||||
if (indexOfSymbolServer > indexOfSymbolCache) {
|
||||
symbolPaths->removeAt(indexOfSymbolServer);
|
||||
if (indexOfSymbolCache != -1)
|
||||
symbolPaths->removeAt(indexOfSymbolCache);
|
||||
} else if (indexOfSymbolCache > indexOfSymbolServer) {
|
||||
symbolPaths->removeAt(indexOfSymbolCache);
|
||||
if (indexOfSymbolServer != -1)
|
||||
symbolPaths->removeAt(indexOfSymbolServer);
|
||||
}
|
||||
|
||||
if (useSymbolCache) {
|
||||
symbolPaths->push_back(CdbSymbolPathListEditor::symbolPath(path, SymbolCachePath));
|
||||
if (useSymbolServer)
|
||||
symbolPaths->push_back(CdbSymbolPathListEditor::symbolPath(QString(), SymbolServerPath));
|
||||
return true;
|
||||
} else if (useSymbolServer) {
|
||||
symbolPaths->push_back(CdbSymbolPathListEditor::symbolPath(path, SymbolServerPath));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Debugger
|
||||
|
@@ -93,11 +93,9 @@ public:
|
||||
// Check for symbol server in list of paths.
|
||||
static int indexOfSymbolPath(const QStringList &paths, SymbolPathMode mode, QString *cacheDir = 0);
|
||||
|
||||
// Nag user to add a symbol cache and server to the path list on debugger startup.
|
||||
static bool promptToAddSymbolPaths(QStringList *symbolPaths);
|
||||
|
||||
private:
|
||||
void addSymbolPath(SymbolPathMode mode);
|
||||
void setupSymbolPaths();
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -64,11 +64,6 @@ QString SymbolPathsDialog::path() const
|
||||
return ui->pathChooser->path();
|
||||
}
|
||||
|
||||
bool SymbolPathsDialog::doNotAskAgain() const
|
||||
{
|
||||
return ui->doNotAskAgain->isChecked();
|
||||
}
|
||||
|
||||
void SymbolPathsDialog::setUseSymbolCache(bool useSymbolCache)
|
||||
{
|
||||
ui->useLocalSymbolCache->setChecked(useSymbolCache);
|
||||
@@ -84,23 +79,16 @@ void SymbolPathsDialog::setPath(const QString &path)
|
||||
ui->pathChooser->setPath(path);
|
||||
}
|
||||
|
||||
void SymbolPathsDialog::setDoNotAskAgain(bool doNotAskAgain) const
|
||||
{
|
||||
ui->doNotAskAgain->setChecked(doNotAskAgain);
|
||||
}
|
||||
|
||||
bool SymbolPathsDialog::useCommonSymbolPaths(bool &useSymbolCache, bool &useSymbolServer,
|
||||
QString &path, bool &doNotAskAgain)
|
||||
QString &path)
|
||||
{
|
||||
SymbolPathsDialog dialog;
|
||||
dialog.setUseSymbolCache(useSymbolCache);
|
||||
dialog.setUseSymbolServer(useSymbolServer);
|
||||
dialog.setPath(path);
|
||||
dialog.setDoNotAskAgain(doNotAskAgain);
|
||||
int ret = dialog.exec();
|
||||
useSymbolCache = dialog.useSymbolCache();
|
||||
useSymbolServer = dialog.useSymbolServer();
|
||||
path = dialog.path();
|
||||
doNotAskAgain = dialog.doNotAskAgain();
|
||||
return ret == QDialog::Accepted;
|
||||
}
|
||||
|
@@ -57,7 +57,7 @@ public:
|
||||
void setPath(const QString &path);
|
||||
void setDoNotAskAgain(bool doNotAskAgain) const;
|
||||
|
||||
static bool useCommonSymbolPaths(bool &useSymbolCache, bool &useSymbolServer, QString &path, bool &doNotAskAgain);
|
||||
static bool useCommonSymbolPaths(bool &useSymbolCache, bool &useSymbolServer, QString &path);
|
||||
|
||||
private:
|
||||
Ui::SymbolPathsDialog *ui;
|
||||
|
@@ -7,11 +7,11 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>537</width>
|
||||
<height>245</height>
|
||||
<height>249</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
<string>Set up Symbol Paths</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
@@ -73,23 +73,6 @@
|
||||
<item>
|
||||
<widget class="Utils::PathChooser" name="pathChooser" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="doNotAskAgain">
|
||||
<property name="text">
|
||||
<string>Do not ask again</string>
|
||||
</property>
|
||||
<property name="tristate">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
|
@@ -131,7 +131,8 @@ WatchData::WatchData() :
|
||||
elided(0),
|
||||
wantsChildren(false),
|
||||
valueEnabled(true),
|
||||
valueEditable(true)
|
||||
valueEditable(true),
|
||||
outdated(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@@ -119,6 +119,7 @@ public:
|
||||
bool wantsChildren;
|
||||
bool valueEnabled; // Value will be enabled or not
|
||||
bool valueEditable; // Value will be editable
|
||||
bool outdated; // \internal item is to be removed.
|
||||
|
||||
Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::WatchHandler)
|
||||
};
|
||||
|
@@ -1221,8 +1221,20 @@ void WatchHandler::resetWatchers()
|
||||
loadSessionData();
|
||||
}
|
||||
|
||||
void WatchHandler::notifyUpdateStarted()
|
||||
void WatchHandler::notifyUpdateStarted(const QList<QByteArray> &inames)
|
||||
{
|
||||
auto marker = [](TreeItem *it) { static_cast<WatchItem *>(it)->outdated = true; };
|
||||
|
||||
if (inames.isEmpty()) {
|
||||
foreach (auto item, m_model->itemsAtLevel<WatchItem *>(2))
|
||||
item->walkTree(marker);
|
||||
} else {
|
||||
foreach (auto iname, inames) {
|
||||
if (WatchItem *item = m_model->findItem(iname))
|
||||
item->walkTree(marker);
|
||||
}
|
||||
}
|
||||
|
||||
m_model->m_requestUpdateTimer.start(80);
|
||||
m_model->m_contentsValid = false;
|
||||
updateWatchersWindow();
|
||||
@@ -1230,25 +1242,32 @@ void WatchHandler::notifyUpdateStarted()
|
||||
|
||||
void WatchHandler::notifyUpdateFinished()
|
||||
{
|
||||
struct OutDatedItemsFinder : public TreeItemVisitor
|
||||
{
|
||||
bool preVisit(TreeItem *item)
|
||||
{
|
||||
auto watchItem = static_cast<WatchItem *>(item);
|
||||
if (level() <= 1 || !watchItem->outdated)
|
||||
return true;
|
||||
toRemove.append(watchItem);
|
||||
return false;
|
||||
}
|
||||
|
||||
QList<WatchItem *> toRemove;
|
||||
} finder;
|
||||
|
||||
m_model->root()->walkTree(&finder);
|
||||
|
||||
foreach (auto item, finder.toRemove)
|
||||
delete m_model->takeItem(item);
|
||||
|
||||
m_model->m_contentsValid = true;
|
||||
updateWatchersWindow();
|
||||
m_model->reexpandItems();
|
||||
m_model->m_requestUpdateTimer.stop();
|
||||
emit m_model->updateFinished();
|
||||
}
|
||||
|
||||
void WatchHandler::purgeOutdatedItems(const QSet<QByteArray> &inames)
|
||||
{
|
||||
foreach (const QByteArray &iname, inames) {
|
||||
WatchItem *item = findItem(iname);
|
||||
delete m_model->takeItem(item);
|
||||
}
|
||||
|
||||
m_model->layoutChanged();
|
||||
m_model->reexpandItems();
|
||||
m_model->m_contentsValid = true;
|
||||
updateWatchersWindow();
|
||||
}
|
||||
|
||||
void WatchHandler::removeItemByIName(const QByteArray &iname)
|
||||
{
|
||||
WatchItem *item = m_model->findItem(iname);
|
||||
|
@@ -197,9 +197,9 @@ public:
|
||||
void removeAllData(bool includeInspectData = false);
|
||||
void resetValueCache();
|
||||
void resetWatchers();
|
||||
void notifyUpdateStarted();
|
||||
|
||||
void notifyUpdateStarted(const QList<QByteArray> &inames = {});
|
||||
void notifyUpdateFinished();
|
||||
void purgeOutdatedItems(const QSet<QByteArray> &inames);
|
||||
|
||||
private:
|
||||
WatchModel *m_model; // Owned.
|
||||
|
@@ -9,6 +9,10 @@ QtcPlugin {
|
||||
Depends { name: "Core" }
|
||||
Depends { name: "TextEditor" }
|
||||
|
||||
pluginRecommends: [
|
||||
"CodePaster"
|
||||
]
|
||||
|
||||
files: [
|
||||
"diffeditor.cpp",
|
||||
"diffeditor.h",
|
||||
|
@@ -5,3 +5,5 @@ QTC_LIB_DEPENDS += \
|
||||
QTC_PLUGIN_DEPENDS += \
|
||||
texteditor \
|
||||
coreplugin
|
||||
QTC_PLUGIN_RECOMMENDS += \
|
||||
cpaster
|
||||
|
@@ -147,8 +147,11 @@ QString DiffEditorController::prepareBranchesForCommit(const QString &output)
|
||||
moreBranches = QLatin1Char(' ') + tr("and %n more", 0, branchCount - leave);
|
||||
res.erase(res.begin() + leave, res.end());
|
||||
}
|
||||
if (!res.isEmpty())
|
||||
branches = (QLatin1String("Branches: ") + res.join(QLatin1String(", ")) + moreBranches);
|
||||
branches = QLatin1String("Branches: ");
|
||||
if (res.isEmpty())
|
||||
branches += tr("<None>");
|
||||
else
|
||||
branches += res.join(QLatin1String(", ")) + moreBranches;
|
||||
|
||||
return branches;
|
||||
}
|
||||
|
@@ -56,8 +56,11 @@
|
||||
#include <coreplugin/minisplitter.h>
|
||||
#include <coreplugin/patchtool.h>
|
||||
|
||||
#include <cpaster/codepasterservice.h>
|
||||
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/tooltip/tooltip.h>
|
||||
|
||||
using namespace Core;
|
||||
@@ -894,11 +897,14 @@ void SideBySideDiffEditorWidget::slotLeftContextMenuRequested(QMenu *menu,
|
||||
int chunkIndex)
|
||||
{
|
||||
menu->addSeparator();
|
||||
QAction *sendChunkToCodePasterAction =
|
||||
menu->addAction(tr("Send Chunk to CodePaster..."));
|
||||
connect(sendChunkToCodePasterAction, &QAction::triggered,
|
||||
this, &SideBySideDiffEditorWidget::slotSendChunkToCodePaster);
|
||||
menu->addSeparator();
|
||||
if (ExtensionSystem::PluginManager::getObject<CodePaster::Service>()) {
|
||||
// optional code pasting service
|
||||
QAction *sendChunkToCodePasterAction =
|
||||
menu->addAction(tr("Send Chunk to CodePaster..."));
|
||||
connect(sendChunkToCodePasterAction, &QAction::triggered,
|
||||
this, &SideBySideDiffEditorWidget::slotSendChunkToCodePaster);
|
||||
menu->addSeparator();
|
||||
}
|
||||
QAction *applyAction = menu->addAction(tr("Apply Chunk..."));
|
||||
connect(applyAction, &QAction::triggered, this, &SideBySideDiffEditorWidget::slotApplyChunk);
|
||||
applyAction->setEnabled(false);
|
||||
@@ -929,11 +935,14 @@ void SideBySideDiffEditorWidget::slotRightContextMenuRequested(QMenu *menu,
|
||||
int chunkIndex)
|
||||
{
|
||||
menu->addSeparator();
|
||||
QAction *sendChunkToCodePasterAction =
|
||||
menu->addAction(tr("Send Chunk to CodePaster..."));
|
||||
connect(sendChunkToCodePasterAction, &QAction::triggered,
|
||||
this, &SideBySideDiffEditorWidget::slotSendChunkToCodePaster);
|
||||
menu->addSeparator();
|
||||
if (ExtensionSystem::PluginManager::getObject<CodePaster::Service>()) {
|
||||
// optional code pasting service
|
||||
QAction *sendChunkToCodePasterAction =
|
||||
menu->addAction(tr("Send Chunk to CodePaster..."));
|
||||
connect(sendChunkToCodePasterAction, &QAction::triggered,
|
||||
this, &SideBySideDiffEditorWidget::slotSendChunkToCodePaster);
|
||||
menu->addSeparator();
|
||||
}
|
||||
QAction *revertAction = menu->addAction(tr("Revert Chunk..."));
|
||||
connect(revertAction, &QAction::triggered, this, &SideBySideDiffEditorWidget::slotRevertChunk);
|
||||
revertAction->setEnabled(false);
|
||||
@@ -961,21 +970,15 @@ void SideBySideDiffEditorWidget::slotSendChunkToCodePaster()
|
||||
if (!m_document)
|
||||
return;
|
||||
|
||||
// Retrieve service by soft dependency.
|
||||
auto pasteService = ExtensionSystem::PluginManager::getObject<CodePaster::Service>();
|
||||
QTC_ASSERT(pasteService, return);
|
||||
|
||||
const QString patch = m_document->makePatch(m_contextMenuFileIndex, m_contextMenuChunkIndex, false);
|
||||
if (patch.isEmpty())
|
||||
return;
|
||||
|
||||
// Retrieve service by soft dependency.
|
||||
QObject *pasteService
|
||||
= ExtensionSystem::PluginManager::getObjectByClassName(QLatin1String("CodePaster::CodePasterService"));
|
||||
if (pasteService) {
|
||||
QMetaObject::invokeMethod(pasteService, "postText",
|
||||
Q_ARG(QString, patch),
|
||||
Q_ARG(QString, QLatin1String(DiffEditor::Constants::DIFF_EDITOR_MIMETYPE)));
|
||||
} else {
|
||||
QMessageBox::information(this, tr("Unable to Paste"),
|
||||
tr("Code pasting services are not available."));
|
||||
}
|
||||
pasteService->postText(patch, QLatin1String(Constants::DIFF_EDITOR_MIMETYPE));
|
||||
}
|
||||
|
||||
void SideBySideDiffEditorWidget::slotApplyChunk()
|
||||
|
@@ -54,8 +54,11 @@
|
||||
#include <coreplugin/patchtool.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
|
||||
#include <cpaster/codepasterservice.h>
|
||||
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/tooltip/tooltip.h>
|
||||
|
||||
//static const int FILE_LEVEL = 1;
|
||||
@@ -189,10 +192,13 @@ void UnifiedDiffEditorWidget::addContextMenuActions(QMenu *menu,
|
||||
|
||||
menu->addSeparator();
|
||||
menu->addSeparator();
|
||||
QAction *sendChunkToCodePasterAction =
|
||||
menu->addAction(tr("Send Chunk to CodePaster..."));
|
||||
connect(sendChunkToCodePasterAction, &QAction::triggered,
|
||||
this, &UnifiedDiffEditorWidget::slotSendChunkToCodePaster);
|
||||
if (ExtensionSystem::PluginManager::getObject<CodePaster::Service>()) {
|
||||
// optional code pasting service
|
||||
QAction *sendChunkToCodePasterAction =
|
||||
menu->addAction(tr("Send Chunk to CodePaster..."));
|
||||
connect(sendChunkToCodePasterAction, &QAction::triggered,
|
||||
this, &UnifiedDiffEditorWidget::slotSendChunkToCodePaster);
|
||||
}
|
||||
QAction *applyAction = menu->addAction(tr("Apply Chunk..."));
|
||||
connect(applyAction, &QAction::triggered, this, &UnifiedDiffEditorWidget::slotApplyChunk);
|
||||
QAction *revertAction = menu->addAction(tr("Revert Chunk..."));
|
||||
@@ -229,23 +235,16 @@ void UnifiedDiffEditorWidget::slotSendChunkToCodePaster()
|
||||
if (!m_document)
|
||||
return;
|
||||
|
||||
// Retrieve service by soft dependency.
|
||||
auto pasteService = ExtensionSystem::PluginManager::getObject<CodePaster::Service>();
|
||||
QTC_ASSERT(pasteService, return);
|
||||
|
||||
const QString patch = m_document->makePatch(m_contextMenuFileIndex, m_contextMenuChunkIndex, false);
|
||||
|
||||
if (patch.isEmpty())
|
||||
return;
|
||||
|
||||
// Retrieve service by soft dependency.
|
||||
QObject *pasteService =
|
||||
ExtensionSystem::PluginManager::getObjectByClassName(
|
||||
QLatin1String("CodePaster::CodePasterService"));
|
||||
if (pasteService) {
|
||||
QMetaObject::invokeMethod(pasteService, "postText",
|
||||
Q_ARG(QString, patch),
|
||||
Q_ARG(QString, QLatin1String(DiffEditor::Constants::DIFF_EDITOR_MIMETYPE)));
|
||||
} else {
|
||||
QMessageBox::information(this, tr("Unable to Paste"),
|
||||
tr("Code pasting services are not available."));
|
||||
}
|
||||
pasteService->postText(patch, QLatin1String(Constants::DIFF_EDITOR_MIMETYPE));
|
||||
}
|
||||
|
||||
void UnifiedDiffEditorWidget::slotApplyChunk()
|
||||
|
@@ -87,6 +87,12 @@ static const char HEAD[] = "HEAD";
|
||||
static const char CHERRY_PICK_HEAD[] = "CHERRY_PICK_HEAD";
|
||||
static const char noColorOption[] = "--no-color";
|
||||
static const char decorateOption[] = "--decorate";
|
||||
static const char showFormatC[] =
|
||||
"--pretty=format:commit %H%n"
|
||||
"Author: %an <%ae>, %ad (%ar)%n"
|
||||
"Committer: %cn <%ce>, %cd (%cr)%n"
|
||||
"%n"
|
||||
"%B";
|
||||
|
||||
using namespace Core;
|
||||
using namespace DiffEditor;
|
||||
@@ -367,7 +373,7 @@ void ShowController::reload()
|
||||
{
|
||||
QStringList args;
|
||||
args << QLatin1String("show") << QLatin1String("-s") << QLatin1String(noColorOption)
|
||||
<< QLatin1String(decorateOption) << m_id;
|
||||
<< QLatin1String(decorateOption) << QLatin1String(showFormatC) << m_id;
|
||||
m_state = GettingDescription;
|
||||
runCommand(QList<QStringList>() << args, gitClient()->encoding(m_directory, "i18n.commitEncoding"));
|
||||
}
|
||||
@@ -2838,12 +2844,20 @@ void GitClient::handleMergeConflicts(const QString &workingDir, const QString &c
|
||||
const QStringList &files, const QString &abortCommand)
|
||||
{
|
||||
QString message;
|
||||
if (!commit.isEmpty())
|
||||
if (!commit.isEmpty()) {
|
||||
message = tr("Conflicts detected with commit %1.").arg(commit);
|
||||
else if (!files.isEmpty())
|
||||
message = tr("Conflicts detected with files:\n%1").arg(files.join(QLatin1Char('\n')));
|
||||
else
|
||||
} else if (!files.isEmpty()) {
|
||||
QString fileList;
|
||||
QStringList partialFiles = files;
|
||||
while (partialFiles.count() > 20)
|
||||
partialFiles.removeLast();
|
||||
fileList = partialFiles.join(QLatin1Char('\n'));
|
||||
if (partialFiles.count() != files.count())
|
||||
fileList += QLatin1String("\n...");
|
||||
message = tr("Conflicts detected with files:\n%1").arg(fileList);
|
||||
} else {
|
||||
message = tr("Conflicts detected.");
|
||||
}
|
||||
QMessageBox mergeOrAbort(QMessageBox::Question, tr("Conflicts Detected"), message,
|
||||
QMessageBox::NoButton, ICore::mainWindow());
|
||||
QPushButton *mergeToolButton = mergeOrAbort.addButton(tr("Run &Merge Tool"),
|
||||
|
@@ -124,45 +124,46 @@ BaseAnnotationHighlighter *GitEditorWidget::createAnnotationHighlighter(const QS
|
||||
8ca887aa (author YYYY-MM-DD HH:MM:SS <offset> <line>)<content>
|
||||
\endcode */
|
||||
|
||||
static QString removeAnnotationDate(const QString &b)
|
||||
static QString sanitizeBlameOutput(const QString &b)
|
||||
{
|
||||
if (b.isEmpty())
|
||||
return b;
|
||||
|
||||
const bool omitDate = GitPlugin::instance()->client()->settings().boolValue(
|
||||
GitSettings::omitAnnotationDateKey);
|
||||
const QChar space(QLatin1Char(' '));
|
||||
const int parenPos = b.indexOf(QLatin1Char(')'));
|
||||
if (parenPos == -1)
|
||||
return b;
|
||||
int datePos = parenPos;
|
||||
|
||||
int i = parenPos;
|
||||
while (i >= 0 && b.at(i) != space)
|
||||
--i;
|
||||
while (i >= 0 && b.at(i) == space)
|
||||
--i;
|
||||
int spaceCount = 0;
|
||||
// i is now on timezone. Go back 3 spaces: That is where the date starts.
|
||||
while (i >= 0) {
|
||||
if (b.at(i) == space)
|
||||
++spaceCount;
|
||||
if (spaceCount == 3) {
|
||||
datePos = i;
|
||||
break;
|
||||
int stripPos = i + 1;
|
||||
if (omitDate) {
|
||||
int spaceCount = 0;
|
||||
// i is now on timezone. Go back 3 spaces: That is where the date starts.
|
||||
while (i >= 0) {
|
||||
if (b.at(i) == space)
|
||||
++spaceCount;
|
||||
if (spaceCount == 3) {
|
||||
stripPos = i;
|
||||
break;
|
||||
}
|
||||
--i;
|
||||
}
|
||||
--i;
|
||||
}
|
||||
if (datePos == 0)
|
||||
return b;
|
||||
|
||||
// Copy over the parts that have not changed into a new byte array
|
||||
QString result;
|
||||
QTC_ASSERT(b.size() >= parenPos, return result);
|
||||
int prevPos = 0;
|
||||
int pos = b.indexOf(QLatin1Char('\n'), 0) + 1;
|
||||
forever {
|
||||
QTC_CHECK(prevPos < pos);
|
||||
int afterParen = prevPos + parenPos;
|
||||
result.append(b.mid(prevPos, datePos));
|
||||
result.append(b.mid(prevPos, stripPos));
|
||||
result.append(b.mid(afterParen, pos - afterParen));
|
||||
prevPos = pos;
|
||||
QTC_CHECK(prevPos != 0);
|
||||
@@ -179,17 +180,12 @@ static QString removeAnnotationDate(const QString &b)
|
||||
void GitEditorWidget::setPlainText(const QString &text)
|
||||
{
|
||||
QString modText = text;
|
||||
GitPlugin *plugin = GitPlugin::instance();
|
||||
// If desired, filter out the date from annotation
|
||||
switch (contentType())
|
||||
{
|
||||
case AnnotateOutput: {
|
||||
const bool omitAnnotationDate
|
||||
= plugin->client()->settings().boolValue(GitSettings::omitAnnotationDateKey);
|
||||
if (omitAnnotationDate)
|
||||
modText = removeAnnotationDate(text);
|
||||
case AnnotateOutput:
|
||||
modText = sanitizeBlameOutput(text);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@@ -163,7 +163,7 @@ void WorkingDirectoryAspect::addToMainConfigurationWidget(QWidget *parent, QForm
|
||||
this, &WorkingDirectoryAspect::setWorkingDirectory);
|
||||
|
||||
auto resetButton = new QToolButton(parent);
|
||||
resetButton->setToolTip(tr("Reset to default"));
|
||||
resetButton->setToolTip(tr("Reset to Default"));
|
||||
resetButton->setIcon(QIcon(QLatin1String(Core::Constants::ICON_RESET)));
|
||||
connect(resetButton, &QAbstractButton::clicked, this, &WorkingDirectoryAspect::resetPath);
|
||||
|
||||
|
@@ -33,6 +33,7 @@
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
#include <windows.h>
|
||||
#include <QApplication>
|
||||
|
||||
|
||||
/*!
|
||||
@@ -68,6 +69,7 @@ WinDebugInterface::WinDebugInterface(QObject *parent) :
|
||||
QThread(parent)
|
||||
{
|
||||
m_instance = this;
|
||||
m_creatorPid = qApp->applicationPid();
|
||||
setObjectName(QLatin1String("WinDebugInterfaceThread"));
|
||||
}
|
||||
|
||||
@@ -138,7 +140,8 @@ bool WinDebugInterface::runLoop()
|
||||
if (ret == WAIT_FAILED || ret - WAIT_OBJECT_0 == TerminateEventHandle)
|
||||
break;
|
||||
if (ret - WAIT_OBJECT_0 == DataReadyEventHandle) {
|
||||
emit debugOutput(*processId, QString::fromLocal8Bit(message));
|
||||
if (*processId != m_creatorPid)
|
||||
emit debugOutput(*processId, QString::fromLocal8Bit(message));
|
||||
SetEvent(m_bufferReadyEvent);
|
||||
}
|
||||
}
|
||||
|
@@ -60,6 +60,7 @@ private:
|
||||
|
||||
static WinDebugInterface *m_instance;
|
||||
|
||||
qint64 m_creatorPid;
|
||||
Qt::HANDLE m_waitHandles[HandleCount];
|
||||
Qt::HANDLE m_bufferReadyEvent;
|
||||
Qt::HANDLE m_sharedFile;
|
||||
|
@@ -219,7 +219,7 @@ DesktopQmakeRunConfigurationWidget::DesktopQmakeRunConfigurationWidget(DesktopQm
|
||||
m_workingDirectoryEdit->setPromptDialogTitle(tr("Select Working Directory"));
|
||||
|
||||
QToolButton *resetButton = new QToolButton(this);
|
||||
resetButton->setToolTip(tr("Reset to default"));
|
||||
resetButton->setToolTip(tr("Reset to Default"));
|
||||
resetButton->setIcon(QIcon(QLatin1String(Core::Constants::ICON_RESET)));
|
||||
|
||||
QHBoxLayout *boxlayout = new QHBoxLayout();
|
||||
|
@@ -210,7 +210,7 @@ void QmlProfilerClientManager::disconnectClientSignals()
|
||||
|
||||
void QmlProfilerClientManager::connectToClient()
|
||||
{
|
||||
if (!d->connection || d->connection->isOpen())
|
||||
if (!d->connection || d->connection->isOpen() || d->connection->isConnecting())
|
||||
return;
|
||||
|
||||
d->connection->connectToHost(d->tcpHost, d->tcpPort);
|
||||
@@ -285,6 +285,12 @@ void QmlProfilerClientManager::logState(const QString &msg)
|
||||
|
||||
void QmlProfilerClientManager::retryMessageBoxFinished(int result)
|
||||
{
|
||||
if (d->connection) {
|
||||
QTC_ASSERT(!d->connection->isOpen(), return);
|
||||
if (d->connection->isConnecting())
|
||||
d->connection->disconnect();
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
case QMessageBox::Retry: {
|
||||
d->connectionAttempts = 0;
|
||||
|
@@ -296,8 +296,7 @@ void QtOptionsPageWidget::toolChainsUpdated()
|
||||
updateDescriptionLabel();
|
||||
updateDebuggingHelperUi();
|
||||
} else {
|
||||
const ValidityInfo info = validInformation(m_versions.at(i));
|
||||
item->setIcon(0, info.icon);
|
||||
updateVersionItem(m_versions.at(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -369,6 +368,9 @@ QtOptionsPageWidget::ValidityInfo QtOptionsPageWidget::validInformation(const Ba
|
||||
|
||||
bool useable = true;
|
||||
QStringList warnings;
|
||||
if (!isNameUnique(version))
|
||||
warnings << tr("Display Name is not unique.");
|
||||
|
||||
if (!missingToolChains.isEmpty()) {
|
||||
if (missingToolChains.count() == abiCount) {
|
||||
// Yes, this Qt version can't be used at all!
|
||||
@@ -422,6 +424,27 @@ QString QtOptionsPageWidget::defaultToolChainId(const BaseQtVersion *version)
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool QtOptionsPageWidget::isNameUnique(const BaseQtVersion *version)
|
||||
{
|
||||
const QString name = version->displayName().trimmed();
|
||||
foreach (const BaseQtVersion *i, m_versions) {
|
||||
if (i == version)
|
||||
continue;
|
||||
if (i->displayName().trimmed() == name)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void QtOptionsPageWidget::updateVersionItem(BaseQtVersion *version)
|
||||
{
|
||||
const ValidityInfo info = validInformation(version);
|
||||
QTreeWidgetItem *item = treeItemForIndex(m_versions.indexOf(version));
|
||||
item->setText(0, version->displayName());
|
||||
item->setText(1, version->qmakeCommand().toUserOutput());
|
||||
item->setIcon(0, info.icon);
|
||||
}
|
||||
|
||||
void QtOptionsPageWidget::buildDebuggingHelper(DebuggingHelperBuildTask::Tools tools)
|
||||
{
|
||||
const int index = currentIndex();
|
||||
@@ -551,12 +574,8 @@ void QtOptionsPageWidget::updateQtVersions(const QList<int> &additions, const QL
|
||||
m_versions.append(version);
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem;
|
||||
|
||||
item->setText(0, version->displayName());
|
||||
item->setText(1, version->qmakeCommand().toUserOutput());
|
||||
item->setData(0, VersionIdRole, version->uniqueId());
|
||||
item->setData(0, ToolChainIdRole, defaultToolChainId(version));
|
||||
const ValidityInfo info = validInformation(version);
|
||||
item->setIcon(0, info.icon);
|
||||
|
||||
// Insert in the right place:
|
||||
QTreeWidgetItem *parent = version->isAutodetected()? m_autoItem : m_manualItem;
|
||||
@@ -572,6 +591,10 @@ void QtOptionsPageWidget::updateQtVersions(const QList<int> &additions, const QL
|
||||
if (parent)
|
||||
parent->addChild(item);
|
||||
}
|
||||
|
||||
// Only set the icon after all versions are there to make sure all names are known:
|
||||
foreach (BaseQtVersion *i, m_versions)
|
||||
updateVersionItem(i);
|
||||
}
|
||||
|
||||
QtOptionsPageWidget::~QtOptionsPageWidget()
|
||||
@@ -902,20 +925,24 @@ void QtOptionsPageWidget::updateCurrentQtName()
|
||||
int currentItemIndex = indexForTreeItem(currentItem);
|
||||
if (currentItemIndex < 0)
|
||||
return;
|
||||
m_versions[currentItemIndex]->setUnexpandedDisplayName(m_versionUi->nameEdit->text());
|
||||
currentItem->setText(0, m_versions[currentItemIndex]->displayName());
|
||||
|
||||
BaseQtVersion *version = m_versions[currentItemIndex];
|
||||
version->setUnexpandedDisplayName(m_versionUi->nameEdit->text());
|
||||
updateDescriptionLabel();
|
||||
|
||||
foreach (BaseQtVersion *i, m_versions)
|
||||
updateVersionItem(i);
|
||||
}
|
||||
|
||||
void QtOptionsPageWidget::apply()
|
||||
{
|
||||
disconnect(QtVersionManager::instance(), SIGNAL(qtVersionsChanged(QList<int>,QList<int>,QList<int>)),
|
||||
this, SLOT(updateQtVersions(QList<int>,QList<int>,QList<int>)));
|
||||
disconnect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged,
|
||||
this, &QtOptionsPageWidget::updateQtVersions);
|
||||
|
||||
QtVersionManager::setNewQtVersions(versions());
|
||||
|
||||
connect(QtVersionManager::instance(), SIGNAL(qtVersionsChanged(QList<int>,QList<int>,QList<int>)),
|
||||
this, SLOT(updateQtVersions(QList<int>,QList<int>,QList<int>)));
|
||||
connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged,
|
||||
this, &QtOptionsPageWidget::updateQtVersions);
|
||||
}
|
||||
|
||||
QList<BaseQtVersion *> QtOptionsPageWidget::versions() const
|
||||
|
@@ -126,6 +126,9 @@ private:
|
||||
QList<ProjectExplorer::ToolChain*> toolChains(const BaseQtVersion *version);
|
||||
QString defaultToolChainId(const BaseQtVersion *verison);
|
||||
|
||||
bool isNameUnique(const BaseQtVersion *version);
|
||||
void updateVersionItem(BaseQtVersion *version);
|
||||
|
||||
QTreeWidgetItem *m_autoItem;
|
||||
QTreeWidgetItem *m_manualItem;
|
||||
};
|
||||
|
@@ -59,7 +59,7 @@ CallgrindRunControl::CallgrindRunControl(const AnalyzerStartParameters &sp,
|
||||
|
||||
void CallgrindRunControl::showStatusMessage(const QString &msg)
|
||||
{
|
||||
AnalyzerManager::showStatusMessage(CallgrindToolId, msg);
|
||||
AnalyzerManager::showPermanentStatusMessage(CallgrindToolId, msg);
|
||||
}
|
||||
|
||||
QStringList CallgrindRunControl::toolArguments() const
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user