cppeditor.cpp 38.9 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
con's avatar
con committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
con's avatar
con committed
7
**
hjk's avatar
hjk committed
8 9 10 11 12 13 14
** 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 Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17 18 19 20 21 22 23 24 25
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
26 27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
hjk's avatar
hjk committed
29

con's avatar
con committed
30
#include "cppeditor.h"
31

32
#include "cppautocompleter.h"
33 34
#include "cppcanonicalsymbol.h"
#include "cppdocumentationcommenthelper.h"
con's avatar
con committed
35
#include "cppeditorconstants.h"
36
#include "cppeditoroutline.h"
37
#include "cppeditorplugin.h"
38
#include "cppfollowsymbolundercursor.h"
con's avatar
con committed
39
#include "cpphighlighter.h"
40
#include "cpplocalrenaming.h"
41
#include "cpppreprocessordialog.h"
Leandro Melo's avatar
Leandro Melo committed
42
#include "cppquickfixassistant.h"
Roberto Raggi's avatar
Roberto Raggi committed
43

44 45
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
46

47
#include <cpptools/cppchecksymbols.h>
Christian Kamm's avatar
Christian Kamm committed
48
#include <cpptools/cppcodeformatter.h>
49
#include <cpptools/cppcompletionassistprovider.h>
50
#include <cpptools/cpphighlightingsupport.h>
Nikolai Kosjar's avatar
Nikolai Kosjar committed
51
#include <cpptools/cppmodelmanagerinterface.h>
52
#include <cpptools/cppsemanticinfo.h>
53
#include <cpptools/cpptoolsconstants.h>
54 55
#include <cpptools/cpptoolseditorsupport.h>
#include <cpptools/cpptoolsplugin.h>
56
#include <cpptools/cpptoolsreuse.h>
57
#include <cpptools/cppworkingcopy.h>
58
#include <cpptools/symbolfinder.h>
59 60 61

#include <projectexplorer/session.h>

con's avatar
con committed
62
#include <texteditor/basetextdocument.h>
63
#include <texteditor/basetextdocumentlayout.h>
64 65 66
#include <texteditor/codeassist/basicproposalitem.h>
#include <texteditor/codeassist/basicproposalitemlistmodel.h>
#include <texteditor/codeassist/genericproposal.h>
con's avatar
con committed
67
#include <texteditor/fontsettings.h>
68
#include <texteditor/refactoroverlay.h>
69 70 71 72

#include <utils/qtcassert.h>

#include <cplusplus/ASTPath.h>
73
#include <cplusplus/BackwardsScanner.h>
74 75
#include <cplusplus/ExpressionUnderCursor.h>
#include <cplusplus/OverviewModel.h>
con's avatar
con committed
76

77
#include <QAction>
78
#include <QFutureWatcher>
79
#include <QMenu>
80 81 82 83
#include <QPointer>
#include <QSignalMapper>
#include <QTextEdit>
#include <QTimer>
84
#include <QToolButton>
con's avatar
con committed
85

Roberto Raggi's avatar
Roberto Raggi committed
86
enum {
87 88
    UPDATE_USES_INTERVAL = 500,
    UPDATE_FUNCTION_DECL_DEF_LINK_INTERVAL = 200
Roberto Raggi's avatar
Roberto Raggi committed
89 90
};

Roberto Raggi's avatar
Roberto Raggi committed
91
using namespace CPlusPlus;
92
using namespace CppTools;
Roberto Raggi's avatar
Roberto Raggi committed
93 94
using namespace CppEditor::Internal;

95 96 97
namespace CppEditor {
namespace Internal {

98
CPPEditor::CPPEditor()
con's avatar
con committed
99
{
100 101 102
    m_context.add(CppEditor::Constants::C_CPPEDITOR);
    m_context.add(ProjectExplorer::Constants::LANG_CXX);
    m_context.add(TextEditor::Constants::C_TEXTEDITOR);
103
    setDuplicateSupported(true);
104
    setCommentStyle(Utils::CommentDefinition::CppStyle);
105 106 107
    setCompletionAssistProvider([this] () -> TextEditor::CompletionAssistProvider * {
        return CppModelManagerInterface::instance()->cppEditorSupport(this)->completionAssistProvider();
    });
con's avatar
con committed
108 109
}

110 111
Q_GLOBAL_STATIC(CppTools::SymbolFinder, symbolFinder)

112
class CppEditorWidgetPrivate
113 114
{
public:
115
    CppEditorWidgetPrivate(CppEditorWidget *q);
116 117 118 119 120

public:
    QPointer<CppTools::CppModelManagerInterface> m_modelManager;

    CPPEditorDocument *m_cppEditorDocument;
121 122
    CppEditorOutline *m_cppEditorOutline;

123 124
    CppDocumentationCommentHelper m_cppDocumentationCommentHelper;

125 126
    QTimer m_updateUsesTimer;
    QTimer m_updateFunctionDeclDefLinkTimer;
127 128
    QHash<int, QTextCharFormat> m_semanticHighlightFormatMap;

129
    CppLocalRenaming m_localRenaming;
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147

    CppTools::SemanticInfo m_lastSemanticInfo;
    QList<TextEditor::QuickFixOperation::Ptr> m_quickFixes;

    QScopedPointer<QFutureWatcher<TextEditor::HighlightingResult> > m_highlightWatcher;
    unsigned m_highlightRevision; // the editor revision that requested the highlight

    QScopedPointer<QFutureWatcher<QList<int> > > m_referencesWatcher;
    unsigned m_referencesRevision;
    int m_referencesCursorPosition;

    FunctionDeclDefLinkFinder *m_declDefLinkFinder;
    QSharedPointer<FunctionDeclDefLink> m_declDefLink;

    QScopedPointer<FollowSymbolUnderCursor> m_followSymbolUnderCursor;
    QToolButton *m_preprocessorButton;
};

148
CppEditorWidgetPrivate::CppEditorWidgetPrivate(CppEditorWidget *q)
149
    : m_modelManager(CppModelManagerInterface::instance())
150
    , m_cppEditorDocument(qobject_cast<CPPEditorDocument *>(q->textDocument()))
151
    , m_cppEditorOutline(new CppEditorOutline(q))
152
    , m_cppDocumentationCommentHelper(q)
153
    , m_localRenaming(q)
154 155 156 157 158 159 160 161 162
    , m_highlightRevision(0)
    , m_referencesRevision(0)
    , m_referencesCursorPosition(0)
    , m_declDefLinkFinder(new FunctionDeclDefLinkFinder(q))
    , m_followSymbolUnderCursor(new FollowSymbolUnderCursor(q))
    , m_preprocessorButton(0)
{
}

163
CppEditorWidget::CppEditorWidget(TextEditor::BaseTextDocumentPtr doc, CPPEditor *editor)
164
{
165 166
    editor->setEditorWidget(this);

167
    setTextDocument(doc);
168
    d.reset(new CppEditorWidgetPrivate(this));
169
    setAutoCompleter(new CppAutoCompleter);
170

171
    qRegisterMetaType<SemanticInfo>("CppTools::SemanticInfo");
Roberto Raggi's avatar
Roberto Raggi committed
172

con's avatar
con committed
173 174
    setParenthesesMatchingEnabled(true);
    setMarksVisible(true);
175
    setCodeFoldingSupported(true);
176
    setRevisionsVisible(true);
dt's avatar
dt committed
177

178
    if (d->m_modelManager) {
179
        CppEditorSupport *editorSupport = d->m_modelManager->cppEditorSupport(editor);
180 181 182 183
        connect(editorSupport, SIGNAL(documentUpdated()),
                this, SLOT(onDocumentUpdated()));
        connect(editorSupport, SIGNAL(semanticInfoUpdated(CppTools::SemanticInfo)),
                this, SLOT(updateSemanticInfo(CppTools::SemanticInfo)));
Eike Ziller's avatar
Eike Ziller committed
184 185
        connect(editorSupport, SIGNAL(highlighterStarted(QFuture<TextEditor::HighlightingResult>*,uint)),
                this, SLOT(highlighterStarted(QFuture<TextEditor::HighlightingResult>*,uint)));
con's avatar
con committed
186
    }
187

188
    connect(d->m_declDefLinkFinder, SIGNAL(foundLink(QSharedPointer<FunctionDeclDefLink>)),
189
            this, SLOT(onFunctionDeclDefLinkFound(QSharedPointer<FunctionDeclDefLink>)));
190

191
    connect(textDocument(), SIGNAL(filePathChanged(QString,QString)),
192
            this, SLOT(onFilePathChanged()));
193 194 195 196 197

    connect(&d->m_localRenaming, SIGNAL(finished()),
            this, SLOT(onLocalRenamingFinished()));
    connect(&d->m_localRenaming, SIGNAL(processKeyPressNormally(QKeyEvent*)),
            this, SLOT(onLocalRenamingProcessKeyPressNormally(QKeyEvent*)));
con's avatar
con committed
198

199
    // Tool bar creation
200 201 202 203 204 205 206 207
    d->m_updateUsesTimer.setSingleShot(true);
    d->m_updateUsesTimer.setInterval(UPDATE_USES_INTERVAL);

    connect(&d->m_updateUsesTimer, &QTimer::timeout,
            this, &CppEditorWidget::updateUsesNow);

    d->m_updateFunctionDeclDefLinkTimer.setSingleShot(true);
    d->m_updateFunctionDeclDefLinkTimer.setInterval(UPDATE_FUNCTION_DECL_DEF_LINK_INTERVAL);
208

209 210
    connect(&d->m_updateFunctionDeclDefLinkTimer, &QTimer::timeout,
            this, &CppEditorWidget::updateFunctionDeclDefLinkNow);
211

212 213
    connect(this, SIGNAL(cursorPositionChanged()),
            d->m_cppEditorOutline, SLOT(updateIndex()));
con's avatar
con committed
214

215
    // set up slots to document changes
216 217
    connect(document(), SIGNAL(contentsChange(int,int,int)),
            this, SLOT(onContentsChanged(int,int,int)));
con's avatar
con committed
218

219 220 221
    // set up function declaration - definition link
    connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateFunctionDeclDefLink()));
    connect(this, SIGNAL(textChanged()), this, SLOT(updateFunctionDeclDefLink()));
Roberto Raggi's avatar
Roberto Raggi committed
222 223 224 225 226

    // set up the semantic highlighter
    connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateUses()));
    connect(this, SIGNAL(textChanged()), this, SLOT(updateUses()));

227 228
    d->m_preprocessorButton = new QToolButton(this);
    d->m_preprocessorButton->setText(QLatin1String("#"));
229 230 231
    Core::Command *cmd = Core::ActionManager::command(Constants::OPEN_PREPROCESSOR_DIALOG);
    connect(cmd, SIGNAL(keySequenceChanged()), this, SLOT(updatePreprocessorButtonTooltip()));
    updatePreprocessorButtonTooltip();
232
    connect(d->m_preprocessorButton, SIGNAL(clicked()), this, SLOT(showPreProcessorWidget()));
233 234
    insertExtraToolBarWidget(TextEditor::BaseTextEditorWidget::Left, d->m_preprocessorButton);
    insertExtraToolBarWidget(TextEditor::BaseTextEditorWidget::Left, d->m_cppEditorOutline->widget());
235
    setLanguageSettingsId(CppTools::Constants::CPP_SETTINGS_ID);
con's avatar
con committed
236 237
}

238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
CppEditorWidget::~CppEditorWidget()
{
    if (d->m_modelManager)
        d->m_modelManager->deleteCppEditorSupport(editor());
}

CPPEditorDocument *CppEditorWidget::cppEditorDocument() const
{
    return d->m_cppEditorDocument;
}

CppEditorOutline *CppEditorWidget::outline() const
{
    return d->m_cppEditorOutline;
}

TextEditor::BaseTextEditor *CppEditorWidget::createEditor()
{
256
    QTC_ASSERT("should not happen anymore" && false, return 0);
257 258
}

259
void CppEditorWidget::paste()
mae's avatar
mae committed
260
{
261
    if (d->m_localRenaming.handlePaste())
mae's avatar
mae committed
262 263
        return;

264
    BaseTextEditorWidget::paste();
mae's avatar
mae committed
265 266
}

267
void CppEditorWidget::cut()
mae's avatar
mae committed
268
{
269
    if (d->m_localRenaming.handlePaste())
mae's avatar
mae committed
270 271
        return;

272
    BaseTextEditorWidget::cut();
mae's avatar
mae committed
273 274
}

275
void CppEditorWidget::selectAll()
276
{
277
    if (d->m_localRenaming.handleSelectAll())
mae's avatar
mae committed
278
        return;
279

280
    BaseTextEditorWidget::selectAll();
281 282
}

283 284
/// \brief Called by \c CppEditorSupport when the document corresponding to the
///        file in this editor is updated.
285
void CppEditorWidget::onDocumentUpdated()
con's avatar
con committed
286
{
287
    d->m_cppEditorOutline->update();
con's avatar
con committed
288 289
}

290
void CppEditorWidget::findUsages()
291
{
292
    if (!d->m_modelManager)
293 294
        return;

295
    SemanticInfo info = d->m_lastSemanticInfo;
296
    info.snapshot = CppModelManagerInterface::instance()->snapshot();
297
    info.snapshot.insert(info.doc);
298

299
    if (const Macro *macro = CppTools::findCanonicalMacro(textCursor(), info.doc)) {
300
        d->m_modelManager->findMacroUsages(*macro);
301
    } else {
302
        CanonicalSymbol cs(info.doc, info.snapshot);
303 304
        Symbol *canonicalSymbol = cs(textCursor());
        if (canonicalSymbol)
305
            d->m_modelManager->findUsages(canonicalSymbol, cs.context());
306
    }
307 308
}

309
void CppEditorWidget::renameUsages(const QString &replacement)
310
{
311
    if (!d->m_modelManager)
312 313
        return;

314
    SemanticInfo info = d->m_lastSemanticInfo;
315
    info.snapshot = CppModelManagerInterface::instance()->snapshot();
316 317
    info.snapshot.insert(info.doc);

318
    if (const Macro *macro = CppTools::findCanonicalMacro(textCursor(), info.doc)) {
319
        d->m_modelManager->renameMacroUsages(*macro, replacement);
320
    } else {
321
        CanonicalSymbol cs(info.doc, info.snapshot);
322 323
        if (Symbol *canonicalSymbol = cs(textCursor()))
            if (canonicalSymbol->identifier() != 0)
324
                d->m_modelManager->renameUsages(canonicalSymbol, cs.context(), replacement);
325
    }
326 327
}

328
void CppEditorWidget::markSymbolsNow()
329
{
330 331 332 333 334
    QTC_ASSERT(d->m_referencesWatcher, return);
    if (!d->m_referencesWatcher->isCanceled()
            && d->m_referencesCursorPosition == position()
            && d->m_referencesRevision == editorRevision()) {
        const SemanticInfo info = d->m_lastSemanticInfo;
Erik Verbruggen's avatar
Erik Verbruggen committed
335
        TranslationUnit *unit = info.doc->translationUnit();
336
        const QList<int> result = d->m_referencesWatcher->result();
337

Erik Verbruggen's avatar
Erik Verbruggen committed
338
        QList<QTextEdit::ExtraSelection> selections;
339

Erik Verbruggen's avatar
Erik Verbruggen committed
340 341 342
        foreach (int index, result) {
            unsigned line, column;
            unit->getTokenPosition(index, &line, &column);
343

Erik Verbruggen's avatar
Erik Verbruggen committed
344 345
            if (column)
                --column;  // adjust the column position.
346

347
            const int len = unit->tokenAt(index).utf16chars();
348

Erik Verbruggen's avatar
Erik Verbruggen committed
349 350 351
            QTextCursor cursor(document()->findBlockByNumber(line - 1));
            cursor.setPosition(cursor.position() + column);
            cursor.setPosition(cursor.position() + len, QTextCursor::KeepAnchor);
352

Erik Verbruggen's avatar
Erik Verbruggen committed
353
            QTextEdit::ExtraSelection sel;
354
            sel.format = textCharFormat(TextEditor::C_OCCURRENCES);
Erik Verbruggen's avatar
Erik Verbruggen committed
355 356 357
            sel.cursor = cursor;
            selections.append(sel);
        }
358

Erik Verbruggen's avatar
Erik Verbruggen committed
359
        setExtraSelections(CodeSemanticsSelection, selections);
Roberto Raggi's avatar
Roberto Raggi committed
360
    }
361
    d->m_referencesWatcher.reset();
Roberto Raggi's avatar
Roberto Raggi committed
362 363
}

Nikolai Kosjar's avatar
Nikolai Kosjar committed
364 365
static QList<int> lazyFindReferences(Scope *scope, QString code, Document::Ptr doc,
                                     Snapshot snapshot)
366 367
{
    TypeOfExpression typeOfExpression;
368 369
    snapshot.insert(doc);
    typeOfExpression.init(doc, snapshot);
370 371
    // make possible to instantiate templates
    typeOfExpression.setExpandTemplates(true);
372
    if (Symbol *canonicalSymbol = CanonicalSymbol::canonicalSymbol(scope, code, typeOfExpression))
Nikolai Kosjar's avatar
Nikolai Kosjar committed
373 374
        return CppModelManagerInterface::instance()->references(canonicalSymbol,
                                                                typeOfExpression.context());
375 376 377
    return QList<int>();
}

378
void CppEditorWidget::markSymbols(const QTextCursor &tc, const SemanticInfo &info)
379
{
380
    d->m_localRenaming.stop();
381

382
    if (!info.doc)
383
        return;
384
    const QTextCharFormat &occurrencesFormat = textCharFormat(TextEditor::C_OCCURRENCES);
385
    if (const Macro *macro = CppTools::findCanonicalMacro(textCursor(), info.doc)) {
386 387 388 389 390
        QList<QTextEdit::ExtraSelection> selections;

        //Macro definition
        if (macro->fileName() == info.doc->fileName()) {
            QTextCursor cursor(document());
391
            cursor.setPosition(macro->utf16CharOffset());
Nikolai Kosjar's avatar
Nikolai Kosjar committed
392
            cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor,
393
                                macro->nameToQString().size());
394 395

            QTextEdit::ExtraSelection sel;
396
            sel.format = occurrencesFormat;
397 398 399 400 401
            sel.cursor = cursor;
            selections.append(sel);
        }

        //Other macro uses
402
        foreach (const Document::MacroUse &use, info.doc->macroUses()) {
403 404
            const Macro &useMacro = use.macro();
            if (useMacro.line() != macro->line()
405
                    || useMacro.utf16CharOffset() != macro->utf16CharOffset()
406 407
                    || useMacro.length() != macro->length()
                    || useMacro.fileName() != macro->fileName())
408 409 410
                continue;

            QTextCursor cursor(document());
411 412
            cursor.setPosition(use.utf16charsBegin());
            cursor.setPosition(use.utf16charsEnd(), QTextCursor::KeepAnchor);
413 414

            QTextEdit::ExtraSelection sel;
415
            sel.format = occurrencesFormat;
416 417 418
            sel.cursor = cursor;
            selections.append(sel);
        }
419

420 421
        setExtraSelections(CodeSemanticsSelection, selections);
    } else {
422
        CanonicalSymbol cs(info.doc, info.snapshot);
423
        QString expression;
424
        if (Scope *scope = cs.getScopeAndExpression(tc, &expression)) {
425 426 427 428 429 430 431 432 433
            if (d->m_referencesWatcher)
                d->m_referencesWatcher->cancel();
            d->m_referencesWatcher.reset(new QFutureWatcher<QList<int> >);
            connect(d->m_referencesWatcher.data(), SIGNAL(finished()), SLOT(markSymbolsNow()));

            d->m_referencesRevision = info.revision;
            d->m_referencesCursorPosition = position();
            d->m_referencesWatcher->setFuture(
                QtConcurrent::run(&lazyFindReferences, scope, expression, info.doc, info.snapshot));
434 435 436
        } else {
            const QList<QTextEdit::ExtraSelection> selections = extraSelections(CodeSemanticsSelection);

437
            if (!selections.isEmpty())
438 439
                setExtraSelections(CodeSemanticsSelection, QList<QTextEdit::ExtraSelection>());
        }
440 441 442
    }
}

443
void CppEditorWidget::renameSymbolUnderCursor()
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
444
{
445
    if (!d->m_modelManager)
446 447
        return;

448 449
    CppEditorSupport *ces = d->m_modelManager->cppEditorSupport(editor());
    updateSemanticInfo(ces->recalculateSemanticInfo());
450

451 452
    if (!d->m_localRenaming.start()) // Rename local symbol
        renameUsages(); // Rename non-local symbol or macro
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
453 454
}

455
void CppEditorWidget::onContentsChanged(int position, int charsRemoved, int charsAdded)
456
{
457 458
    Q_UNUSED(position)
    Q_UNUSED(charsAdded)
459 460 461 462 463

    if (charsRemoved > 0)
        updateUses();
}

464
void CppEditorWidget::updatePreprocessorButtonTooltip()
465
{
466
    QTC_ASSERT(d->m_preprocessorButton, return);
467 468
    Core::Command *cmd = Core::ActionManager::command(Constants::OPEN_PREPROCESSOR_DIALOG);
    QTC_ASSERT(cmd, return);
469
    d->m_preprocessorButton->setToolTip(cmd->action()->toolTip());
470 471
}

472
QList<QTextEdit::ExtraSelection> CppEditorWidget::createSelectionsFromUses(
473
        const QList<SemanticInfo::Use> &uses)
Roberto Raggi's avatar
Roberto Raggi committed
474
{
475 476
    QList<QTextEdit::ExtraSelection> result;
    const bool isUnused = uses.size() == 1;
Roberto Raggi's avatar
Roberto Raggi committed
477

Roberto Raggi's avatar
Roberto Raggi committed
478
    foreach (const SemanticInfo::Use &use, uses) {
479 480
        if (use.isInvalid())
            continue;
Roberto Raggi's avatar
Roberto Raggi committed
481

482
        QTextEdit::ExtraSelection sel;
Roberto Raggi's avatar
Roberto Raggi committed
483
        if (isUnused)
484
            sel.format = textCharFormat(TextEditor::C_OCCURRENCES_UNUSED);
Roberto Raggi's avatar
Roberto Raggi committed
485
        else
486
            sel.format = textCharFormat(TextEditor::C_OCCURRENCES);
Roberto Raggi's avatar
Roberto Raggi committed
487

488 489
        const int position = document()->findBlockByNumber(use.line - 1).position() + use.column - 1;
        const int anchor = position + use.length;
Roberto Raggi's avatar
Roberto Raggi committed
490

491
        sel.cursor = QTextCursor(document());
Roberto Raggi's avatar
Roberto Raggi committed
492 493
        sel.cursor.setPosition(anchor);
        sel.cursor.setPosition(position, QTextCursor::KeepAnchor);
Roberto Raggi's avatar
Roberto Raggi committed
494

495
        result.append(sel);
Roberto Raggi's avatar
Roberto Raggi committed
496
    }
497 498

    return result;
Roberto Raggi's avatar
Roberto Raggi committed
499 500
}

501
void CppEditorWidget::updateUses()
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
502
{
503
    // Block premature semantic info calculation when editor is created.
504
    if (d->m_modelManager && d->m_modelManager->cppEditorSupport(editor())->initialized())
505
        d->m_updateUsesTimer.start();
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
506 507
}

508
void CppEditorWidget::updateUsesNow()
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
509
{
510
    if (d->m_localRenaming.isActive())
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
511 512
        return;

Roberto Raggi's avatar
Roberto Raggi committed
513
    semanticRehighlight();
con's avatar
con committed
514 515
}

516
void CppEditorWidget::highlightSymbolUsages(int from, int to)
517
{
518
    if (editorRevision() != d->m_highlightRevision)
519 520
        return; // outdated

521
    else if (!d->m_highlightWatcher || d->m_highlightWatcher->isCanceled())
522 523
        return; // aborted

524
    TextEditor::SyntaxHighlighter *highlighter = textDocument()->syntaxHighlighter();
525
    QTC_ASSERT(highlighter, return);
526

527
    TextEditor::SemanticHighlighter::incrementalApplyExtraAdditionalFormats(
528
                highlighter, d->m_highlightWatcher->future(), from, to, d->m_semanticHighlightFormatMap);
529 530
}

531
void CppEditorWidget::finishHighlightSymbolUsages()
532
{
533 534 535 536
    QTC_ASSERT(d->m_highlightWatcher, return);
    if (!d->m_highlightWatcher->isCanceled()
            && editorRevision() == d->m_highlightRevision
            && !d->m_lastSemanticInfo.doc.isNull()) {
537
        TextEditor::SyntaxHighlighter *highlighter = textDocument()->syntaxHighlighter();
Erik Verbruggen's avatar
Erik Verbruggen committed
538 539 540
        QTC_CHECK(highlighter);
        if (highlighter)
            TextEditor::SemanticHighlighter::clearExtraAdditionalFormatsUntilEnd(highlighter,
541
                d->m_highlightWatcher->future());
Erik Verbruggen's avatar
Erik Verbruggen committed
542
    }
543
    d->m_highlightWatcher.reset();
544 545
}

546
void CppEditorWidget::switchDeclarationDefinition(bool inNextSplit)
con's avatar
con committed
547
{
548
    if (!d->m_modelManager)
con's avatar
con committed
549 550
        return;

551
    if (!d->m_lastSemanticInfo.doc)
552
        return;
con's avatar
con committed
553

554 555 556 557
    // Find function declaration or definition under cursor
    Function *functionDefinitionSymbol = 0;
    Symbol *functionDeclarationSymbol = 0;

558
    ASTPath astPathFinder(d->m_lastSemanticInfo.doc);
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
    const QList<AST *> astPath = astPathFinder(textCursor());

    for (int i = 0, size = astPath.size(); i < size; ++i) {
        AST *ast = astPath.at(i);
        if (FunctionDefinitionAST *functionDefinitionAST = ast->asFunctionDefinition()) {
            if ((functionDefinitionSymbol = functionDefinitionAST->symbol))
                break; // Function definition found!
        } else if (SimpleDeclarationAST *simpleDeclaration = ast->asSimpleDeclaration()) {
            if (List<Symbol *> *symbols = simpleDeclaration->symbols) {
                if (Symbol *symbol = symbols->value) {
                    if (symbol->isDeclaration() && symbol->type()->isFunctionType()) {
                        functionDeclarationSymbol = symbol;
                        break; // Function declaration found!
                    }
                }
            }
        }
    }
con's avatar
con committed
577

578
    // Link to function definition/declaration
579
    CppEditorWidget::Link symbolLink;
580 581
    if (functionDeclarationSymbol) {
        symbolLink = linkToSymbol(symbolFinder()
582
            ->findMatchingDefinition(functionDeclarationSymbol, d->m_modelManager->snapshot()));
583
    } else if (functionDefinitionSymbol) {
584 585
        const Snapshot snapshot = d->m_modelManager->snapshot();
        LookupContext context(d->m_lastSemanticInfo.doc, snapshot);
586 587 588 589 590 591 592 593
        ClassOrNamespace *binding = context.lookupType(functionDefinitionSymbol);
        const QList<LookupItem> declarations = context.lookup(functionDefinitionSymbol->name(),
            functionDefinitionSymbol->enclosingScope());

        QList<Symbol *> best;
        foreach (const LookupItem &r, declarations) {
            if (Symbol *decl = r.declaration()) {
                if (Function *funTy = decl->type()->asFunctionType()) {
594
                    if (funTy->match(functionDefinitionSymbol)) {
595 596 597 598
                        if (decl != functionDefinitionSymbol && binding == r.binding())
                            best.prepend(decl);
                        else
                            best.append(decl);
599 600
                    }
                }
601 602
            }
        }
603

604 605 606
        if (best.isEmpty())
            return;
        symbolLink = linkToSymbol(best.first());
con's avatar
con committed
607
    }
608 609 610 611

    // Open Editor at link position
    if (symbolLink.hasValidTarget())
        openCppEditorAt(symbolLink, inNextSplit != alwaysOpenLinksInNextSplit());
con's avatar
con committed
612 613
}

614
CppEditorWidget::Link CppEditorWidget::findLinkAt(const QTextCursor &cursor, bool resolveTarget,
615
                                                  bool inNextSplit)
con's avatar
con committed
616
{
617
    if (!d->m_modelManager)
618
        return Link();
619

620 621 622 623 624
    return d->m_followSymbolUnderCursor->findLink(cursor, resolveTarget,
                                                  d->m_modelManager->snapshot(),
                                                  d->m_lastSemanticInfo.doc,
                                                  symbolFinder(),
                                                  inNextSplit);
con's avatar
con committed
625 626
}

627
unsigned CppEditorWidget::editorRevision() const
628 629 630 631
{
    return document()->revision();
}

632
bool CppEditorWidget::isOutdated() const
633
{
634
    if (d->m_lastSemanticInfo.revision != editorRevision())
635 636 637 638 639
        return true;

    return false;
}

640
SemanticInfo CppEditorWidget::semanticInfo() const
Roberto Raggi's avatar
Roberto Raggi committed
641
{
642
    return d->m_lastSemanticInfo;
Roberto Raggi's avatar
Roberto Raggi committed
643 644
}

645
bool CppEditorWidget::event(QEvent *e)
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
646 647 648
{
    switch (e->type()) {
    case QEvent::ShortcutOverride:
649
        // handle escape manually if a rename is active
650
        if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape && d->m_localRenaming.isActive()) {
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
651 652 653 654 655 656 657 658
            e->accept();
            return true;
        }
        break;
    default:
        break;
    }

659
    return BaseTextEditorWidget::event(e);
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
660 661
}

662
void CppEditorWidget::performQuickFix(int index)
663
{
664
    TextEditor::QuickFixOperation::Ptr op = d->m_quickFixes.at(index);
665
    op->perform();
666 667
}

668
void CppEditorWidget::contextMenuEvent(QContextMenuEvent *e)
con's avatar
con committed
669
{
Roberto Raggi's avatar
Roberto Raggi committed
670 671 672
    // ### enable
    // updateSemanticInfo(m_semanticHighlighter->semanticInfo(currentSource()));

673
    QPointer<QMenu> menu(new QMenu(this));
con's avatar
con committed
674

Eike Ziller's avatar
Eike Ziller committed
675
    Core::ActionContainer *mcontext = Core::ActionManager::actionContainer(Constants::M_CONTEXT);
con's avatar
con committed
676 677
    QMenu *contextMenu = mcontext->menu();

678
    QMenu *quickFixMenu = new QMenu(tr("&Refactor"), menu);
Nikolai Kosjar's avatar
Nikolai Kosjar committed
679 680
    quickFixMenu->addAction(Core::ActionManager::command(
                                Constants::RENAME_SYMBOL_UNDER_CURSOR)->action());
681 682 683

    QSignalMapper mapper;
    connect(&mapper, SIGNAL(mapped(int)), this, SLOT(performQuickFix(int)));
684
    if (!isOutdated()) {
Leandro Melo's avatar
Leandro Melo committed
685 686 687 688
        TextEditor::IAssistInterface *interface =
            createAssistInterface(TextEditor::QuickFix, TextEditor::ExplicitlyInvoked);
        if (interface) {
            QScopedPointer<TextEditor::IAssistProcessor> processor(
689
                        CppEditorPlugin::instance()->quickFixProvider()->createProcessor());
Leandro Melo's avatar
Leandro Melo committed
690 691 692 693 694 695 696 697 698
            QScopedPointer<TextEditor::IAssistProposal> proposal(processor->perform(interface));
            if (!proposal.isNull()) {
                TextEditor::BasicProposalItemListModel *model =
                        static_cast<TextEditor::BasicProposalItemListModel *>(proposal->model());
                for (int index = 0; index < model->size(); ++index) {
                    TextEditor::BasicProposalItem *item =
                            static_cast<TextEditor::BasicProposalItem *>(model->proposalItem(index));
                    TextEditor::QuickFixOperation::Ptr op =
                            item->data().value<TextEditor::QuickFixOperation::Ptr>();
699
                    d->m_quickFixes.append(op);
Leandro Melo's avatar
Leandro Melo committed
700 701 702 703 704
                    QAction *action = quickFixMenu->addAction(op->description());
                    mapper.setMapping(action, index);
                    connect(action, SIGNAL(triggered()), &mapper, SLOT(map()));
                }
                delete model;
705 706 707 708
            }
        }
    }

709
    foreach (QAction *action, contextMenu->actions()) {
con's avatar
con committed
710
        menu->addAction(action);
711
        if (action->objectName() == QLatin1String(Constants::M_REFACTORING_MENU_INSERTION_POINT))
712 713
            menu->addMenu(quickFixMenu);
    }
con's avatar
con committed
714

715 716
    appendStandardContextMenuActions(menu);

con's avatar
con committed
717
    menu->exec(e->globalPos());
718 719
    if (!menu)
        return;
720
    d->m_quickFixes.clear();
con's avatar
con committed
721 722 723
    delete menu;
}

724
void CppEditorWidget::keyPressEvent(QKeyEvent *e)
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
725
{
726
    if (d->m_localRenaming.handleKeyPressEvent(e))
727 728
        return;

729 730 731 732
    if (d->m_cppDocumentationCommentHelper.handleKeyPressEvent(e))
        return;

    TextEditor::BaseTextEditorWidget::keyPressEvent(e);
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
733 734
}

735
Core::IEditor *CPPEditor::duplicate()
con's avatar
con committed
736
{
737 738 739 740 741
    CPPEditor *editor = new CPPEditor;
    CppEditorWidget *widget = new CppEditorWidget(editorWidget()->textDocumentPtr(), editor);
    CppEditorPlugin::instance()->initializeEditor(widget);
    editor->configureCodeAssistant();
    return editor;
con's avatar
con committed
742 743
}

744
bool CPPEditor::open(QString *errorString, const QString &fileName, const QString &realFileName)
dt's avatar
dt committed
745
{
746 747
    if (!TextEditor::BaseTextEditor::open(errorString, fileName, realFileName))
        return false;
748
    textDocument()->setMimeType(Core::MimeDatabase::findByFile(QFileInfo(fileName)).type());
749
    return true;
dt's avatar
dt committed
750 751
}

752
void CppEditorWidget::applyFontSettings()
con's avatar
con committed
753
{
754
    const TextEditor::FontSettings &fs = textDocument()->fontSettings();
Erik Verbruggen's avatar
Erik Verbruggen committed
755

756
    d->m_semanticHighlightFormatMap[CppHighlightingSupport::TypeUse] =
757
            fs.toTextCharFormat(TextEditor::C_TYPE);
758
    d->m_semanticHighlightFormatMap[CppHighlightingSupport::LocalUse] =
759
            fs.toTextCharFormat(TextEditor::C_LOCAL);
760
    d->m_semanticHighlightFormatMap[CppHighlightingSupport::FieldUse] =
761
            fs.toTextCharFormat(TextEditor::C_FIELD);
762
    d->m_semanticHighlightFormatMap[CppHighlightingSupport::EnumerationUse] =
763
            fs.toTextCharFormat(TextEditor::C_ENUMERATION);
764
    d->m_semanticHighlightFormatMap[CppHighlightingSupport::VirtualMethodUse] =
765
            fs.toTextCharFormat(TextEditor::C_VIRTUAL_METHOD);
766
    d->m_semanticHighlightFormatMap[CppHighlightingSupport::LabelUse] =
767
            fs.toTextCharFormat(TextEditor::C_LABEL);
768
    d->m_semanticHighlightFormatMap[CppHighlightingSupport::MacroUse] =
769
            fs.toTextCharFormat(TextEditor::C_PREPROCESSOR);
770
    d->m_semanticHighlightFormatMap[CppHighlightingSupport::FunctionUse] =
771
            fs.toTextCharFormat(TextEditor::C_FUNCTION);
772
    d->m_semanticHighlightFormatMap[CppHighlightingSupport::PseudoKeywordUse] =
773
            fs.toTextCharFormat(TextEditor::C_KEYWORD);
774
    d->m_semanticHighlightFormatMap[CppHighlightingSupport::StringUse] =
775
            fs.toTextCharFormat(TextEditor::C_STRING);