cppeditor.cpp 28.8 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 "cppeditordocument.h"
37
#include "cppeditoroutline.h"
38
#include "cppeditorplugin.h"
39
#include "cppfollowsymbolundercursor.h"
con's avatar
con committed
40
#include "cpphighlighter.h"
41
#include "cpplocalrenaming.h"
42
#include "cpppreprocessordialog.h"
Leandro Melo's avatar
Leandro Melo committed
43
#include "cppquickfixassistant.h"
44
#include "cppuseselectionsupdater.h"
Roberto Raggi's avatar
Roberto Raggi committed
45

46 47
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
48

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

#include <projectexplorer/session.h>

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

#include <cplusplus/ASTPath.h>
72
#include <utils/qtcassert.h>
con's avatar
con committed
73

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

84
enum { UPDATE_FUNCTION_DECL_DEF_LINK_INTERVAL = 200 };
Roberto Raggi's avatar
Roberto Raggi committed
85

Roberto Raggi's avatar
Roberto Raggi committed
86
using namespace CPlusPlus;
87
using namespace CppTools;
Roberto Raggi's avatar
Roberto Raggi committed
88 89
using namespace CppEditor::Internal;

90 91 92
namespace CppEditor {
namespace Internal {

93
CppEditor::CppEditor()
con's avatar
con committed
94
{
95
    m_context.add(Constants::C_CPPEDITOR);
96 97
    m_context.add(ProjectExplorer::Constants::LANG_CXX);
    m_context.add(TextEditor::Constants::C_TEXTEDITOR);
98
    setDuplicateSupported(true);
99
    setCommentStyle(Utils::CommentDefinition::CppStyle);
100
    setCompletionAssistProvider([this] () -> TextEditor::CompletionAssistProvider * {
101
        if (CppEditorDocument *document = qobject_cast<CppEditorDocument *>(textDocument()))
102 103
            return document->completionAssistProvider();
        return 0;
104
    });
con's avatar
con committed
105 106
}

107 108
Q_GLOBAL_STATIC(CppTools::SymbolFinder, symbolFinder)

109
class CppEditorWidgetPrivate
110 111
{
public:
112
    CppEditorWidgetPrivate(CppEditorWidget *q);
113 114 115 116

public:
    QPointer<CppTools::CppModelManagerInterface> m_modelManager;

117
    CppEditorDocument *m_cppEditorDocument;
118 119
    CppEditorOutline *m_cppEditorOutline;

120 121
    CppDocumentationCommentHelper m_cppDocumentationCommentHelper;

122
    QTimer m_updateFunctionDeclDefLinkTimer;
123

124
    CppLocalRenaming m_localRenaming;
125 126 127 128

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

129
    CppUseSelectionsUpdater m_useSelectionsUpdater;
130 131 132 133 134 135 136 137

    FunctionDeclDefLinkFinder *m_declDefLinkFinder;
    QSharedPointer<FunctionDeclDefLink> m_declDefLink;

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

138
CppEditorWidgetPrivate::CppEditorWidgetPrivate(CppEditorWidget *q)
139
    : m_modelManager(CppModelManagerInterface::instance())
140
    , m_cppEditorDocument(qobject_cast<CppEditorDocument *>(q->textDocument()))
141
    , m_cppEditorOutline(new CppEditorOutline(q))
142
    , m_cppDocumentationCommentHelper(q)
143
    , m_localRenaming(q)
144
    , m_useSelectionsUpdater(q)
145 146 147 148 149 150
    , m_declDefLinkFinder(new FunctionDeclDefLinkFinder(q))
    , m_followSymbolUnderCursor(new FollowSymbolUnderCursor(q))
    , m_preprocessorButton(0)
{
}

151
CppEditorWidget::CppEditorWidget(TextEditor::BaseTextDocumentPtr doc, CppEditor *editor)
152
{
153 154
    qRegisterMetaType<SemanticInfo>("CppTools::SemanticInfo");

155 156
    editor->setEditorWidget(this);

157
    setTextDocument(doc);
158
    d.reset(new CppEditorWidgetPrivate(this));
159
    setAutoCompleter(new CppAutoCompleter);
160
    setLanguageSettingsId(CppTools::Constants::CPP_SETTINGS_ID);
161
    setCodeFoldingSupported(true);
162 163
    setMarksVisible(true);
    setParenthesesMatchingEnabled(true);
164
    setRevisionsVisible(true);
dt's avatar
dt committed
165

166
    connect(d->m_cppEditorDocument, &CppEditorDocument::codeWarningsUpdated,
167
            this, &CppEditorWidget::onCodeWarningsUpdated);
168
    connect(d->m_cppEditorDocument, &CppEditorDocument::ifdefedOutBlocksUpdated,
169 170 171 172 173
            this, &CppEditorWidget::onIfdefedOutBlocksUpdated);
    connect(d->m_cppEditorDocument, SIGNAL(cppDocumentUpdated(CPlusPlus::Document::Ptr)),
            this, SLOT(onCppDocumentUpdated()));
    connect(d->m_cppEditorDocument, SIGNAL(semanticInfoUpdated(CppTools::SemanticInfo)),
            this, SLOT(updateSemanticInfo(CppTools::SemanticInfo)));
174

175
    connect(d->m_declDefLinkFinder, SIGNAL(foundLink(QSharedPointer<FunctionDeclDefLink>)),
176
            this, SLOT(onFunctionDeclDefLinkFound(QSharedPointer<FunctionDeclDefLink>)));
177

178
    connect(textDocument(), SIGNAL(filePathChanged(QString,QString)),
179
            this, SLOT(onFilePathChanged()));
180

181 182 183 184
    connect(&d->m_useSelectionsUpdater,
            SIGNAL(selectionsForVariableUnderCursorUpdated(QList<QTextEdit::ExtraSelection>)),
            &d->m_localRenaming,
            SLOT(updateSelectionsForVariableUnderCursor(QList<QTextEdit::ExtraSelection>)));
185

186 187 188 189 190 191
    connect(&d->m_useSelectionsUpdater, &CppUseSelectionsUpdater::finished,
            [this] (CppTools::SemanticInfo::LocalUseMap localUses) {
                QTC_CHECK(isSemanticInfoValidExceptLocalUses());
                d->m_lastSemanticInfo.localUsesUpdated = true;
                d->m_lastSemanticInfo.localUses = localUses;
    });
192

193 194 195 196 197
    connect(&d->m_localRenaming, &CppLocalRenaming::finished, [this] {
        cppEditorDocument()->semanticRehighlight();
    });
    connect(&d->m_localRenaming, &CppLocalRenaming::processKeyPressNormally,
            this, &CppEditorWidget::processKeyNormally);
198

199 200
    connect(this, SIGNAL(cursorPositionChanged()),
            d->m_cppEditorOutline, SLOT(updateIndex()));
con's avatar
con committed
201

202
    // set up function declaration - definition link
203 204 205 206
    d->m_updateFunctionDeclDefLinkTimer.setSingleShot(true);
    d->m_updateFunctionDeclDefLinkTimer.setInterval(UPDATE_FUNCTION_DECL_DEF_LINK_INTERVAL);
    connect(&d->m_updateFunctionDeclDefLinkTimer, SIGNAL(timeout()),
            this, SLOT(updateFunctionDeclDefLinkNow()));
207 208
    connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateFunctionDeclDefLink()));
    connect(this, SIGNAL(textChanged()), this, SLOT(updateFunctionDeclDefLink()));
Roberto Raggi's avatar
Roberto Raggi committed
209

210 211 212 213 214
    // set up the use highlighitng
    connect(this, &CppEditorWidget::cursorPositionChanged, [this]() {
        if (!d->m_localRenaming.isActive())
            d->m_useSelectionsUpdater.scheduleUpdate();
    });
Roberto Raggi's avatar
Roberto Raggi committed
215

216
    // Tool bar creation
217 218
    d->m_preprocessorButton = new QToolButton(this);
    d->m_preprocessorButton->setText(QLatin1String("#"));
219 220 221
    Core::Command *cmd = Core::ActionManager::command(Constants::OPEN_PREPROCESSOR_DIALOG);
    connect(cmd, SIGNAL(keySequenceChanged()), this, SLOT(updatePreprocessorButtonTooltip()));
    updatePreprocessorButtonTooltip();
222
    connect(d->m_preprocessorButton, SIGNAL(clicked()), this, SLOT(showPreProcessorWidget()));
223 224
    insertExtraToolBarWidget(TextEditor::BaseTextEditorWidget::Left, d->m_preprocessorButton);
    insertExtraToolBarWidget(TextEditor::BaseTextEditorWidget::Left, d->m_cppEditorOutline->widget());
con's avatar
con committed
225 226
}

227 228
CppEditorWidget::~CppEditorWidget()
{
229 230 231
    // non-inline destructor, see section "Forward Declared Pointers" of QScopedPointer.
}

232
CppEditorWidget *CppEditorWidget::duplicate(CppEditor *editor) const
233 234 235 236 237 238 239 240 241 242 243
{
    QTC_ASSERT(editor, return 0);

    CppEditorWidget *widget = new CppEditorWidget(textDocumentPtr(), editor);
    widget->updateSemanticInfo(semanticInfo());
    widget->updateFunctionDeclDefLink();
    widget->d->m_cppEditorOutline->update();
    const ExtraSelectionKind selectionKind = CodeWarningsSelection;
    widget->setExtraSelections(selectionKind, extraSelections(selectionKind));

    return widget;
244 245
}

246
CppEditorDocument *CppEditorWidget::cppEditorDocument() const
247 248 249 250 251 252 253 254 255 256 257
{
    return d->m_cppEditorDocument;
}

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

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

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

266
    BaseTextEditorWidget::paste();
mae's avatar
mae committed
267 268
}

269
void CppEditorWidget::cut()
mae's avatar
mae committed
270
{
271
    if (d->m_localRenaming.handleCut())
mae's avatar
mae committed
272 273
        return;

274
    BaseTextEditorWidget::cut();
mae's avatar
mae committed
275 276
}

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

282
    BaseTextEditorWidget::selectAll();
283 284
}

285
void CppEditorWidget::onCppDocumentUpdated()
con's avatar
con committed
286
{
287
    d->m_cppEditorOutline->update();
con's avatar
con committed
288 289
}

290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
void CppEditorWidget::onCodeWarningsUpdated(unsigned revision,
                                            const QList<QTextEdit::ExtraSelection> selections)
{
    if (revision != documentRevision())
        return;
    setExtraSelections(BaseTextEditorWidget::CodeWarningsSelection, selections);
}

void CppEditorWidget::onIfdefedOutBlocksUpdated(unsigned revision,
    const QList<TextEditor::BlockRange> ifdefedOutBlocks)
{
    if (revision != documentRevision())
        return;
    setIfdefedOutBlocks(ifdefedOutBlocks);
}

306
void CppEditorWidget::findUsages()
307
{
308
    if (!d->m_modelManager)
309 310
        return;

311
    SemanticInfo info = d->m_lastSemanticInfo;
312
    info.snapshot = CppModelManagerInterface::instance()->snapshot();
313
    info.snapshot.insert(info.doc);
314

315
    if (const Macro *macro = CppTools::findCanonicalMacro(textCursor(), info.doc)) {
316
        d->m_modelManager->findMacroUsages(*macro);
317
    } else {
318
        CanonicalSymbol cs(info.doc, info.snapshot);
319 320
        Symbol *canonicalSymbol = cs(textCursor());
        if (canonicalSymbol)
321
            d->m_modelManager->findUsages(canonicalSymbol, cs.context());
322
    }
323 324
}

325
void CppEditorWidget::renameUsages(const QString &replacement)
326
{
327
    if (!d->m_modelManager)
328 329
        return;

330
    SemanticInfo info = d->m_lastSemanticInfo;
331
    info.snapshot = CppModelManagerInterface::instance()->snapshot();
332 333
    info.snapshot.insert(info.doc);

334
    if (const Macro *macro = CppTools::findCanonicalMacro(textCursor(), info.doc)) {
335
        d->m_modelManager->renameMacroUsages(*macro, replacement);
336
    } else {
337
        CanonicalSymbol cs(info.doc, info.snapshot);
338 339
        if (Symbol *canonicalSymbol = cs(textCursor()))
            if (canonicalSymbol->identifier() != 0)
340
                d->m_modelManager->renameUsages(canonicalSymbol, cs.context(), replacement);
341
    }
342 343
}

344
void CppEditorWidget::renameSymbolUnderCursor()
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
345
{
346
    updateSemanticInfo(d->m_cppEditorDocument->recalculateSemanticInfo());
347

348
    d->m_useSelectionsUpdater.abortSchedule();
349

350 351 352 353 354 355 356 357 358
    // Trigger once the use selections updater is finished and thus has updated
    // the use selections for the local renaming
    QSharedPointer<QMetaObject::Connection> connection(new QMetaObject::Connection);
    *connection.data() = connect(&d->m_useSelectionsUpdater, &CppUseSelectionsUpdater::finished,
        [this, connection] () {
            QObject::disconnect(*connection);
            if (!d->m_localRenaming.start()) // Rename local symbol
                renameUsages(); // Rename non-local symbol or macro
        });
359

360
    d->m_useSelectionsUpdater.update();
361 362
}

363
void CppEditorWidget::updatePreprocessorButtonTooltip()
364
{
365
    QTC_ASSERT(d->m_preprocessorButton, return);
366 367
    Core::Command *cmd = Core::ActionManager::command(Constants::OPEN_PREPROCESSOR_DIALOG);
    QTC_ASSERT(cmd, return);
368
    d->m_preprocessorButton->setToolTip(cmd->action()->toolTip());
369 370
}

371
void CppEditorWidget::switchDeclarationDefinition(bool inNextSplit)
con's avatar
con committed
372
{
373
    if (!d->m_modelManager)
con's avatar
con committed
374 375
        return;

376
    if (!d->m_lastSemanticInfo.doc)
377
        return;
con's avatar
con committed
378

379 380 381 382
    // Find function declaration or definition under cursor
    Function *functionDefinitionSymbol = 0;
    Symbol *functionDeclarationSymbol = 0;

383
    ASTPath astPathFinder(d->m_lastSemanticInfo.doc);
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
    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
402

403
    // Link to function definition/declaration
404
    CppEditorWidget::Link symbolLink;
405 406
    if (functionDeclarationSymbol) {
        symbolLink = linkToSymbol(symbolFinder()
407
            ->findMatchingDefinition(functionDeclarationSymbol, d->m_modelManager->snapshot()));
408
    } else if (functionDefinitionSymbol) {
409 410
        const Snapshot snapshot = d->m_modelManager->snapshot();
        LookupContext context(d->m_lastSemanticInfo.doc, snapshot);
411 412 413 414 415 416 417 418
        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()) {
419
                    if (funTy->match(functionDefinitionSymbol)) {
420 421 422 423
                        if (decl != functionDefinitionSymbol && binding == r.binding())
                            best.prepend(decl);
                        else
                            best.append(decl);
424 425
                    }
                }
426 427
            }
        }
428

429 430 431
        if (best.isEmpty())
            return;
        symbolLink = linkToSymbol(best.first());
con's avatar
con committed
432
    }
433 434 435 436

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

439
CppEditorWidget::Link CppEditorWidget::findLinkAt(const QTextCursor &cursor, bool resolveTarget,
440
                                                  bool inNextSplit)
con's avatar
con committed
441
{
442
    if (!d->m_modelManager)
443
        return Link();
444

445 446 447 448 449
    return d->m_followSymbolUnderCursor->findLink(cursor, resolveTarget,
                                                  d->m_modelManager->snapshot(),
                                                  d->m_lastSemanticInfo.doc,
                                                  symbolFinder(),
                                                  inNextSplit);
con's avatar
con committed
450 451
}

452
unsigned CppEditorWidget::documentRevision() const
453 454 455 456
{
    return document()->revision();
}

457
bool CppEditorWidget::isSemanticInfoValidExceptLocalUses() const
458
{
459 460
    return d->m_lastSemanticInfo.doc && d->m_lastSemanticInfo.revision == documentRevision();
}
461

462 463 464
bool CppEditorWidget::isSemanticInfoValid() const
{
    return isSemanticInfoValidExceptLocalUses() && d->m_lastSemanticInfo.localUsesUpdated;
465 466
}

467
SemanticInfo CppEditorWidget::semanticInfo() const
Roberto Raggi's avatar
Roberto Raggi committed
468
{
469
    return d->m_lastSemanticInfo;
Roberto Raggi's avatar
Roberto Raggi committed
470 471
}

472
bool CppEditorWidget::event(QEvent *e)
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
473 474 475
{
    switch (e->type()) {
    case QEvent::ShortcutOverride:
476
        // handle escape manually if a rename is active
477
        if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape && d->m_localRenaming.isActive()) {
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
478 479 480 481 482 483 484 485
            e->accept();
            return true;
        }
        break;
    default:
        break;
    }

486
    return BaseTextEditorWidget::event(e);
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
487 488
}

489
void CppEditorWidget::performQuickFix(int index)
490
{
491
    TextEditor::QuickFixOperation::Ptr op = d->m_quickFixes.at(index);
492
    op->perform();
493 494
}

495 496 497 498 499
void CppEditorWidget::processKeyNormally(QKeyEvent *e)
{
    BaseTextEditorWidget::keyPressEvent(e);
}

500
void CppEditorWidget::contextMenuEvent(QContextMenuEvent *e)
con's avatar
con committed
501
{
Roberto Raggi's avatar
Roberto Raggi committed
502 503 504
    // ### enable
    // updateSemanticInfo(m_semanticHighlighter->semanticInfo(currentSource()));

505
    QPointer<QMenu> menu(new QMenu(this));
con's avatar
con committed
506

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

510
    QMenu *quickFixMenu = new QMenu(tr("&Refactor"), menu);
Nikolai Kosjar's avatar
Nikolai Kosjar committed
511 512
    quickFixMenu->addAction(Core::ActionManager::command(
                                Constants::RENAME_SYMBOL_UNDER_CURSOR)->action());
513 514 515

    QSignalMapper mapper;
    connect(&mapper, SIGNAL(mapped(int)), this, SLOT(performQuickFix(int)));
516
    if (isSemanticInfoValid()) {
Leandro Melo's avatar
Leandro Melo committed
517 518 519 520
        TextEditor::IAssistInterface *interface =
            createAssistInterface(TextEditor::QuickFix, TextEditor::ExplicitlyInvoked);
        if (interface) {
            QScopedPointer<TextEditor::IAssistProcessor> processor(
521
                        CppEditorPlugin::instance()->quickFixProvider()->createProcessor());
Leandro Melo's avatar
Leandro Melo committed
522 523 524 525 526 527 528 529 530
            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>();
531
                    d->m_quickFixes.append(op);
Leandro Melo's avatar
Leandro Melo committed
532 533 534 535 536
                    QAction *action = quickFixMenu->addAction(op->description());
                    mapper.setMapping(action, index);
                    connect(action, SIGNAL(triggered()), &mapper, SLOT(map()));
                }
                delete model;
537 538 539 540
            }
        }
    }

541
    foreach (QAction *action, contextMenu->actions()) {
con's avatar
con committed
542
        menu->addAction(action);
543
        if (action->objectName() == QLatin1String(Constants::M_REFACTORING_MENU_INSERTION_POINT))
544 545
            menu->addMenu(quickFixMenu);
    }
con's avatar
con committed
546

547 548
    appendStandardContextMenuActions(menu);

con's avatar
con committed
549
    menu->exec(e->globalPos());
550 551
    if (!menu)
        return;
552
    d->m_quickFixes.clear();
con's avatar
con committed
553 554 555
    delete menu;
}

556
void CppEditorWidget::keyPressEvent(QKeyEvent *e)
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
557
{
558
    if (d->m_localRenaming.handleKeyPressEvent(e))
559 560
        return;

561 562 563 564
    if (d->m_cppDocumentationCommentHelper.handleKeyPressEvent(e))
        return;

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

567
Core::IEditor *CppEditor::duplicate()
con's avatar
con committed
568
{
569
    CppEditor *editor = new CppEditor;
570
    CppEditorWidget *widget = qobject_cast<CppEditorWidget *>(editorWidget())->duplicate(editor);
571 572 573
    CppEditorPlugin::instance()->initializeEditor(widget);
    editor->configureCodeAssistant();
    return editor;
con's avatar
con committed
574 575
}

576
bool CppEditor::open(QString *errorString, const QString &fileName, const QString &realFileName)
dt's avatar
dt committed
577
{
578 579
    if (!TextEditor::BaseTextEditor::open(errorString, fileName, realFileName))
        return false;
580
    textDocument()->setMimeType(Core::MimeDatabase::findByFile(QFileInfo(fileName)).type());
581
    return true;
dt's avatar
dt committed
582 583
}

584
void CppEditorWidget::applyFontSettings()
con's avatar
con committed
585
{
586
    // This also makes the document apply font settings
587
    TextEditor::BaseTextEditorWidget::applyFontSettings();
con's avatar
con committed
588 589
}

590
void CppEditorWidget::slotCodeStyleSettingsChanged(const QVariant &)
591 592 593 594 595
{
    CppTools::QtStyleCodeFormatter formatter;
    formatter.invalidateCache(document());
}

596
CppEditorWidget::Link CppEditorWidget::linkToSymbol(CPlusPlus::Symbol *symbol)
597
{
598 599 600
    if (!symbol)
        return Link();

David Schulz's avatar
David Schulz committed
601
    const QString filename = QString::fromUtf8(symbol->fileName(),
602
                                               symbol->fileNameLength());
David Schulz's avatar
David Schulz committed
603

604 605
    unsigned line = symbol->line();
    unsigned column = symbol->column();
606

607 608
    if (column)
        --column;
609

610
    if (symbol->isGenerated())
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
611
        column = 0;
612

David Schulz's avatar
David Schulz committed
613
    return Link(filename, line, column);
614 615
}

616
bool CppEditorWidget::openCppEditorAt(const Link &link, bool inNextSplit)
617
{
618
    if (!link.hasValidTarget())
619 620
        return false;

Eike Ziller's avatar
Eike Ziller committed
621
    Core::EditorManager::OpenEditorFlags flags;
622 623
    if (inNextSplit)
        flags |= Core::EditorManager::OpenInOtherSplit;
624 625 626
    return Core::EditorManager::openEditorAt(link.targetFileName,
                                             link.targetLine,
                                             link.targetColumn,
627 628
                                             Constants::CPPEDITOR_ID,
                                             flags);
con's avatar
con committed
629
}
Roberto Raggi's avatar
Roberto Raggi committed
630

631
void CppEditorWidget::updateSemanticInfo(const SemanticInfo &semanticInfo)
Roberto Raggi's avatar
Roberto Raggi committed
632
{
633
    if (semanticInfo.revision != documentRevision())
Roberto Raggi's avatar
Roberto Raggi committed
634
        return;
Roberto Raggi's avatar
Roberto Raggi committed
635

636
    d->m_lastSemanticInfo = semanticInfo;
Roberto Raggi's avatar
Roberto Raggi committed
637

638 639
    if (!d->m_localRenaming.isActive())
        d->m_useSelectionsUpdater.update();
640 641 642

    // schedule a check for a decl/def link
    updateFunctionDeclDefLink();
Roberto Raggi's avatar
Roberto Raggi committed
643 644
}

645
TextEditor::IAssistInterface *CppEditorWidget::createAssistInterface(
Leandro Melo's avatar
Leandro Melo committed
646 647 648 649
    TextEditor::AssistKind kind,
    TextEditor::AssistReason reason) const
{
    if (kind == TextEditor::Completion) {
650
        if (CppCompletionAssistProvider *cap = cppEditorDocument()->completionAssistProvider()) {
651
            return cap->createAssistInterface(
652
                            ProjectExplorer::ProjectExplorerPlugin::currentProject(),
653 654 655 656
                            textDocument()->filePath(),
                            document(),
                            cppEditorDocument()->isObjCEnabled(),
                            position(),
657
                            reason);
658
        }
Leandro Melo's avatar
Leandro Melo committed
659
    } else if (kind == TextEditor::QuickFix) {
660
        if (!isSemanticInfoValid())
Leandro Melo's avatar
Leandro Melo committed
661
            return 0;
662
        return new CppQuickFixAssistInterface(const_cast<CppEditorWidget *>(this), reason);
663 664
    } else {
        return BaseTextEditorWidget::createAssistInterface(kind, reason);
Leandro Melo's avatar
Leandro Melo committed
665 666 667 668
    }
    return 0;
}

669
QSharedPointer<FunctionDeclDefLink> CppEditorWidget::declDefLink() const
670
{
671
    return d->m_declDefLink;
672 673
}

674
void CppEditorWidget::onRefactorMarkerClicked(const TextEditor::RefactorMarker &marker)
675 676 677 678 679
{
    if (marker.data.canConvert<FunctionDeclDefLink::Marker>())
        applyDeclDefLinkChanges(true);
}

680
void CppEditorWidget::updateFunctionDeclDefLink()
681 682 683
{
    const int pos = textCursor().selectionStart();

684
    // if there's already a link, abort it if the cursor is outside or the name changed
685
    // (adding a prefix is an exception since the user might type a return type)
686 687 688 689 690
    if (d->m_declDefLink
            && (pos < d->m_declDefLink->linkSelection.selectionStart()
                || pos > d->m_declDefLink->linkSelection.selectionEnd()
                || !d->m_declDefLink->nameSelection.selectedText().trimmed()
                    .endsWith(d->m_declDefLink->nameInitial))) {
691 692 693 694 695
        abortDeclDefLink();
        return;
    }

    // don't start a new scan if there's one active and the cursor is already in the scanned area
696
    const QTextCursor scannedSelection = d->m_declDefLinkFinder->scannedSelection();
697 698 699 700 701 702
    if (!scannedSelection.isNull()
            && scannedSelection.selectionStart() <= pos
            && scannedSelection.selectionEnd() >= pos) {
        return;
    }

703
    d->m_updateFunctionDeclDefLinkTimer.start();
704 705
}

706
void CppEditorWidget::updateFunctionDeclDefLinkNow()
707
{
hjk's avatar
hjk committed
708
    if (Core::EditorManager::currentEditor() != editor())
709
        return;
710

711 712
    const Snapshot semanticSnapshot = d->m_lastSemanticInfo.snapshot;
    const Document::Ptr semanticDoc = d->m_lastSemanticInfo.doc;
713

714
    if (d->m_declDefLink) {
715
        // update the change marker
716
        const Utils::ChangeSet changes = d->m_declDefLink->changes(semanticSnapshot);
717
        if (changes.isEmpty())
718
            d->m_declDefLink->hideMarker(this);
719
        else
720
            d->m_declDefLink->showMarker(this);
721 722
        return;
    }
723 724

    if (!isSemanticInfoValidExceptLocalUses())
725 726 727
        return;

    Snapshot snapshot = CppModelManagerInterface::instance()->snapshot();
728
    snapshot.insert(semanticDoc);
729

730
    d->m_declDefLinkFinder->startFindLinkAt(textCursor(), semanticDoc, snapshot);
731 732
}

733
void CppEditorWidget::onFunctionDeclDefLinkFound(QSharedPointer<FunctionDeclDefLink> link)
734 735
{
    abortDeclDefLink();
736 737 738
    d->m_declDefLink = link;
    Core::IDocument *targetDocument
            = Core::DocumentModel::documentForFilePath( d->m_declDefLink->targetFile->fileName());
739
    if (textDocument() != targetDocument) {
740 741
        if (auto textDocument = qobject_cast<TextEditor::BaseTextDocument *>(targetDocument))
            connect(textDocument, SIGNAL(contentsChanged()),
742
                    this, SLOT(abortDeclDefLink()));
743
    }
744

745 746
}

747
void CppEditorWidget::onFilePathChanged()
748
{
749
    QTC_ASSERT(d->m_modelManager, return);
750
    QByteArray additionalDirectives;
751
    const QString &filePath = textDocument()->filePath();
752 753 754 755 756 757
    if (!filePath.isEmpty()) {
        const QString &projectFile = ProjectExplorer::SessionManager::value(
                    QLatin1String(Constants::CPP_PREPROCESSOR_PROJECT_PREFIX) + filePath).toString();
        additionalDirectives = ProjectExplorer::SessionManager::value(
                    projectFile + QLatin1Char(',') + filePath).toString().toUtf8();

758 759
        BaseEditorDocumentParser *parser = BaseEditorDocumentParser::get(filePath);
        QTC_ASSERT(parser, return);
760 761
        parser->setProjectPart(d->m_modelManager->projectPartForProjectFile(projectFile));
        parser->setEditorDefines(additionalDirectives);
762
    }
763 764
    d->m_preprocessorButton->setProperty("highlightWidget", !additionalDirectives.trimmed().isEmpty());
    d->m_preprocessorButton->update();
765 766
}

767
void CppEditorWidget::applyDeclDefLinkChanges(bool jumpToMatch)
768
{
769
    if (!d->m_declDefLink)
770
        return;
771
    d->m_declDefLink->apply(this, jumpToMatch);
772
    abortDeclDefLink();
773 774 775
    updateFunctionDeclDefLink();
}

776
FollowSymbolUnderCursor *CppEditorWidget::followSymbolUnderCursorDelegate()
777
{
778
    return d->m_followSymbolUnderCursor.data();
779 780
}

781
void CppEditorWidget::abortDeclDefLink()
782
{
783
    if (!d->m_declDefLink)
784