Merge remote-tracking branch 'origin/3.5'

This commit is contained in:
Eike Ziller
2015-07-08 14:32:13 +02:00
112 changed files with 2229 additions and 3581 deletions

87
dist/changes-3.5.0.md vendored
View File

@@ -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

View File

@@ -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}

View File

@@ -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

View File

@@ -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")

View File

@@ -1759,6 +1759,7 @@ class Tester(Dumper):
self.expandedINames = set(expandedINames)
self.passExceptions = True
self.sortStructMembers = True
self.loadDumpers({})
error = lldb.SBError()

View File

@@ -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)

View File

@@ -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

View File

@@ -12,6 +12,7 @@ BackgroundColorDark=ff232323
BackgroundColorHover=ff515151
BackgroundColorNormal=ffffffff
BackgroundColorSelected=ff151515
BackgroundColorDisabled=ffefebe7
BadgeLabelBackgroundColorChecked=ffe0e0e0
BadgeLabelBackgroundColorUnchecked=ff808080
BadgeLabelTextColorChecked=ff606060

View File

@@ -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();

View File

@@ -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())

View File

@@ -57,6 +57,7 @@ public:
void connectToHost(const QString &hostName, quint16 port);
bool isOpen() const;
bool isConnecting() const;
void close();
signals:

View File

@@ -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;
}

View File

@@ -63,6 +63,7 @@ public:
BackgroundColorHover,
BackgroundColorNormal,
BackgroundColorSelected,
BackgroundColorDisabled,
BadgeLabelBackgroundColorChecked,
BadgeLabelBackgroundColorUnchecked,
BadgeLabelTextColorChecked,

View File

@@ -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

View 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

View 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

View File

@@ -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

View File

@@ -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

View 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

View 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

View 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

View File

@@ -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

View File

@@ -30,7 +30,7 @@
#include "clangbackendipcintegration.h"
#include "clangcompletion.h"
#include "clangcompletionassistprocessor.h"
#include "clangmodelmanagersupport.h"
#include "clangutils.h"
#include "pchmanager.h"

View File

@@ -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 {

View File

@@ -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",

View File

@@ -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
};

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View 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

View File

@@ -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

View 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

View 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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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()
{

View File

@@ -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);

View File

@@ -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("&lt;");
break;
case CXCompletionChunk_RightAngle:
m_snippet += text;
parts.back().text += QLatin1String("&gt;");
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("&nbsp;");
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("&lt;");
break;
case CXCompletionChunk_RightAngle:
m_snippet += text;
m_text += text;
m_hint += QLatin1String("&gt;");
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

View File

@@ -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

View File

@@ -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>

View 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()));

View File

@@ -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("&nbsp;");
}
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&lt;Aaaa&gt; *)aabb");
QTest::newRow("case: objective-c class messages from base class") << file << texts << snippets << hints;
texts.clear();
snippets.clear();
hints.clear();
}
#endif

View File

@@ -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

View File

@@ -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.<<<<;
}

View File

@@ -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.<<<<;
}

View File

@@ -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::<<<<;
}

View File

@@ -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.<<<<;
}

View File

@@ -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()
{
<<<<
}

View File

@@ -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 <<<<
}
}

View File

@@ -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 = <<<<;
}

View File

@@ -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
{
<<<<
};

View File

@@ -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);

View File

@@ -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();

View File

@@ -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"),

View File

@@ -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());

View File

@@ -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 &current, 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);

View File

@@ -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;
}

View File

@@ -13,7 +13,8 @@ HEADERS += cpasterplugin.h \
fileshareprotocol.h \
fileshareprotocolsettingspage.h \
kdepasteprotocol.h \
urlopenprotocol.h
urlopenprotocol.h \
codepasterservice.h
SOURCES += cpasterplugin.cpp \
settingspage.cpp \

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
};

View File

@@ -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);

View File

@@ -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 &params)
{
m_pendingBreakpointRequests = 0;
watchHandler()->notifyUpdateStarted();
watchHandler()->notifyUpdateStarted(params.partialVariables());
DebuggerCommand cmd("showData");
watchHandler()->appendFormatRequests(&cmd);
@@ -4716,7 +4722,6 @@ void GdbEngine::doUpdateLocals(const UpdateParameters &params)
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)

View File

@@ -211,6 +211,7 @@ private:
CommandsDoneCallback m_commandsDoneCallback;
QList<DebuggerCommand> m_commandsToRunOnTemporaryBreak;
bool m_rerunPending;
private: ////////// Gdb Output, State & Capability Handling //////////
protected:

View File

@@ -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 &params)
return;
}
watchHandler()->notifyUpdateStarted();
watchHandler()->notifyUpdateStarted(params.partialVariables());
DebuggerCommand cmd("updateData");
cmd.arg("nativeMixed", isNativeMixedActive());

View File

@@ -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);
}

View File

@@ -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 {

View File

@@ -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,

View File

@@ -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 &currentPaths = 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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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">

View File

@@ -131,7 +131,8 @@ WatchData::WatchData() :
elided(0),
wantsChildren(false),
valueEnabled(true),
valueEditable(true)
valueEditable(true),
outdated(false)
{
}

View File

@@ -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)
};

View File

@@ -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);

View File

@@ -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.

View File

@@ -9,6 +9,10 @@ QtcPlugin {
Depends { name: "Core" }
Depends { name: "TextEditor" }
pluginRecommends: [
"CodePaster"
]
files: [
"diffeditor.cpp",
"diffeditor.h",

View File

@@ -5,3 +5,5 @@ QTC_LIB_DEPENDS += \
QTC_PLUGIN_DEPENDS += \
texteditor \
coreplugin
QTC_PLUGIN_RECOMMENDS += \
cpaster

View File

@@ -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;
}

View File

@@ -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()

View File

@@ -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()

View File

@@ -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"),

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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