cppeditor.cpp 43.4 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"
con's avatar
con committed
33
#include "cppeditorconstants.h"
34
#include "cppeditoroutline.h"
35
#include "cppeditorplugin.h"
36
#include "cppdocumentationcommenthelper.h"
37
#include "cppfollowsymbolundercursor.h"
con's avatar
con committed
38
#include "cpphighlighter.h"
39
#include "cpplocalrenaming.h"
40
#include "cpppreprocessordialog.h"
Leandro Melo's avatar
Leandro Melo committed
41
#include "cppquickfixassistant.h"
Roberto Raggi's avatar
Roberto Raggi committed
42

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

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

#include <projectexplorer/session.h>

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

#include <utils/qtcassert.h>

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

75
#include <QAction>
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

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

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

con's avatar
con committed
93 94
namespace {

95
class CanonicalSymbol
96 97
{
public:
98 99 100 101 102 103
    CanonicalSymbol(CPPEditorWidget *editor,
                    const Document::Ptr &document,
                    const Snapshot &snapshot)
        : m_editor(editor),
          m_document(document),
          m_snapshot(snapshot)
104
    {
105 106
        m_typeOfExpression.init(document, snapshot);
        m_typeOfExpression.setExpandTemplates(true);
107 108 109 110
    }

    const LookupContext &context() const
    {
111
        return m_typeOfExpression.context();
112 113
    }

114 115
    Scope *getScopeAndExpression(const QTextCursor &cursor, QString *code)
    {
116
        if (!m_document)
117 118 119
            return 0;

        QTextCursor tc = cursor;
120 121 122
        int line, column;
        m_editor->convertPosition(tc.position(), &line, &column);
        ++column; // 1-based line and 1-based column
123 124

        int pos = tc.position();
125 126 127
        QTextDocument *textDocument = m_editor->document();
        if (!isValidIdentifierChar(textDocument->characterAt(pos)))
            if (!(pos > 0 && isValidIdentifierChar(textDocument->characterAt(pos - 1))))
128 129
                return 0;

130
        while (isValidIdentifierChar(textDocument->characterAt(pos)))
131 132 133
            ++pos;
        tc.setPosition(pos);

134 135
        ExpressionUnderCursor expressionUnderCursor;
        *code = expressionUnderCursor(tc);
136
        return m_document->scopeAt(line, column);
137 138 139 140 141 142 143 144
    }

    Symbol *operator()(const QTextCursor &cursor)
    {
        QString code;

        if (Scope *scope = getScopeAndExpression(cursor, &code))
            return operator()(scope, code);
145

146 147 148 149 150
        return 0;
    }

    Symbol *operator()(Scope *scope, const QString &code)
    {
151
        return canonicalSymbol(scope, code, m_typeOfExpression);
152 153
    }

Nikolai Kosjar's avatar
Nikolai Kosjar committed
154 155
    static Symbol *canonicalSymbol(Scope *scope, const QString &code,
                                   TypeOfExpression &typeOfExpression)
156
    {
157 158
        const QList<LookupItem> results =
                typeOfExpression(code.toUtf8(), scope, TypeOfExpression::Preprocess);
159

Roberto Raggi's avatar
Roberto Raggi committed
160 161
        for (int i = results.size() - 1; i != -1; --i) {
            const LookupItem &r = results.at(i);
162
            Symbol *decl = r.declaration();
Roberto Raggi's avatar
Roberto Raggi committed
163

164
            if (!(decl && decl->enclosingScope()))
Roberto Raggi's avatar
Roberto Raggi committed
165 166
                break;

167
            if (Class *classScope = r.declaration()->enclosingScope()->asClass()) {
168 169 170
                const Identifier *declId = decl->identifier();
                const Identifier *classId = classScope->identifier();

171
                if (classId && classId->match(declId))
172 173
                    continue; // skip it, it's a ctor or a dtor.

174
                if (Function *funTy = r.declaration()->type()->asFunctionType()) {
175 176 177 178
                    if (funTy->isVirtual())
                        return r.declaration();
                }
            }
Roberto Raggi's avatar
Roberto Raggi committed
179 180 181
        }

        for (int i = 0; i < results.size(); ++i) {
182 183 184 185 186 187 188 189
            const LookupItem &r = results.at(i);

            if (r.declaration())
                return r.declaration();
        }

        return 0;
    }
190

191 192 193 194 195
private:
    CPPEditorWidget *m_editor;
    TypeOfExpression m_typeOfExpression;
    Document::Ptr m_document;
    Snapshot m_snapshot;
196 197
};

198 199 200 201 202 203 204 205
QTimer *newSingleShotTimer(QObject *parent, int msecInterval)
{
    QTimer *timer = new QTimer(parent);
    timer->setSingleShot(true);
    timer->setInterval(msecInterval);
    return timer;
}

con's avatar
con committed
206 207
} // end of anonymous namespace

208 209 210
namespace CppEditor {
namespace Internal {

211 212
CPPEditor::CPPEditor(CPPEditorWidget *editor)
    : BaseTextEditor(editor)
con's avatar
con committed
213
{
214 215 216
    m_context.add(CppEditor::Constants::C_CPPEDITOR);
    m_context.add(ProjectExplorer::Constants::LANG_CXX);
    m_context.add(TextEditor::Constants::C_TEXTEDITOR);
217
    setDuplicateSupported(true);
con's avatar
con committed
218 219
}

220 221
Q_GLOBAL_STATIC(CppTools::SymbolFinder, symbolFinder)

222 223 224 225 226 227 228 229 230 231 232
class CPPEditorWidgetPrivate
{
public:
    CPPEditorWidgetPrivate(CPPEditorWidget *q);

public:
    CPPEditorWidget *q;

    QPointer<CppTools::CppModelManagerInterface> m_modelManager;

    CPPEditorDocument *m_cppEditorDocument;
233 234
    CppEditorOutline *m_cppEditorOutline;

235 236
    CppDocumentationCommentHelper m_cppDocumentationCommentHelper;

237 238 239 240
    QTimer *m_updateUsesTimer;
    QTimer *m_updateFunctionDeclDefLinkTimer;
    QHash<int, QTextCharFormat> m_semanticHighlightFormatMap;

241
    CppLocalRenaming m_localRenaming;
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263

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

CPPEditorWidgetPrivate::CPPEditorWidgetPrivate(CPPEditorWidget *q)
    : q(q)
    , m_modelManager(CppModelManagerInterface::instance())
    , m_cppEditorDocument(qobject_cast<CPPEditorDocument *>(q->baseTextDocument()))
264
    , m_cppEditorOutline(new CppEditorOutline(q))
265
    , m_cppDocumentationCommentHelper(q)
266
    , m_localRenaming(q)
267 268 269 270 271 272 273 274 275
    , m_highlightRevision(0)
    , m_referencesRevision(0)
    , m_referencesCursorPosition(0)
    , m_declDefLinkFinder(new FunctionDeclDefLinkFinder(q))
    , m_followSymbolUnderCursor(new FollowSymbolUnderCursor(q))
    , m_preprocessorButton(0)
{
}

276
CPPEditorWidget::CPPEditorWidget(QWidget *parent)
277
    : TextEditor::BaseTextEditorWidget(new CPPEditorDocument(), parent)
con's avatar
con committed
278
{
279
    baseTextDocument()->setIndenter(new CppTools::CppQtStyleIndenter);
280 281 282 283 284 285 286 287 288 289 290
    ctor();
}

CPPEditorWidget::CPPEditorWidget(CPPEditorWidget *other)
    : TextEditor::BaseTextEditorWidget(other)
{
    ctor();
}

void CPPEditorWidget::ctor()
{
291
    d.reset(new CPPEditorWidgetPrivate(this));
292

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

con's avatar
con committed
295 296
    setParenthesesMatchingEnabled(true);
    setMarksVisible(true);
297
    setCodeFoldingSupported(true);
298
    setAutoCompleter(new CppAutoCompleter);
dt's avatar
dt committed
299

300 301
    if (d->m_modelManager) {
        CppEditorSupport *editorSupport = d->m_modelManager->cppEditorSupport(editor());
302 303 304 305
        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
306 307
        connect(editorSupport, SIGNAL(highlighterStarted(QFuture<TextEditor::HighlightingResult>*,uint)),
                this, SLOT(highlighterStarted(QFuture<TextEditor::HighlightingResult>*,uint)));
con's avatar
con committed
308
    }
309

310 311 312
    connect(this, SIGNAL(refactorMarkerClicked(TextEditor::RefactorMarker)),
            this, SLOT(onRefactorMarkerClicked(TextEditor::RefactorMarker)));

313
    connect(d->m_declDefLinkFinder, SIGNAL(foundLink(QSharedPointer<FunctionDeclDefLink>)),
314
            this, SLOT(onFunctionDeclDefLinkFound(QSharedPointer<FunctionDeclDefLink>)));
315

316 317
    connect(baseTextDocument(), SIGNAL(filePathChanged(QString,QString)),
            this, SLOT(onFilePathChanged()));
318 319 320 321 322

    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
323 324
}

325
CPPEditorWidget::~CPPEditorWidget()
con's avatar
con committed
326
{
327 328
    if (d->m_modelManager)
        d->m_modelManager->deleteCppEditorSupport(editor());
con's avatar
con committed
329 330
}

331 332
CPPEditorDocument *CPPEditorWidget::cppEditorDocument() const
{
333
    return d->m_cppEditorDocument;
334 335
}

336 337 338 339 340
CppEditorOutline *CPPEditorWidget::outline() const
{
    return d->m_cppEditorOutline;
}

341
TextEditor::BaseTextEditor *CPPEditorWidget::createEditor()
con's avatar
con committed
342
{
343
    CPPEditor *editable = new CPPEditor(this);
con's avatar
con committed
344 345 346 347
    createToolBar(editable);
    return editable;
}

348
void CPPEditorWidget::createToolBar(CPPEditor *editor)
con's avatar
con committed
349
{
350
    d->m_updateUsesTimer = newSingleShotTimer(this, UPDATE_USES_INTERVAL);
351 352
    connect(d->m_updateUsesTimer, SIGNAL(timeout()), this, SLOT(updateUsesNow()));

353
    d->m_updateFunctionDeclDefLinkTimer = newSingleShotTimer(this, UPDATE_FUNCTION_DECL_DEF_LINK_INTERVAL);
354
    connect(d->m_updateFunctionDeclDefLinkTimer, SIGNAL(timeout()),
Nikolai Kosjar's avatar
Nikolai Kosjar committed
355
            this, SLOT(updateFunctionDeclDefLinkNow()));
356

357 358
    connect(this, SIGNAL(cursorPositionChanged()),
            d->m_cppEditorOutline, SLOT(updateIndex()));
con's avatar
con committed
359

360
    // set up slots to document changes
361 362
    connect(document(), SIGNAL(contentsChange(int,int,int)),
            this, SLOT(onContentsChanged(int,int,int)));
con's avatar
con committed
363

364 365 366
    // 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
367 368 369 370 371

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

372 373
    d->m_preprocessorButton = new QToolButton(this);
    d->m_preprocessorButton->setText(QLatin1String("#"));
374 375 376
    Core::Command *cmd = Core::ActionManager::command(Constants::OPEN_PREPROCESSOR_DIALOG);
    connect(cmd, SIGNAL(keySequenceChanged()), this, SLOT(updatePreprocessorButtonTooltip()));
    updatePreprocessorButtonTooltip();
377 378
    connect(d->m_preprocessorButton, SIGNAL(clicked()), this, SLOT(showPreProcessorWidget()));
    editor->insertExtraToolBarWidget(TextEditor::BaseTextEditor::Left, d->m_preprocessorButton);
379
    editor->insertExtraToolBarWidget(TextEditor::BaseTextEditor::Left, d->m_cppEditorOutline->widget());
con's avatar
con committed
380 381
}

382
void CPPEditorWidget::paste()
mae's avatar
mae committed
383
{
384
    if (d->m_localRenaming.handlePaste())
mae's avatar
mae committed
385 386
        return;

387
    BaseTextEditorWidget::paste();
mae's avatar
mae committed
388 389
}

390
void CPPEditorWidget::cut()
mae's avatar
mae committed
391
{
392
    if (d->m_localRenaming.handlePaste())
mae's avatar
mae committed
393 394
        return;

395
    BaseTextEditorWidget::cut();
mae's avatar
mae committed
396 397
}

398 399
void CPPEditorWidget::selectAll()
{
400
    if (d->m_localRenaming.handleSelectAll())
mae's avatar
mae committed
401
        return;
402

403
    BaseTextEditorWidget::selectAll();
404 405
}

406 407 408
/// \brief Called by \c CppEditorSupport when the document corresponding to the
///        file in this editor is updated.
void CPPEditorWidget::onDocumentUpdated()
con's avatar
con committed
409
{
410
    d->m_cppEditorOutline->update();
con's avatar
con committed
411 412
}

413
const Macro *CPPEditorWidget::findCanonicalMacro(const QTextCursor &cursor, Document::Ptr doc) const
Christian Kamm's avatar
Christian Kamm committed
414
{
415
    if (!doc)
Christian Kamm's avatar
Christian Kamm committed
416 417 418 419 420
        return 0;

    int line, col;
    convertPosition(cursor.position(), &line, &col);

421 422
    if (const Macro *macro = doc->findMacroDefinitionAt(line)) {
        QTextCursor macroCursor = cursor;
423
        const QByteArray name = identifierUnderCursor(&macroCursor).toUtf8();
424
        if (macro->name() == name)
425 426
            return macro;
    } else if (const Document::MacroUse *use = doc->findMacroUseAt(cursor.position())) {
427
        return &use->macro();
428
    }
Christian Kamm's avatar
Christian Kamm committed
429 430 431

    return 0;
}
432

433
void CPPEditorWidget::findUsages()
434
{
435
    if (!d->m_modelManager)
436 437
        return;

438
    SemanticInfo info = d->m_lastSemanticInfo;
439
    info.snapshot = CppModelManagerInterface::instance()->snapshot();
440
    info.snapshot.insert(info.doc);
441

442
    if (const Macro *macro = findCanonicalMacro(textCursor(), info.doc)) {
443
        d->m_modelManager->findMacroUsages(*macro);
444
    } else {
445
        CanonicalSymbol cs(this, info.doc, info.snapshot);
446 447
        Symbol *canonicalSymbol = cs(textCursor());
        if (canonicalSymbol)
448
            d->m_modelManager->findUsages(canonicalSymbol, cs.context());
449
    }
450 451
}

Nikolai Kosjar's avatar
Nikolai Kosjar committed
452
void CPPEditorWidget::renameUsages(const QString &replacement)
453
{
454
    if (!d->m_modelManager)
455 456
        return;

457
    SemanticInfo info = d->m_lastSemanticInfo;
458
    info.snapshot = CppModelManagerInterface::instance()->snapshot();
459 460
    info.snapshot.insert(info.doc);

461
    if (const Macro *macro = findCanonicalMacro(textCursor(), info.doc)) {
462
        d->m_modelManager->renameMacroUsages(*macro, replacement);
463
    } else {
464
        CanonicalSymbol cs(this, info.doc, info.snapshot);
465 466
        if (Symbol *canonicalSymbol = cs(textCursor()))
            if (canonicalSymbol->identifier() != 0)
467
                d->m_modelManager->renameUsages(canonicalSymbol, cs.context(), replacement);
468
    }
469 470
}

471
void CPPEditorWidget::markSymbolsNow()
472
{
473 474 475 476 477
    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
478
        TranslationUnit *unit = info.doc->translationUnit();
479
        const QList<int> result = d->m_referencesWatcher->result();
480

Erik Verbruggen's avatar
Erik Verbruggen committed
481
        QList<QTextEdit::ExtraSelection> selections;
482

Erik Verbruggen's avatar
Erik Verbruggen committed
483 484 485
        foreach (int index, result) {
            unsigned line, column;
            unit->getTokenPosition(index, &line, &column);
486

Erik Verbruggen's avatar
Erik Verbruggen committed
487 488
            if (column)
                --column;  // adjust the column position.
489

490
            const int len = unit->tokenAt(index).utf16chars();
491

Erik Verbruggen's avatar
Erik Verbruggen committed
492 493 494
            QTextCursor cursor(document()->findBlockByNumber(line - 1));
            cursor.setPosition(cursor.position() + column);
            cursor.setPosition(cursor.position() + len, QTextCursor::KeepAnchor);
495

Erik Verbruggen's avatar
Erik Verbruggen committed
496
            QTextEdit::ExtraSelection sel;
497
            sel.format = textCharFormat(TextEditor::C_OCCURRENCES);
Erik Verbruggen's avatar
Erik Verbruggen committed
498 499 500
            sel.cursor = cursor;
            selections.append(sel);
        }
501

Erik Verbruggen's avatar
Erik Verbruggen committed
502
        setExtraSelections(CodeSemanticsSelection, selections);
Roberto Raggi's avatar
Roberto Raggi committed
503
    }
504
    d->m_referencesWatcher.reset();
Roberto Raggi's avatar
Roberto Raggi committed
505 506
}

Nikolai Kosjar's avatar
Nikolai Kosjar committed
507 508
static QList<int> lazyFindReferences(Scope *scope, QString code, Document::Ptr doc,
                                     Snapshot snapshot)
509 510
{
    TypeOfExpression typeOfExpression;
511 512
    snapshot.insert(doc);
    typeOfExpression.init(doc, snapshot);
513 514
    // make possible to instantiate templates
    typeOfExpression.setExpandTemplates(true);
515
    if (Symbol *canonicalSymbol = CanonicalSymbol::canonicalSymbol(scope, code, typeOfExpression))
Nikolai Kosjar's avatar
Nikolai Kosjar committed
516 517
        return CppModelManagerInterface::instance()->references(canonicalSymbol,
                                                                typeOfExpression.context());
518 519 520
    return QList<int>();
}

521
void CPPEditorWidget::markSymbols(const QTextCursor &tc, const SemanticInfo &info)
522
{
523
    d->m_localRenaming.stop();
524

525
    if (!info.doc)
526
        return;
527
    const QTextCharFormat &occurrencesFormat = textCharFormat(TextEditor::C_OCCURRENCES);
528 529 530 531 532 533
    if (const Macro *macro = findCanonicalMacro(textCursor(), info.doc)) {
        QList<QTextEdit::ExtraSelection> selections;

        //Macro definition
        if (macro->fileName() == info.doc->fileName()) {
            QTextCursor cursor(document());
534
            cursor.setPosition(macro->utf16CharOffset());
Nikolai Kosjar's avatar
Nikolai Kosjar committed
535
            cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor,
536
                                macro->nameToQString().size());
537 538

            QTextEdit::ExtraSelection sel;
539
            sel.format = occurrencesFormat;
540 541 542 543 544
            sel.cursor = cursor;
            selections.append(sel);
        }

        //Other macro uses
545
        foreach (const Document::MacroUse &use, info.doc->macroUses()) {
546 547
            const Macro &useMacro = use.macro();
            if (useMacro.line() != macro->line()
548
                    || useMacro.utf16CharOffset() != macro->utf16CharOffset()
549 550
                    || useMacro.length() != macro->length()
                    || useMacro.fileName() != macro->fileName())
551 552 553
                continue;

            QTextCursor cursor(document());
554 555
            cursor.setPosition(use.utf16charsBegin());
            cursor.setPosition(use.utf16charsEnd(), QTextCursor::KeepAnchor);
556 557

            QTextEdit::ExtraSelection sel;
558
            sel.format = occurrencesFormat;
559 560 561
            sel.cursor = cursor;
            selections.append(sel);
        }
562

563 564
        setExtraSelections(CodeSemanticsSelection, selections);
    } else {
565
        CanonicalSymbol cs(this, info.doc, info.snapshot);
566
        QString expression;
567
        if (Scope *scope = cs.getScopeAndExpression(tc, &expression)) {
568 569 570 571 572 573 574 575 576
            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));
577 578 579
        } else {
            const QList<QTextEdit::ExtraSelection> selections = extraSelections(CodeSemanticsSelection);

580
            if (!selections.isEmpty())
581 582
                setExtraSelections(CodeSemanticsSelection, QList<QTextEdit::ExtraSelection>());
        }
583 584 585
    }
}

586
void CPPEditorWidget::renameSymbolUnderCursor()
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
587
{
588
    if (!d->m_modelManager)
589 590
        return;

591 592
    CppEditorSupport *ces = d->m_modelManager->cppEditorSupport(editor());
    updateSemanticInfo(ces->recalculateSemanticInfo());
593

594 595
    if (!d->m_localRenaming.start()) // Rename local symbol
        renameUsages(); // Rename non-local symbol or macro
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
596 597
}

598
void CPPEditorWidget::onContentsChanged(int position, int charsRemoved, int charsAdded)
599
{
600 601
    Q_UNUSED(position)
    Q_UNUSED(charsAdded)
602 603 604 605 606

    if (charsRemoved > 0)
        updateUses();
}

607 608
void CPPEditorWidget::updatePreprocessorButtonTooltip()
{
609
    QTC_ASSERT(d->m_preprocessorButton, return);
610 611
    Core::Command *cmd = Core::ActionManager::command(Constants::OPEN_PREPROCESSOR_DIALOG);
    QTC_ASSERT(cmd, return);
612
    d->m_preprocessorButton->setToolTip(cmd->action()->toolTip());
613 614
}

615 616
QList<QTextEdit::ExtraSelection> CPPEditorWidget::createSelectionsFromUses(
        const QList<SemanticInfo::Use> &uses)
Roberto Raggi's avatar
Roberto Raggi committed
617
{
618 619
    QList<QTextEdit::ExtraSelection> result;
    const bool isUnused = uses.size() == 1;
Roberto Raggi's avatar
Roberto Raggi committed
620

Roberto Raggi's avatar
Roberto Raggi committed
621
    foreach (const SemanticInfo::Use &use, uses) {
622 623
        if (use.isInvalid())
            continue;
Roberto Raggi's avatar
Roberto Raggi committed
624

625
        QTextEdit::ExtraSelection sel;
Roberto Raggi's avatar
Roberto Raggi committed
626
        if (isUnused)
627
            sel.format = textCharFormat(TextEditor::C_OCCURRENCES_UNUSED);
Roberto Raggi's avatar
Roberto Raggi committed
628
        else
629
            sel.format = textCharFormat(TextEditor::C_OCCURRENCES);
Roberto Raggi's avatar
Roberto Raggi committed
630

631 632
        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
633

634
        sel.cursor = QTextCursor(document());
Roberto Raggi's avatar
Roberto Raggi committed
635 636
        sel.cursor.setPosition(anchor);
        sel.cursor.setPosition(position, QTextCursor::KeepAnchor);
Roberto Raggi's avatar
Roberto Raggi committed
637

638
        result.append(sel);
Roberto Raggi's avatar
Roberto Raggi committed
639
    }
640 641

    return result;
Roberto Raggi's avatar
Roberto Raggi committed
642 643
}

644
void CPPEditorWidget::updateUses()
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
645
{
646
    // Block premature semantic info calculation when editor is created.
647 648
    if (d->m_modelManager && d->m_modelManager->cppEditorSupport(editor())->initialized())
        d->m_updateUsesTimer->start();
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
649 650
}

651
void CPPEditorWidget::updateUsesNow()
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
652
{
653
    if (d->m_localRenaming.isActive())
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
654 655
        return;

Roberto Raggi's avatar
Roberto Raggi committed
656
    semanticRehighlight();
con's avatar
con committed
657 658
}

659
void CPPEditorWidget::highlightSymbolUsages(int from, int to)
660
{
661
    if (editorRevision() != d->m_highlightRevision)
662 663
        return; // outdated

664
    else if (!d->m_highlightWatcher || d->m_highlightWatcher->isCanceled())
665 666
        return; // aborted

667 668
    TextEditor::SyntaxHighlighter *highlighter = baseTextDocument()->syntaxHighlighter();
    QTC_ASSERT(highlighter, return);
669

670
    TextEditor::SemanticHighlighter::incrementalApplyExtraAdditionalFormats(
671
                highlighter, d->m_highlightWatcher->future(), from, to, d->m_semanticHighlightFormatMap);
672 673
}

674
void CPPEditorWidget::finishHighlightSymbolUsages()
675
{
676 677 678 679
    QTC_ASSERT(d->m_highlightWatcher, return);
    if (!d->m_highlightWatcher->isCanceled()
            && editorRevision() == d->m_highlightRevision
            && !d->m_lastSemanticInfo.doc.isNull()) {
Erik Verbruggen's avatar
Erik Verbruggen committed
680 681 682 683
        TextEditor::SyntaxHighlighter *highlighter = baseTextDocument()->syntaxHighlighter();
        QTC_CHECK(highlighter);
        if (highlighter)
            TextEditor::SemanticHighlighter::clearExtraAdditionalFormatsUntilEnd(highlighter,
684
                d->m_highlightWatcher->future());
Erik Verbruggen's avatar
Erik Verbruggen committed
685
    }
686
    d->m_highlightWatcher.reset();
687 688
}

689
void CPPEditorWidget::switchDeclarationDefinition(bool inNextSplit)
con's avatar
con committed
690
{
691
    if (!d->m_modelManager)
con's avatar
con committed
692 693
        return;

694
    if (!d->m_lastSemanticInfo.doc)
695
        return;
con's avatar
con committed
696

697 698 699 700
    // Find function declaration or definition under cursor
    Function *functionDefinitionSymbol = 0;
    Symbol *functionDeclarationSymbol = 0;

701
    ASTPath astPathFinder(d->m_lastSemanticInfo.doc);
702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
    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
720

721 722 723 724
    // Link to function definition/declaration
    CPPEditorWidget::Link symbolLink;
    if (functionDeclarationSymbol) {
        symbolLink = linkToSymbol(symbolFinder()
725
            ->findMatchingDefinition(functionDeclarationSymbol, d->m_modelManager->snapshot()));
726
    } else if (functionDefinitionSymbol) {
727 728
        const Snapshot snapshot = d->m_modelManager->snapshot();
        LookupContext context(d->m_lastSemanticInfo.doc, snapshot);
729 730 731 732 733 734 735 736
        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()) {
737
                    if (funTy->match(functionDefinitionSymbol)) {
738 739 740 741
                        if (decl != functionDefinitionSymbol && binding == r.binding())
                            best.prepend(decl);
                        else
                            best.append(decl);
742 743
                    }
                }
744 745
            }
        }
746

747 748 749
        if (best.isEmpty())
            return;
        symbolLink = linkToSymbol(best.first());
con's avatar
con committed
750
    }
751 752 753 754

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

757
QString CPPEditorWidget::identifierUnderCursor(QTextCursor *macroCursor)
758 759 760 761 762 763
{
    macroCursor->movePosition(QTextCursor::StartOfWord);
    macroCursor->movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
    return macroCursor->selectedText();
}

764 765
CPPEditorWidget::Link CPPEditorWidget::findLinkAt(const QTextCursor &cursor, bool resolveTarget,
                                                  bool inNextSplit)
con's avatar
con committed
766
{
767
    if (!d->m_modelManager)
768
        return Link();
769

770 771 772 773 774
    return d->m_followSymbolUnderCursor->findLink(cursor, resolveTarget,
                                                  d->m_modelManager->snapshot(),
                                                  d->m_lastSemanticInfo.doc,
                                                  symbolFinder(),
                                                  inNextSplit);
con's avatar
con committed
775 776
}

777
unsigned CPPEditorWidget::editorRevision() const
778 779 780 781
{
    return document()->revision();
}

782
bool CPPEditorWidget::isOutdated() const
783
{
784
    if (d->m_lastSemanticInfo.revision != editorRevision())
785 786 787 788 789
        return true;

    return false;
}

790
SemanticInfo CPPEditorWidget::semanticInfo() const
Roberto Raggi's avatar
Roberto Raggi committed
791
{
792
    return d->m_lastSemanticInfo;
Roberto Raggi's avatar
Roberto Raggi committed
793 794
}

795
bool CPPEditorWidget::event(QEvent *e)
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
796 797 798
{
    switch (e->type()) {
    case QEvent::ShortcutOverride:
799
        // handle escape manually if a rename is active
800
        if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape && d->m_localRenaming.isActive()) {
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
801 802 803 804 805 806 807 808
            e->accept();
            return true;
        }
        break;
    default:
        break;
    }

809
    return BaseTextEditorWidget::event(e);
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
810 811
}

812
void CPPEditorWidget::performQuickFix(int index)
813
{
814
    TextEditor::QuickFixOperation::Ptr op = d->m_quickFixes.at(index);
815
    op->perform();
816 817
}

818
void CPPEditorWidget::contextMenuEvent(QContextMenuEvent *e)
con's avatar
con committed
819
{
Roberto Raggi's avatar
Roberto Raggi committed
820 821 822
    // ### enable
    // updateSemanticInfo(m_semanticHighlighter->semanticInfo(currentSource()));

823
    QPointer<QMenu> menu(new QMenu(this));
con's avatar
con committed
824

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