cppeditor.cpp 70.6 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
2
3
4
**
** This file is part of Qt Creator
**
con's avatar
con committed
5
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
6
**
7
** Contact: Nokia Corporation (qt-info@nokia.com)
con's avatar
con committed
8
**
con's avatar
con committed
9
** No Commercial Usage
10
**
con's avatar
con committed
11
12
13
14
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
15
**
16
** GNU Lesser General Public License Usage
17
**
18
19
20
21
22
23
** 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.
24
**
con's avatar
con committed
25
26
27
28
29
30
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
con's avatar
con committed
31
**
32
**************************************************************************/
hjk's avatar
hjk committed
33

con's avatar
con committed
34
35
36
37
#include "cppeditor.h"
#include "cppeditorconstants.h"
#include "cppplugin.h"
#include "cpphighlighter.h"
Roberto Raggi's avatar
Roberto Raggi committed
38
#include "cppchecksymbols.h"
39
#include "cppquickfix.h"
40
#include "cpplocalsymbols.h"
41
#include "cppquickfixcollector.h"
42
#include "cppqtstyleindenter.h"
43
#include "cppautocompleter.h"
Roberto Raggi's avatar
Roberto Raggi committed
44

con's avatar
con committed
45
#include <AST.h>
46
#include <Control.h>
con's avatar
con committed
47
48
49
50
51
52
#include <Token.h>
#include <Scope.h>
#include <Symbols.h>
#include <Names.h>
#include <CoreTypes.h>
#include <Literals.h>
53
#include <ASTVisitor.h>
54
#include <SymbolVisitor.h>
55
#include <TranslationUnit.h>
56
#include <cplusplus/ASTPath.h>
57
#include <cplusplus/ModelManagerInterface.h>
con's avatar
con committed
58
#include <cplusplus/ExpressionUnderCursor.h>
Roberto Raggi's avatar
Roberto Raggi committed
59
#include <cplusplus/TypeOfExpression.h>
con's avatar
con committed
60
61
62
#include <cplusplus/Overview.h>
#include <cplusplus/OverviewModel.h>
#include <cplusplus/SimpleLexer.h>
63
#include <cplusplus/MatchingText.h>
64
#include <cplusplus/BackwardsScanner.h>
65
66
#include <cplusplus/FastPreprocessor.h>

Roberto Raggi's avatar
Roberto Raggi committed
67
#include <cpptools/cpptoolsplugin.h>
68
#include <cpptools/cpptoolsconstants.h>
Christian Kamm's avatar
Christian Kamm committed
69
#include <cpptools/cppcodeformatter.h>
con's avatar
con committed
70
71

#include <coreplugin/icore.h>
72
#include <coreplugin/actionmanager/actionmanager.h>
73
#include <coreplugin/actionmanager/actioncontainer.h>
74
#include <coreplugin/actionmanager/command.h>
75
#include <coreplugin/uniqueidmanager.h>
con's avatar
con committed
76
77
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/editormanager/editormanager.h>
dt's avatar
dt committed
78
#include <coreplugin/mimedatabase.h>
79
#include <utils/uncommentselection.h>
80
#include <extensionsystem/pluginmanager.h>
con's avatar
con committed
81
82
#include <projectexplorer/projectexplorerconstants.h>
#include <texteditor/basetextdocument.h>
83
#include <texteditor/basetextdocumentlayout.h>
con's avatar
con committed
84
#include <texteditor/fontsettings.h>
85
#include <texteditor/tabsettings.h>
con's avatar
con committed
86
87
88
89
90
#include <texteditor/texteditorconstants.h>

#include <QtCore/QDebug>
#include <QtCore/QTime>
#include <QtCore/QTimer>
91
#include <QtCore/QStack>
92
#include <QtCore/QSettings>
93
#include <QtCore/QSignalMapper>
con's avatar
con committed
94
#include <QtGui/QAction>
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
95
#include <QtGui/QApplication>
96
#include <QtGui/QHeaderView>
con's avatar
con committed
97
98
99
100
101
#include <QtGui/QLayout>
#include <QtGui/QMenu>
#include <QtGui/QShortcut>
#include <QtGui/QTextEdit>
#include <QtGui/QComboBox>
con's avatar
con committed
102
#include <QtGui/QToolBar>
con's avatar
con committed
103
#include <QtGui/QTreeView>
104
#include <QtGui/QSortFilterProxyModel>
con's avatar
con committed
105

106
107
#include <sstream>

Roberto Raggi's avatar
Roberto Raggi committed
108
enum {
109
110
    UPDATE_OUTLINE_INTERVAL = 500,
    UPDATE_USES_INTERVAL = 500
Roberto Raggi's avatar
Roberto Raggi committed
111
112
};

Roberto Raggi's avatar
Roberto Raggi committed
113
114
115
using namespace CPlusPlus;
using namespace CppEditor::Internal;

116
117
118
119
namespace {
bool semanticHighlighterDisabled = qstrcmp(qVersion(), "4.7.0") == 0;
}

120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
static QList<QTextEdit::ExtraSelection> createSelections(QTextDocument *document,
                                                         const QList<CPlusPlus::Document::DiagnosticMessage> &msgs,
                                                         const QTextCharFormat &format)
{
    QList<QTextEdit::ExtraSelection> selections;

    foreach (const Document::DiagnosticMessage &m, msgs) {
        const int pos = document->findBlockByNumber(m.line() - 1).position() + m.column() - 1;
        if (pos < 0)
            continue;

        QTextCursor cursor(document);
        cursor.setPosition(pos);
        cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, m.length());

        QTextEdit::ExtraSelection sel;
        sel.cursor = cursor;
        sel.format = format;
        sel.format.setToolTip(m.text());
        selections.append(sel);
    }

    return selections;
}

con's avatar
con committed
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
namespace {

class OverviewTreeView : public QTreeView
{
public:
    OverviewTreeView(QWidget *parent = 0)
        : QTreeView(parent)
    {
        // TODO: Disable the root for all items (with a custom delegate?)
        setRootIsDecorated(false);
    }

    void sync()
    {
        expandAll();
        setMinimumWidth(qMax(sizeHintForColumn(0), minimumSizeHint().width()));
    }
};

164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
class OverviewProxyModel : public QSortFilterProxyModel
{
    Q_OBJECT
public:
    OverviewProxyModel(CPlusPlus::OverviewModel *sourceModel, QObject *parent) :
        QSortFilterProxyModel(parent),
        m_sourceModel(sourceModel)
    {
        setSourceModel(m_sourceModel);
    }

    bool filterAcceptsRow(int sourceRow,const QModelIndex &sourceParent) const
    {
        // ignore generated symbols, e.g. by macro expansion (Q_OBJECT)
        const QModelIndex sourceIndex = m_sourceModel->index(sourceRow, 0, sourceParent);
        CPlusPlus::Symbol *symbol = m_sourceModel->symbolFromIndex(sourceIndex);
        if (symbol && symbol->isGenerated())
            return false;

        return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
    }
private:
    CPlusPlus::OverviewModel *m_sourceModel;
};

Roberto Raggi's avatar
Roberto Raggi committed
189
190
191
192
class FunctionDefinitionUnderCursor: protected ASTVisitor
{
    unsigned _line;
    unsigned _column;
193
    DeclarationAST *_functionDefinition;
Roberto Raggi's avatar
Roberto Raggi committed
194
195

public:
Roberto Raggi's avatar
Roberto Raggi committed
196
197
    FunctionDefinitionUnderCursor(TranslationUnit *translationUnit)
        : ASTVisitor(translationUnit),
Roberto Raggi's avatar
Roberto Raggi committed
198
          _line(0), _column(0)
Roberto Raggi's avatar
Roberto Raggi committed
199
200
    { }

201
    DeclarationAST *operator()(AST *ast, unsigned line, unsigned column)
Roberto Raggi's avatar
Roberto Raggi committed
202
203
    {
        _functionDefinition = 0;
Roberto Raggi's avatar
Roberto Raggi committed
204
205
        _line = line;
        _column = column;
Roberto Raggi's avatar
Roberto Raggi committed
206
207
208
209
210
211
212
213
214
215
216
        accept(ast);
        return _functionDefinition;
    }

protected:
    virtual bool preVisit(AST *ast)
    {
        if (_functionDefinition)
            return false;

        else if (FunctionDefinitionAST *def = ast->asFunctionDefinition()) {
217
218
219
220
221
222
            return checkDeclaration(def);
        }

        else if (ObjCMethodDeclarationAST *method = ast->asObjCMethodDeclaration()) {
            if (method->function_body)
                return checkDeclaration(method);
Roberto Raggi's avatar
Roberto Raggi committed
223
224
225
226
227
        }

        return true;
    }

228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
private:
    bool checkDeclaration(DeclarationAST *ast)
    {
        unsigned startLine, startColumn;
        unsigned endLine, endColumn;
        getTokenStartPosition(ast->firstToken(), &startLine, &startColumn);
        getTokenEndPosition(ast->lastToken() - 1, &endLine, &endColumn);

        if (_line > startLine || (_line == startLine && _column >= startColumn)) {
            if (_line < endLine || (_line == endLine && _column < endColumn)) {
                _functionDefinition = ast;
                return false;
            }
        }

        return true;
    }
Roberto Raggi's avatar
Roberto Raggi committed
245
246
};

247
248
class FindFunctionDefinitions: protected SymbolVisitor
{
Roberto Raggi's avatar
Roberto Raggi committed
249
    const Name *_declarationName;
250
251
252
253
254
255
256
257
    QList<Function *> *_functions;

public:
    FindFunctionDefinitions()
        : _declarationName(0),
          _functions(0)
    { }

Roberto Raggi's avatar
Roberto Raggi committed
258
    void operator()(const Name *declarationName, Scope *globals,
259
260
261
262
263
                    QList<Function *> *functions)
    {
        _declarationName = declarationName;
        _functions = functions;

Roberto Raggi's avatar
Roberto Raggi committed
264
265
        for (unsigned i = 0; i < globals->memberCount(); ++i) {
            accept(globals->memberAt(i));
266
267
268
269
270
271
272
273
        }
    }

protected:
    using SymbolVisitor::visit;

    virtual bool visit(Function *function)
    {
Roberto Raggi's avatar
Roberto Raggi committed
274
275
        const Name *name = function->name();
        if (const QualifiedNameId *q = name->asQualifiedNameId())
276
            name = q->name();
277
278
279
280
281
282
283
284

        if (_declarationName->isEqualTo(name))
            _functions->append(function);

        return false;
    }
};

285

286
struct CanonicalSymbol
287
288
289
290
291
{
    CPPEditor *editor;
    TypeOfExpression typeOfExpression;
    SemanticInfo info;

292
    CanonicalSymbol(CPPEditor *editor, const SemanticInfo &info)
Erik Verbruggen's avatar
Erik Verbruggen committed
293
        : editor(editor), info(info)
294
295
296
297
298
299
300
301
302
    {
        typeOfExpression.init(info.doc, info.snapshot);
    }

    const LookupContext &context() const
    {
        return typeOfExpression.context();
    }

303
    static inline bool isIdentifierChar(const QChar &ch)
304
305
306
307
    {
        return ch.isLetterOrNumber() || ch == QLatin1Char('_');
    }

308
309
310
311
312
313
314
315
    Scope *getScopeAndExpression(const QTextCursor &cursor, QString *code)
    {
        return getScopeAndExpression(editor, info, cursor, code);
    }

    static Scope *getScopeAndExpression(CPPEditor *editor, const SemanticInfo &info,
                                        const QTextCursor &cursor,
                                        QString *code)
316
317
318
319
320
321
322
323
324
325
326
327
    {
        if (! info.doc)
            return 0;

        QTextCursor tc = cursor;
        int line, col;
        editor->convertPosition(tc.position(), &line, &col);
        ++col; // 1-based line and 1-based column

        QTextDocument *document = editor->document();

        int pos = tc.position();
328
329
330
331
332
333

        if (! isIdentifierChar(document->characterAt(pos)))
            if (! (pos > 0 && isIdentifierChar(document->characterAt(pos - 1))))
                return 0;

        while (isIdentifierChar(document->characterAt(pos)))
334
335
336
            ++pos;
        tc.setPosition(pos);

337
338
339
340
341
342
343
344
345
346
347
        ExpressionUnderCursor expressionUnderCursor;
        *code = expressionUnderCursor(tc);
        return info.doc->scopeAt(line, col);
    }

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

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

349
350
351
352
353
354
355
356
357
358
        return 0;
    }

    Symbol *operator()(Scope *scope, const QString &code)
    {
        return canonicalSymbol(scope, code, typeOfExpression);
    }

    static Symbol *canonicalSymbol(Scope *scope, const QString &code, TypeOfExpression &typeOfExpression)
    {
359
        const QList<LookupItem> results = typeOfExpression(code, scope, TypeOfExpression::Preprocess);
360

Roberto Raggi's avatar
Roberto Raggi committed
361
362
        for (int i = results.size() - 1; i != -1; --i) {
            const LookupItem &r = results.at(i);
363
            Symbol *decl = r.declaration();
Roberto Raggi's avatar
Roberto Raggi committed
364

365
            if (! (decl && decl->enclosingScope()))
Roberto Raggi's avatar
Roberto Raggi committed
366
367
                break;

368
            if (Class *classScope = r.declaration()->enclosingScope()->asClass()) {
369
370
371
372
373
374
375
376
377
378
379
                const Identifier *declId = decl->identifier();
                const Identifier *classId = classScope->identifier();

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

                else if (Function *funTy = r.declaration()->type()->asFunctionType()) {
                    if (funTy->isVirtual())
                        return r.declaration();
                }
            }
Roberto Raggi's avatar
Roberto Raggi committed
380
381
382
        }

        for (int i = 0; i < results.size(); ++i) {
383
384
385
386
387
388
389
390
            const LookupItem &r = results.at(i);

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

        return 0;
    }
391

392
393
};

394
395
396

int numberOfClosedEditors = 0;

con's avatar
con committed
397
398
399
} // end of anonymous namespace

CPPEditorEditable::CPPEditorEditable(CPPEditor *editor)
hjk's avatar
hjk committed
400
    : BaseTextEditorEditable(editor)
con's avatar
con committed
401
{
402
403
404
    m_context.add(CppEditor::Constants::C_CPPEDITOR);
    m_context.add(ProjectExplorer::Constants::LANG_CXX);
    m_context.add(TextEditor::Constants::C_TEXTEDITOR);
con's avatar
con committed
405
406
}

407
408
CPPEditor::CPPEditor(QWidget *parent)
    : TextEditor::BaseTextEditor(parent)
409
    , m_currentRenameSelection(NoCurrentRenameSelection)
410
    , m_inRename(false)
mae's avatar
mae committed
411
412
    , m_inRenameChanged(false)
    , m_firstRenameChange(false)
413
    , m_objcEnabled(false)
con's avatar
con committed
414
{
Roberto Raggi's avatar
Roberto Raggi committed
415
    m_initialized = false;
416
    qRegisterMetaType<CppEditor::Internal::SemanticInfo>("CppEditor::Internal::SemanticInfo");
Roberto Raggi's avatar
Roberto Raggi committed
417
418
419
420

    m_semanticHighlighter = new SemanticHighlighter(this);
    m_semanticHighlighter->start();

con's avatar
con committed
421
422
    setParenthesesMatchingEnabled(true);
    setMarksVisible(true);
423
    setCodeFoldingSupported(true);
424
    setIndenter(new CppQtStyleIndenter);
425
    setAutoCompleter(new CppAutoCompleter);
dt's avatar
dt committed
426

427
    baseTextDocument()->setSyntaxHighlighter(new CppHighlighter);
con's avatar
con committed
428

429
    m_modelManager = CppModelManagerInterface::instance();
con's avatar
con committed
430
431
432
433
434

    if (m_modelManager) {
        connect(m_modelManager, SIGNAL(documentUpdated(CPlusPlus::Document::Ptr)),
                this, SLOT(onDocumentUpdated(CPlusPlus::Document::Ptr)));
    }
435

436
437
    m_highlightRevision = 0;
    m_nextHighlightBlockNumber = 0;
438
439
    connect(&m_highlightWatcher, SIGNAL(resultsReadyAt(int,int)), SLOT(highlightSymbolUsages(int,int)));
    connect(&m_highlightWatcher, SIGNAL(finished()), SLOT(finishHighlightSymbolUsages()));
440
441
442
443

    m_referencesRevision = 0;
    m_referencesCursorPosition = 0;
    connect(&m_referencesWatcher, SIGNAL(finished()), SLOT(markSymbolsNow()));
con's avatar
con committed
444
445
446
447
}

CPPEditor::~CPPEditor()
{
448
449
    if (Core::EditorManager *em = Core::EditorManager::instance())
        em->hideEditorInfoBar(QLatin1String("CppEditor.Rename"));
450

Roberto Raggi's avatar
Roberto Raggi committed
451
452
    m_semanticHighlighter->abort();
    m_semanticHighlighter->wait();
453
454
455
456
457
458

    ++numberOfClosedEditors;
    if (numberOfClosedEditors == 5) {
        m_modelManager->GC();
        numberOfClosedEditors = 0;
    }
con's avatar
con committed
459
460
461
462
463
464
465
466
467
468
469
}

TextEditor::BaseTextEditorEditable *CPPEditor::createEditableInterface()
{
    CPPEditorEditable *editable = new CPPEditorEditable(this);
    createToolBar(editable);
    return editable;
}

void CPPEditor::createToolBar(CPPEditorEditable *editable)
{
Kai Koehne's avatar
Kai Koehne committed
470
471
    m_outlineCombo = new QComboBox;
    m_outlineCombo->setMinimumContentsLength(22);
472
473

    // Make the combo box prefer to expand
Kai Koehne's avatar
Kai Koehne committed
474
    QSizePolicy policy = m_outlineCombo->sizePolicy();
475
    policy.setHorizontalPolicy(QSizePolicy::Expanding);
Kai Koehne's avatar
Kai Koehne committed
476
    m_outlineCombo->setSizePolicy(policy);
477

Kai Koehne's avatar
Kai Koehne committed
478
479
480
481
482
    QTreeView *outlineView = new OverviewTreeView;
    outlineView->header()->hide();
    outlineView->setItemsExpandable(false);
    m_outlineCombo->setView(outlineView);
    m_outlineCombo->setMaxVisibleItems(20);
con's avatar
con committed
483

Kai Koehne's avatar
Kai Koehne committed
484
485
486
    m_outlineModel = new OverviewModel(this);
    m_proxyModel = new OverviewProxyModel(m_outlineModel, this);
    if (CppPlugin::instance()->sortedOutline())
487
488
        m_proxyModel->sort(0, Qt::AscendingOrder);
    else
Kai Koehne's avatar
Kai Koehne committed
489
        m_proxyModel->sort(-1, Qt::AscendingOrder); // don't sort yet, but set column for sortedOutline()
490
491
    m_proxyModel->setDynamicSortFilter(true);
    m_proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
Kai Koehne's avatar
Kai Koehne committed
492
    m_outlineCombo->setModel(m_proxyModel);
493

Kai Koehne's avatar
Kai Koehne committed
494
495
    m_outlineCombo->setContextMenuPolicy(Qt::ActionsContextMenu);
    m_sortAction = new QAction(tr("Sort Alphabetically"), m_outlineCombo);
496
    m_sortAction->setCheckable(true);
Kai Koehne's avatar
Kai Koehne committed
497
498
499
    m_sortAction->setChecked(sortedOutline());
    connect(m_sortAction, SIGNAL(toggled(bool)), CppPlugin::instance(), SLOT(setSortedOutline(bool)));
    m_outlineCombo->addAction(m_sortAction);
con's avatar
con committed
500

501
502
503
504
505
    m_updateOutlineTimer = new QTimer(this);
    m_updateOutlineTimer->setSingleShot(true);
    m_updateOutlineTimer->setInterval(UPDATE_OUTLINE_INTERVAL);
    connect(m_updateOutlineTimer, SIGNAL(timeout()), this, SLOT(updateOutlineNow()));

Kai Koehne's avatar
Kai Koehne committed
506
507
508
509
    m_updateOutlineIndexTimer = new QTimer(this);
    m_updateOutlineIndexTimer->setSingleShot(true);
    m_updateOutlineIndexTimer->setInterval(UPDATE_OUTLINE_INTERVAL);
    connect(m_updateOutlineIndexTimer, SIGNAL(timeout()), this, SLOT(updateOutlineIndexNow()));
Roberto Raggi's avatar
Roberto Raggi committed
510

Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
511
512
513
514
515
    m_updateUsesTimer = new QTimer(this);
    m_updateUsesTimer->setSingleShot(true);
    m_updateUsesTimer->setInterval(UPDATE_USES_INTERVAL);
    connect(m_updateUsesTimer, SIGNAL(timeout()), this, SLOT(updateUsesNow()));

Kai Koehne's avatar
Kai Koehne committed
516
517
518
    connect(m_outlineCombo, SIGNAL(activated(int)), this, SLOT(jumpToOutlineElement(int)));
    connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateOutlineIndex()));
    connect(m_outlineCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateOutlineToolTip()));
519
    connect(document(), SIGNAL(contentsChange(int,int,int)), this, SLOT(onContentsChanged(int,int,int)));
con's avatar
con committed
520
521
522

    connect(file(), SIGNAL(changed()), this, SLOT(updateFileName()));

Roberto Raggi's avatar
Roberto Raggi committed
523
524
525
526
527

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

528
529
    connect(m_semanticHighlighter, SIGNAL(changed(CppEditor::Internal::SemanticInfo)),
            this, SLOT(updateSemanticInfo(CppEditor::Internal::SemanticInfo)));
Roberto Raggi's avatar
Roberto Raggi committed
530

con's avatar
con committed
531
    QToolBar *toolBar = static_cast<QToolBar*>(editable->toolBar());
con's avatar
con committed
532
    QList<QAction*> actions = toolBar->actions();
533
    QWidget *w = toolBar->widgetForAction(actions.first());
Kai Koehne's avatar
Kai Koehne committed
534
    static_cast<QHBoxLayout*>(w->layout())->insertWidget(0, m_outlineCombo, 1);
con's avatar
con committed
535
536
}

mae's avatar
mae committed
537
538
void CPPEditor::paste()
{
539
    if (m_currentRenameSelection == NoCurrentRenameSelection) {
mae's avatar
mae committed
540
541
542
543
544
545
546
547
548
549
550
        BaseTextEditor::paste();
        return;
    }

    startRename();
    BaseTextEditor::paste();
    finishRename();
}

void CPPEditor::cut()
{
551
    if (m_currentRenameSelection == NoCurrentRenameSelection) {
mae's avatar
mae committed
552
553
554
555
556
557
558
559
560
        BaseTextEditor::cut();
        return;
    }

    startRename();
    BaseTextEditor::cut();
    finishRename();
}

561
CppModelManagerInterface *CPPEditor::modelManager() const
562
563
564
565
{
    return m_modelManager;
}

566
567
568
569
570
571
572
573
574
575
576
577
578
579
void CPPEditor::setMimeType(const QString &mt)
{
    BaseTextEditor::setMimeType(mt);
    setObjCEnabled(mt == CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE);
}

void CPPEditor::setObjCEnabled(bool onoff)
{
    m_objcEnabled = onoff;
}

bool CPPEditor::isObjCEnabled() const
{ return m_objcEnabled; }

mae's avatar
mae committed
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
void CPPEditor::startRename()
{
    m_inRenameChanged = false;
}

void CPPEditor::finishRename()
{
    if (!m_inRenameChanged)
        return;

    m_inRename = true;

    QTextCursor cursor = textCursor();
    cursor.joinPreviousEditBlock();

    cursor.setPosition(m_currentRenameSelectionEnd.position());
    cursor.setPosition(m_currentRenameSelectionBegin.position(), QTextCursor::KeepAnchor);
    m_renameSelections[m_currentRenameSelection].cursor = cursor;
    QString text = cursor.selectedText();

    for (int i = 0; i < m_renameSelections.size(); ++i) {
        if (i == m_currentRenameSelection)
            continue;
        QTextEdit::ExtraSelection &s = m_renameSelections[i];
        int pos = s.cursor.selectionStart();
        s.cursor.removeSelectedText();
        s.cursor.insertText(text);
        s.cursor.setPosition(pos, QTextCursor::KeepAnchor);
    }

    setExtraSelections(CodeSemanticsSelection, m_renameSelections);
    cursor.endEditBlock();

    m_inRename = false;
}

616
617
void CPPEditor::abortRename()
{
618
    if (m_currentRenameSelection <= NoCurrentRenameSelection)
mae's avatar
mae committed
619
        return;
620
    m_renameSelections[m_currentRenameSelection].format = m_occurrencesFormat;
621
    m_currentRenameSelection = NoCurrentRenameSelection;
mae's avatar
mae committed
622
623
    m_currentRenameSelectionBegin = QTextCursor();
    m_currentRenameSelectionEnd = QTextCursor();
624
625
626
    setExtraSelections(CodeSemanticsSelection, m_renameSelections);
}

627
628
629
630
631
632
void CPPEditor::rehighlight(bool force)
{
    const SemanticHighlighter::Source source = currentSource(force);
    m_semanticHighlighter->rehighlight(source);
}

con's avatar
con committed
633
634
635
636
637
void CPPEditor::onDocumentUpdated(Document::Ptr doc)
{
    if (doc->fileName() != file()->fileName())
        return;

638
639
640
    if (doc->editorRevision() != editorRevision())
        return;

Roberto Raggi's avatar
Roberto Raggi committed
641
642
    if (! m_initialized) {
        m_initialized = true;
643
        rehighlight(/* force = */ true);
Roberto Raggi's avatar
Roberto Raggi committed
644
645
    }

646
    m_updateOutlineTimer->start();
con's avatar
con committed
647
648
}

649
const Macro *CPPEditor::findCanonicalMacro(const QTextCursor &cursor, Document::Ptr doc) const
Christian Kamm's avatar
Christian Kamm committed
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
{
    if (! doc)
        return 0;

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

    if (const Macro *macro = doc->findMacroDefinitionAt(line))
        return macro;

    if (const Document::MacroUse *use = doc->findMacroUseAt(cursor.position()))
        return &use->macro();

    return 0;
}
665
666

void CPPEditor::findUsages()
667
{
668
    SemanticInfo info = m_lastSemanticInfo;
669
    info.snapshot = CppModelManagerInterface::instance()->snapshot();
670
    info.snapshot.insert(info.doc);
671

672
    CanonicalSymbol cs(this, info);
673
674
675
676
    Symbol *canonicalSymbol = cs(textCursor());
    if (canonicalSymbol) {
        m_modelManager->findUsages(canonicalSymbol, cs.context());
    } else if (const Macro *macro = findCanonicalMacro(textCursor(), info.doc)) {
Christian Kamm's avatar
Christian Kamm committed
677
        m_modelManager->findMacroUsages(*macro);
678
    }
679
680
}

681
682
683
684

void CPPEditor::renameUsagesNow(const QString &replacement)
{
    SemanticInfo info = m_lastSemanticInfo;
685
    info.snapshot = CppModelManagerInterface::instance()->snapshot();
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
    info.snapshot.insert(info.doc);

    CanonicalSymbol cs(this, info);
    if (Symbol *canonicalSymbol = cs(textCursor())) {
        if (canonicalSymbol->identifier() != 0) {
            if (showWarningMessage()) {
                Core::EditorManager::instance()->showEditorInfoBar(QLatin1String("CppEditor.Rename"),
                                                                   tr("This change cannot be undone."),
                                                                   tr("Yes, I know what I am doing."),
                                                                   this, SLOT(hideRenameNotification()));
            }

            m_modelManager->renameUsages(canonicalSymbol, cs.context(), replacement);
        }
    }
}

703
void CPPEditor::renameUsages()
704
{
705
706
707
    renameUsagesNow();
}

708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
bool CPPEditor::showWarningMessage() const
{
    // Restore settings
    QSettings *settings = Core::ICore::instance()->settings();
    settings->beginGroup(QLatin1String("CppEditor"));
    settings->beginGroup(QLatin1String("Rename"));
    const bool showWarningMessage = settings->value(QLatin1String("ShowWarningMessage"), true).toBool();
    settings->endGroup();
    settings->endGroup();
    return showWarningMessage;
}

void CPPEditor::setShowWarningMessage(bool showWarningMessage)
{
    // Restore settings
    QSettings *settings = Core::ICore::instance()->settings();
    settings->beginGroup(QLatin1String("CppEditor"));
    settings->beginGroup(QLatin1String("Rename"));
    settings->setValue(QLatin1String("ShowWarningMessage"), showWarningMessage);
    settings->endGroup();
    settings->endGroup();
}

731
732
void CPPEditor::hideRenameNotification()
{
733
    setShowWarningMessage(false);
734
    Core::EditorManager::instance()->hideEditorInfoBar(QLatin1String("CppEditor.Rename"));
735
736
}

737
void CPPEditor::markSymbolsNow()
738
{
739
740
741
742
743
744
    if (m_references.isCanceled())
        return;
    else if (m_referencesCursorPosition != position())
        return;
    else if (m_referencesRevision != editorRevision())
        return;
745

746
747
748
    const SemanticInfo info = m_lastSemanticInfo;
    TranslationUnit *unit = info.doc->translationUnit();
    const QList<int> result = m_references.result();
749
750
751

    QList<QTextEdit::ExtraSelection> selections;

752
753
754
    foreach (int index, result) {
        unsigned line, column;
        unit->getTokenPosition(index, &line, &column);
755

756
757
        if (column)
            --column;  // adjust the column position.
758

759
        const int len = unit->tokenAt(index).f.length;
760

761
762
763
        QTextCursor cursor(document()->findBlockByNumber(line - 1));
        cursor.setPosition(cursor.position() + column);
        cursor.setPosition(cursor.position() + len, QTextCursor::KeepAnchor);
764

765
766
767
768
        QTextEdit::ExtraSelection sel;
        sel.format = m_occurrencesFormat;
        sel.cursor = cursor;
        selections.append(sel);
769

Roberto Raggi's avatar
Roberto Raggi committed
770
    }
771
772

    setExtraSelections(CodeSemanticsSelection, selections);
Roberto Raggi's avatar
Roberto Raggi committed
773
774
}

775
static QList<int> lazyFindReferences(Scope *scope, QString code, Document::Ptr doc, Snapshot snapshot)
776
777
{
    TypeOfExpression typeOfExpression;
778
779
780
    snapshot.insert(doc);
    typeOfExpression.init(doc, snapshot);
    if (Symbol *canonicalSymbol = CanonicalSymbol::canonicalSymbol(scope, code, typeOfExpression)) {
781
        return CppModelManagerInterface::instance()->references(canonicalSymbol, typeOfExpression.context());
782
    }
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
    return QList<int>();
}

void CPPEditor::markSymbols(const QTextCursor &tc, const SemanticInfo &info)
{
    abortRename();

    if (! info.doc)
        return;

    CanonicalSymbol cs(this, info);
    QString expression;
    if (Scope *scope = cs.getScopeAndExpression(this, info, tc, &expression)) {
        m_references.cancel();
        m_referencesRevision = info.revision;
        m_referencesCursorPosition = position();
799
        m_references = QtConcurrent::run(&lazyFindReferences, scope, expression, info.doc, info.snapshot);
800
        m_referencesWatcher.setFuture(m_references);
801
802
803
804
805
    } else {
        const QList<QTextEdit::ExtraSelection> selections = extraSelections(CodeSemanticsSelection);

        if (! selections.isEmpty())
            setExtraSelections(CodeSemanticsSelection, QList<QTextEdit::ExtraSelection>());
806
807
808
    }
}

809
void CPPEditor::renameSymbolUnderCursor()
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
810
{
Roberto Raggi's avatar
Roberto Raggi committed
811
    updateSemanticInfo(m_semanticHighlighter->semanticInfo(currentSource()));
mae's avatar
mae committed
812
    abortRename();
813

Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
814
815
816
817
818
    QTextCursor c = textCursor();

    for (int i = 0; i < m_renameSelections.size(); ++i) {
        QTextEdit::ExtraSelection s = m_renameSelections.at(i);
        if (c.position() >= s.cursor.anchor()
819
                && c.position() <= s.cursor.position()) {
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
820
            m_currentRenameSelection = i;
mae's avatar
mae committed
821
822
823
824
825
            m_firstRenameChange = true;
            m_currentRenameSelectionBegin = QTextCursor(c.document()->docHandle(),
                                                        m_renameSelections[i].cursor.selectionStart());
            m_currentRenameSelectionEnd = QTextCursor(c.document()->docHandle(),
                                                        m_renameSelections[i].cursor.selectionEnd());
826
            m_renameSelections[i].format = m_occurrenceRenameFormat;
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
827
828
829
830
            setExtraSelections(CodeSemanticsSelection, m_renameSelections);
            break;
        }
    }
831
832

    if (m_renameSelections.isEmpty())
833
        renameUsages();
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
834
835
}

836
837
void CPPEditor::onContentsChanged(int position, int charsRemoved, int charsAdded)
{
838
839
    Q_UNUSED(position)

840
    if (m_currentRenameSelection == NoCurrentRenameSelection || m_inRename)
841
842
        return;

mae's avatar
mae committed
843
844
845
846
847
848
849
850
851
852
853
    if (position + charsAdded == m_currentRenameSelectionBegin.position()) {
        // we are inserting at the beginning of the rename selection => expand
        m_currentRenameSelectionBegin.setPosition(position);
        m_renameSelections[m_currentRenameSelection].cursor.setPosition(position, QTextCursor::KeepAnchor);
    }

    // the condition looks odd, but keep in mind that the begin and end cursors do move automatically
    m_inRenameChanged = (position >= m_currentRenameSelectionBegin.position()
                         && position + charsAdded <= m_currentRenameSelectionEnd.position());

    if (!m_inRenameChanged)
854
855
856
857
858
859
        abortRename();

    if (charsRemoved > 0)
        updateUses();
}

con's avatar
con committed
860
861
862
void CPPEditor::updateFileName()
{ }

Kai Koehne's avatar
Kai Koehne committed
863
void CPPEditor::jumpToOutlineElement(int)
con's avatar
con committed
864
{
Kai Koehne's avatar
Kai Koehne committed
865
866
    QModelIndex index = m_proxyModel->mapToSource(m_outlineCombo->view()->currentIndex());
    Symbol *symbol = m_outlineModel->symbolFromIndex(index);
con's avatar
con committed
867
868
869
    if (! symbol)
        return;

870
    openCppEditorAt(linkToSymbol(symbol));
con's avatar
con committed
871
872
}

Kai Koehne's avatar
Kai Koehne committed
873
void CPPEditor::setSortedOutline(bool sort)
874
{
Kai Koehne's avatar
Kai Koehne committed
875
    if (sort != sortedOutline()) {
876
877
878
879
880
881
882
        if (sort)
            m_proxyModel->sort(0, Qt::AscendingOrder);
        else
            m_proxyModel->sort(-1, Qt::AscendingOrder);
        bool block = m_sortAction->blockSignals(true);
        m_sortAction->setChecked(m_proxyModel->sortColumn() == 0);
        m_sortAction->blockSignals(block);
Kai Koehne's avatar
Kai Koehne committed
883
        updateOutlineIndexNow();
884
885
886
    }
}

Kai Koehne's avatar
Kai Koehne committed
887
bool CPPEditor::sortedOutline() const
888
889
890
891
{
    return (m_proxyModel->sortColumn() == 0);
}

892
893
894
895
896
897
898
899
900
901
902
903
904
void CPPEditor::updateOutlineNow()
{
    const Snapshot snapshot = m_modelManager->snapshot();
    Document::Ptr document = snapshot.document(file()->fileName());

    if (!document)
        return;

    if (document->editorRevision() != editorRevision()) {
        m_updateOutlineTimer->start();
        return;
    }

Kai Koehne's avatar
Kai Koehne committed
905
    m_outlineModel->rebuild(document);
906

Kai Koehne's avatar
Kai Koehne committed
907
    OverviewTreeView *treeView = static_cast<OverviewTreeView *>(m_outlineCombo->view());
908
    treeView->sync();
Kai Koehne's avatar
Kai Koehne committed
909
    updateOutlineIndexNow();
910
911
}

Kai Koehne's avatar
Kai Koehne committed
912
void CPPEditor::updateOutlineIndex()
con's avatar
con committed
913
{
Kai Koehne's avatar
Kai Koehne committed
914
    m_updateOutlineIndexTimer->start();
Roberto Raggi's avatar
Roberto Raggi committed
915
916
}

917
void CPPEditor::highlightUses(const QList<SemanticInfo::Use> &uses,
918
                              const SemanticInfo &semanticInfo,
919
                              QList<QTextEdit::ExtraSelection> *selections)
Roberto Raggi's avatar
Roberto Raggi committed
920
{
Roberto Raggi's avatar
Roberto Raggi committed
921
    bool isUnused = false;
Roberto Raggi's avatar
Roberto Raggi committed
922
923

    if (uses.size() == 1)
Roberto Raggi's avatar
Roberto Raggi committed
924
        isUnused = true;
Roberto Raggi's avatar
Roberto Raggi committed
925

Roberto Raggi's avatar
Roberto Raggi committed
926
    foreach (const SemanticInfo::Use &use, uses) {
Roberto Raggi's avatar
Roberto Raggi committed
927
        QTextEdit::ExtraSelection sel;
Roberto Raggi's avatar
Roberto Raggi committed
928

Roberto Raggi's avatar
Roberto Raggi committed
929
        if (isUnused)
930
            sel.format = m_occurrencesUnusedFormat;
Roberto Raggi's avatar
Roberto Raggi committed
931
        else
932
            sel.format = m_occurrencesFormat;
Roberto Raggi's avatar
Roberto Raggi committed
933

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

937
        sel.cursor = QTextCursor(document());
Roberto Raggi's avatar
Roberto Raggi committed
938
939
        sel.cursor.setPosition(anchor);
        sel.cursor.setPosition(position, QTextCursor::KeepAnchor);
Roberto Raggi's avatar
Roberto Raggi committed
940

941
942
943
944
945
946
947
948
        if (isUnused) {
            if (semanticInfo.hasQ && sel.cursor.selectedText() == QLatin1String("q"))
                continue; // skip q

            else if (semanticInfo.hasD && sel.cursor.selectedText() == QLatin1String("d"))
                continue; // skip d
        }

Roberto Raggi's avatar
Roberto Raggi committed
949
        selections->append(sel);
Roberto Raggi's avatar
Roberto Raggi committed
950
951
952
    }
}

Kai Koehne's avatar
Kai Koehne committed
953
void CPPEditor::updateOutlineIndexNow()
Roberto Raggi's avatar
Roberto Raggi committed
954
{
Kai Koehne's avatar
Kai Koehne committed
955
    if (!m_outlineModel->document())
956
957
        return;

Kai Koehne's avatar
Kai Koehne committed
958
959
    if (m_outlineModel->document()->editorRevision() != editorRevision()) {
        m_updateOutlineIndexTimer->start();
960
961
962
        return;
    }

Kai Koehne's avatar
Kai Koehne committed
963
    m_updateOutlineIndexTimer->stop();
964

Kai Koehne's avatar
Kai Koehne committed
965
966
    m_outlineModelIndex = QModelIndex(); //invalidate
    QModelIndex comboIndex = outlineModelIndex();
967

con's avatar
con committed
968

969
    if (comboIndex.isValid()) {
Kai Koehne's avatar
Kai Koehne committed
970
        bool blocked = m_outlineCombo->blockSignals(true);
971
972
973

        // There is no direct way to select a non-root item
        m_outlineCombo->setRootModelIndex(m_proxyModel->mapFromSource(comboIndex.parent()));
Kai Koehne's avatar
Kai Koehne committed
974
        m_outlineCombo->setCurrentIndex(m_proxyModel->mapFromSource(comboIndex).row());
975
976
        m_outlineCombo->setRootModelIndex(QModelIndex());

Kai Koehne's avatar
Kai Koehne committed
977
        updateOutlineToolTip();
978
979

        m_outlineCombo->blockSignals(blocked);
con's avatar
con committed
980
    }
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
981
982
}

Kai Koehne's avatar
Kai Koehne committed
983
void CPPEditor::updateOutlineToolTip()
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
984
{
Kai Koehne's avatar
Kai Koehne committed
985
    m_outlineCombo->setToolTip(m_outlineCombo->currentText());
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
986
987
988
989
}

void CPPEditor::updateUses()
{
990
991
    if (editorRevision() != m_highlightRevision)
        m_highlighter.cancel();
mae's avatar
mae committed
992
    m_updateUsesTimer->start();
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
993
994
995
996
}

void CPPEditor::updateUsesNow()
{
997
    if (m_currentRenameSelection != NoCurrentRenameSelection)
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
998
999
        return;

Roberto Raggi's avatar
Roberto Raggi committed
1000
    semanticRehighlight();
con's avatar
con committed
1001
1002
}

1003
void CPPEditor::highlightSymbolUsages(int from, int to)
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
{
    if (editorRevision() != m_highlightRevision)
        return; // outdated

    else if (m_highlighter.isCanceled())
        return; // aborted

    CppHighlighter *highlighter = qobject_cast<CppHighlighter*>(baseTextDocument()->syntaxHighlighter());
    Q_ASSERT(highlighter);
    QTextDocument *doc = document();

    if (m_nextHighlightBlockNumber >= doc->blockCount())
        return;

Roberto Raggi's avatar
Roberto Raggi committed
1018
    QMap<int, QVector<SemanticInfo::Use> > chunks = CheckSymbols::chunks(m_highlighter, from, to);
Roberto Raggi's avatar
Roberto Raggi committed
1019
1020
1021
    if (chunks.isEmpty())
        return;

1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
    QTextBlock b = doc->findBlockByNumber(m_nextHighlightBlockNumber);

    QMapIterator<int, QVector<SemanticInfo::Use> > it(chunks);
    while (b.isValid() && it.hasNext()) {
        it.next();
        const int blockNumber = it.key();
        Q_ASSERT(blockNumber < doc->blockCount());

        while (m_nextHighlightBlockNumber < blockNumber) {
            highlighter->setExtraAdditionalFormats(b, QList<QTextLayout::FormatRange>());
            b = b.next();
            ++m_nextHighlightBlockNumber;
        }

        QList<QTextLayout::FormatRange> formats;
        foreach (const SemanticInfo::Use &use, it.value()) {
            QTextLayout::FormatRange formatRange;
1039
1040
1041
1042
1043
1044
1045

            switch (use.kind) {
            case SemanticInfo::Use::Type:
                formatRange.format = m_typeFormat;
                break;

            case SemanticInfo::Use::Field:
1046
                formatRange.format = m_fieldFormat;
1047
1048
1049
                break;

            case SemanticInfo::Use::Local:
1050
                formatRange.format = m_localFormat;
1051
1052
                break;

1053
1054
1055
1056
            case SemanticInfo::Use::Static:
                formatRange.format = m_staticFormat;
                break;

Roberto Raggi's avatar
Roberto Raggi committed
1057
            case SemanticInfo::Use::VirtualMethod:
1058
                formatRange.format = m_virtualMethodFormat;
Roberto Raggi's avatar
Roberto Raggi committed
1059
1060
                break;

1061
1062
1063
1064
            default:
                continue;
            }

1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
            formatRange.start = use.column - 1;
            formatRange.length = use.length;
            formats.append(formatRange);
        }
        highlighter->setExtraAdditionalFormats(b, formats);
        b = b.next();
        ++m_nextHighlightBlockNumber;
    }
}

1075
void CPPEditor::finishHighlightSymbolUsages()
1076
{
1077
    if (editorRevision() != m_highlightRevision)
1078
1079
1080
1081
1082
        return; // outdated

    else if (m_highlighter.isCanceled())
        return; // aborted

1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
    CppHighlighter *highlighter = qobject_cast<CppHighlighter*>(baseTextDocument()->syntaxHighlighter());
    Q_ASSERT(highlighter);
    QTextDocument *doc = document();

    if (m_nextHighlightBlockNumber >= doc->blockCount())
        return;

    QTextBlock b = doc->findBlockByNumber(m_nextHighlightBlockNumber);

    while (b.isValid()) {
        highlighter->setExtraAdditionalFormats(b, QList<QTextLayout::FormatRange>());
        b = b.next();
        ++m_nextHighlightBlockNumber;
    }
1097
1098
}

1099

con's avatar
con committed
1100
1101
void CPPEditor::switchDeclarationDefinition()
{
1102
    if (! m_modelManager)
con's avatar
con committed
1103
1104
        return;

1105
1106
    const Snapshot snapshot = m_modelManager->snapshot();

1107
    if (Document::Ptr thisDocument = snapshot.document(file()->fileName())) {
1108
1109
        int line = 0, positionInBlock = 0;
        convertPosition(position(), &line, &positionInBlock);
con's avatar
con committed
1110

1111
        Symbol *lastVisibleSymbol = thisDocument->lastVisibleSymbolAt(line, positionInBlock + 1);
1112
1113
        if (! lastVisibleSymbol)
            return;
con's avatar
con committed
1114

1115
1116
1117
        Function *function = lastVisibleSymbol->asFunction();
        if (! function)
            function = lastVisibleSymbol->enclosingFunction();
con's avatar
con committed
1118

1119
        if (function) {
1120
            LookupContext context(thisDocument, snapshot);
con's avatar
con committed
1121

1122
1123
1124
            Function *functionDefinition = function->asFunction();
            ClassOrNamespace *binding = context.lookupType(functionDefinition);

1125
            const QList<LookupItem> declarations = context.lookup(functionDefinition->name(), functionDefinition->enclosingScope());
1126
            QList<Symbol *> best;
1127
            foreach (const LookupItem &r, declarations) {
1128
1129
1130
1131
1132
1133
1134
1135
                if (Symbol *decl = r.declaration()) {
                    if (Function *funTy = decl->type()->asFunctionType()) {
                        if (funTy->isEqualTo(function) && decl != function && binding == r.binding())
                            best.prepend(decl);
                        else
                            best.append(decl);
                    }
                }
1136