cppeditor.cpp 63.7 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
2
3
4
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2010 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
**
9
** Commercial Usage
10
**
11
12
13
14
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
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
**
25
** If you are unsure which license is appropriate for your use, please
hjk's avatar
hjk committed
26
** contact the sales department at http://qt.nokia.com/contact.
con's avatar
con committed
27
**
28
**************************************************************************/
hjk's avatar
hjk committed
29

con's avatar
con committed
30
31
32
33
#include "cppeditor.h"
#include "cppeditorconstants.h"
#include "cppplugin.h"
#include "cpphighlighter.h"
34
#include "cppquickfix.h"
Roberto Raggi's avatar
Roberto Raggi committed
35
36
#include <cpptools/cpptoolsplugin.h>

con's avatar
con committed
37
#include <AST.h>
38
#include <Control.h>
con's avatar
con committed
39
40
41
42
43
44
45
#include <Token.h>
#include <Scope.h>
#include <Symbols.h>
#include <Names.h>
#include <CoreTypes.h>
#include <Literals.h>
#include <Semantic.h>
46
#include <ASTVisitor.h>
47
#include <SymbolVisitor.h>
48
#include <TranslationUnit.h>
con's avatar
con committed
49
#include <cplusplus/ExpressionUnderCursor.h>
Roberto Raggi's avatar
Roberto Raggi committed
50
#include <cplusplus/TypeOfExpression.h>
con's avatar
con committed
51
52
53
54
#include <cplusplus/LookupContext.h>
#include <cplusplus/Overview.h>
#include <cplusplus/OverviewModel.h>
#include <cplusplus/SimpleLexer.h>
55
#include <cplusplus/TokenUnderCursor.h>
56
#include <cplusplus/MatchingText.h>
57
#include <cplusplus/BackwardsScanner.h>
58
#include <cplusplus/FastPreprocessor.h>
59
#include <cplusplus/CppBindings.h>
60

con's avatar
con committed
61
62
63
64
#include <cpptools/cppmodelmanagerinterface.h>

#include <coreplugin/icore.h>
#include <coreplugin/uniqueidmanager.h>
65
#include <coreplugin/actionmanager/actionmanager.h>
con's avatar
con committed
66
67
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/editormanager/editormanager.h>
dt's avatar
dt committed
68
#include <coreplugin/mimedatabase.h>
69
#include <utils/uncommentselection.h>
70
#include <extensionsystem/pluginmanager.h>
con's avatar
con committed
71
72
73
74
75
76
77
78
79
80
#include <projectexplorer/projectexplorerconstants.h>
#include <texteditor/basetextdocument.h>
#include <texteditor/fontsettings.h>
#include <texteditor/texteditorconstants.h>
#include <texteditor/textblockiterator.h>
#include <indenter.h>

#include <QtCore/QDebug>
#include <QtCore/QTime>
#include <QtCore/QTimer>
81
#include <QtCore/QStack>
82
#include <QtCore/QSettings>
83
#include <QtCore/QSignalMapper>
con's avatar
con committed
84
#include <QtGui/QAction>
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
85
#include <QtGui/QApplication>
86
#include <QtGui/QHeaderView>
con's avatar
con committed
87
88
89
90
91
#include <QtGui/QLayout>
#include <QtGui/QMenu>
#include <QtGui/QShortcut>
#include <QtGui/QTextEdit>
#include <QtGui/QComboBox>
con's avatar
con committed
92
#include <QtGui/QToolBar>
con's avatar
con committed
93
#include <QtGui/QTreeView>
94
#include <QtGui/QSortFilterProxyModel>
con's avatar
con committed
95

96
97
#include <sstream>

Roberto Raggi's avatar
Roberto Raggi committed
98
enum {
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
99
100
    UPDATE_METHOD_BOX_INTERVAL = 150,
    UPDATE_USES_INTERVAL = 300
Roberto Raggi's avatar
Roberto Raggi committed
101
102
};

Roberto Raggi's avatar
Roberto Raggi committed
103
104
105
using namespace CPlusPlus;
using namespace CppEditor::Internal;

con's avatar
con committed
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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()));
    }
};

Roberto Raggi's avatar
Roberto Raggi committed
125
class FindScope: protected SymbolVisitor
126
{
Roberto Raggi's avatar
Roberto Raggi committed
127
128
129
130
    TranslationUnit *_unit;
    Scope *_scope;
    unsigned _line;
    unsigned _column;
131

Roberto Raggi's avatar
Roberto Raggi committed
132
133
134
public:
    Scope *operator()(unsigned line, unsigned column,
                      Symbol *root, TranslationUnit *unit)
135
    {
Roberto Raggi's avatar
Roberto Raggi committed
136
137
138
139
140
141
142
        _unit = unit;
        _scope = 0;
        _line = line;
        _column = column;
        accept(root);
        return _scope;
    }
143

Roberto Raggi's avatar
Roberto Raggi committed
144
145
private:
    using SymbolVisitor::visit;
146

Roberto Raggi's avatar
Roberto Raggi committed
147
148
    virtual bool preVisit(Symbol *)
    { return ! _scope; }
149

Roberto Raggi's avatar
Roberto Raggi committed
150
151
    virtual bool visit(Block *block)
    { return processScope(block->members()); }
152

Roberto Raggi's avatar
Roberto Raggi committed
153
154
    virtual bool visit(Function *function)
    { return processScope(function->members()); }
155

156
157
158
    virtual bool visit(ObjCMethod *method)
    { return processScope(method->members()); }

Roberto Raggi's avatar
Roberto Raggi committed
159
160
161
162
    bool processScope(Scope *scope)
    {
        if (_scope || ! scope)
            return false;
163

Roberto Raggi's avatar
Roberto Raggi committed
164
165
        for (unsigned i = 0; i < scope->symbolCount(); ++i) {
            accept(scope->symbolAt(i));
166

Roberto Raggi's avatar
Roberto Raggi committed
167
168
169
            if (_scope)
                return false;
        }
170

Roberto Raggi's avatar
Roberto Raggi committed
171
172
        unsigned startOffset = scope->owner()->startOffset();
        unsigned endOffset = scope->owner()->endOffset();
173

Roberto Raggi's avatar
Roberto Raggi committed
174
175
        unsigned startLine, startColumn;
        unsigned endLine, endColumn;
176

Roberto Raggi's avatar
Roberto Raggi committed
177
178
        _unit->getPosition(startOffset, &startLine, &startColumn);
        _unit->getPosition(endOffset, &endLine, &endColumn);
179

Roberto Raggi's avatar
Roberto Raggi committed
180
181
182
        if (_line > startLine || (_line == startLine && _column >= startColumn)) {
            if (_line < endLine || (_line == endLine && _column < endColumn)) {
                _scope = scope;
183
184
            }
        }
Roberto Raggi's avatar
Roberto Raggi committed
185
186
187
188
189

        return false;
    }
};

190
class FindLocalUses: protected ASTVisitor
Roberto Raggi's avatar
Roberto Raggi committed
191
192
{
    Scope *_functionScope;
193
194
    FindScope findScope;

195
public:
196
197
    FindLocalUses(TranslationUnit *translationUnit)
        : ASTVisitor(translationUnit), hasD(false), hasQ(false)
198
199
    { }

Roberto Raggi's avatar
Roberto Raggi committed
200
    // local and external uses.
Roberto Raggi's avatar
Roberto Raggi committed
201
    SemanticInfo::LocalUseMap localUses;
202
203
    bool hasD;
    bool hasQ;
Roberto Raggi's avatar
Roberto Raggi committed
204

205
    void operator()(DeclarationAST *ast)
206
    {
Roberto Raggi's avatar
Roberto Raggi committed
207
208
        localUses.clear();

209
210
211
212
213
214
215
216
217
218
219
220
221
        if (!ast)
            return;

        if (FunctionDefinitionAST *def = ast->asFunctionDefinition()) {
            if (def->symbol) {
                _functionScope = def->symbol->members();
                accept(ast);
            }
        } else if (ObjCMethodDeclarationAST *decl = ast->asObjCMethodDeclaration()) {
            if (decl->method_prototype->symbol) {
                _functionScope = decl->method_prototype->symbol->members();
                accept(ast);
            }
222
223
224
225
226
227
        }
    }

protected:
    using ASTVisitor::visit;

Roberto Raggi's avatar
Roberto Raggi committed
228
    bool findMember(Scope *scope, NameAST *ast, unsigned line, unsigned column)
229
    {
Roberto Raggi's avatar
Roberto Raggi committed
230
231
232
        if (! (ast && ast->name))
            return false;

Roberto Raggi's avatar
Roberto Raggi committed
233
        const Identifier *id = ast->name->identifier();
234
235
236
237
238

        if (scope) {
            for (Symbol *member = scope->lookat(id); member; member = member->next()) {
                if (member->identifier() != id)
                    continue;
Roberto Raggi's avatar
typo    
Roberto Raggi committed
239
                else if (member->line() < line || (member->line() == line && member->column() <= column)) {
Roberto Raggi's avatar
Roberto Raggi committed
240
                    localUses[member].append(SemanticInfo::Use(line, column, id->size()));
241
242
243
244
245
246
247
248
                    return true;
                }
            }
        }

        return false;
    }

249
250
251
252
253
254
    void searchUsesInTemplateArguments(NameAST *name)
    {
        if (! name)
            return;

        else if (TemplateIdAST *template_id = name->asTemplateId()) {
Roberto Raggi's avatar
Roberto Raggi committed
255
            for (TemplateArgumentListAST *it = template_id->template_argument_list; it; it = it->next) {
256
                accept(it->value);
257
258
259
260
            }
        }
    }

261
    virtual bool visit(SimpleNameAST *ast)
262
263
264
    { return findMemberForToken(ast->firstToken(), ast); }

    bool findMemberForToken(unsigned tokenIdx, NameAST *ast)
265
266
    {
        unsigned line, column;
267
        getTokenStartPosition(tokenIdx, &line, &column);
268
269
270
271
272
273
274
275
276
277
278
279

        Scope *scope = findScope(line, column,
                                 _functionScope->owner(),
                                 translationUnit());

        while (scope) {
            if (scope->isFunctionScope()) {
                Function *fun = scope->owner()->asFunction();
                if (findMember(fun->members(), ast, line, column))
                    return false;
                else if (findMember(fun->arguments(), ast, line, column))
                    return false;
280
281
282
283
284
285
            } else if (scope->isObjCMethodScope()) {
                ObjCMethod *method = scope->owner()->asObjCMethod();
                if (findMember(method->members(), ast, line, column))
                    return false;
                else if (findMember(method->arguments(), ast, line, column))
                    return false;
286
287
288
289
290
291
292
293
294
295
296
297
298
            } else if (scope->isBlockScope()) {
                if (findMember(scope, ast, line, column))
                    return false;
            } else {
                break;
            }

            scope = scope->enclosingScope();
        }

        return false;
    }

Roberto Raggi's avatar
Roberto Raggi committed
299
    virtual bool visit(TemplateIdAST *ast)
300
    {
Roberto Raggi's avatar
Roberto Raggi committed
301
        for (TemplateArgumentListAST *arg = ast->template_argument_list; arg; arg = arg->next)
302
            accept(arg->value);
303

Roberto Raggi's avatar
Roberto Raggi committed
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
        unsigned line, column;
        getTokenStartPosition(ast->firstToken(), &line, &column);

        Scope *scope = findScope(line, column,
                                 _functionScope->owner(),
                                 translationUnit());

        while (scope) {
            if (scope->isFunctionScope()) {
                Function *fun = scope->owner()->asFunction();
                if (findMember(fun->members(), ast, line, column))
                    return false;
                else if (findMember(fun->arguments(), ast, line, column))
                    return false;
            } else if (scope->isBlockScope()) {
                if (findMember(scope, ast, line, column))
                    return false;
            } else {
                break;
            }

            scope = scope->enclosingScope();
        }

        return false;
    }

    virtual bool visit(QualifiedNameAST *ast)
    {
Roberto Raggi's avatar
Roberto Raggi committed
333
        for (NestedNameSpecifierListAST *it = ast->nested_name_specifier_list; it; it = it->next)
Roberto Raggi's avatar
Roberto Raggi committed
334
            searchUsesInTemplateArguments(it->value->class_or_namespace_name);
Roberto Raggi's avatar
Roberto Raggi committed
335

336
        searchUsesInTemplateArguments(ast->unqualified_name);
337
338
339
340
341
342
        return false;
    }

    virtual bool visit(PostfixExpressionAST *ast)
    {
        accept(ast->base_expression);
Roberto Raggi's avatar
Roberto Raggi committed
343
        for (PostfixListAST *it = ast->postfix_expression_list; it; it = it->next) {
Roberto Raggi's avatar
Roberto Raggi committed
344
345
            PostfixAST *fx = it->value;
            if (fx->asMemberAccess() != 0)
346
                continue; // skip members
Roberto Raggi's avatar
Roberto Raggi committed
347
            accept(fx);
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
        }
        return false;
    }

    virtual bool visit(ElaboratedTypeSpecifierAST *)
    {
        // ### template args
        return false;
    }

    virtual bool visit(ClassSpecifierAST *)
    {
        // ### template args
        return false;
    }

    virtual bool visit(EnumSpecifierAST *)
    {
        // ### template args
        return false;
    }

    virtual bool visit(UsingDirectiveAST *)
    {
        return false;
    }

    virtual bool visit(UsingAST *ast)
    {
        accept(ast->name);
        return false;
    }
380

381
382
383
384
385
386
387
388
389
390
    virtual bool visit(QtMemberDeclarationAST *ast)
    {
        if (tokenKind(ast->q_token) == T_Q_D)
            hasD = true;
        else
            hasQ = true;

        return true;
    }

391
392
393
394
395
396
397
398
399
400
    virtual bool visit(ExpressionOrDeclarationStatementAST *ast)
    {
        accept(ast->declaration);
        return false;
    }

    virtual bool visit(FunctionDeclaratorAST *ast)
    {
        accept(ast->parameters);

Roberto Raggi's avatar
Roberto Raggi committed
401
        for (SpecifierListAST *it = ast->cv_qualifier_list; it; it = it->next)
Roberto Raggi's avatar
Roberto Raggi committed
402
            accept(it->value);
403
404
405
406
407

        accept(ast->exception_specification);

        return false;
    }
408
409
410
411
412
413

    virtual bool visit(ObjCMethodPrototypeAST *ast)
    {
        accept(ast->argument_list);
        return false;
    }
414
415
416
417
418
419

    virtual bool visit(ObjCMessageArgumentDeclarationAST *ast)
    {
        accept(ast->param_name);
        return false;
    }
420
421
422
};


Roberto Raggi's avatar
Roberto Raggi committed
423
424
425
426
class FunctionDefinitionUnderCursor: protected ASTVisitor
{
    unsigned _line;
    unsigned _column;
427
    DeclarationAST *_functionDefinition;
Roberto Raggi's avatar
Roberto Raggi committed
428
429

public:
Roberto Raggi's avatar
Roberto Raggi committed
430
431
    FunctionDefinitionUnderCursor(TranslationUnit *translationUnit)
        : ASTVisitor(translationUnit),
Roberto Raggi's avatar
Roberto Raggi committed
432
          _line(0), _column(0)
Roberto Raggi's avatar
Roberto Raggi committed
433
434
    { }

435
    DeclarationAST *operator()(AST *ast, unsigned line, unsigned column)
Roberto Raggi's avatar
Roberto Raggi committed
436
437
    {
        _functionDefinition = 0;
Roberto Raggi's avatar
Roberto Raggi committed
438
439
        _line = line;
        _column = column;
Roberto Raggi's avatar
Roberto Raggi committed
440
441
442
443
444
445
446
447
448
449
450
        accept(ast);
        return _functionDefinition;
    }

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

        else if (FunctionDefinitionAST *def = ast->asFunctionDefinition()) {
451
452
453
454
455
456
            return checkDeclaration(def);
        }

        else if (ObjCMethodDeclarationAST *method = ast->asObjCMethodDeclaration()) {
            if (method->function_body)
                return checkDeclaration(method);
Roberto Raggi's avatar
Roberto Raggi committed
457
458
459
460
461
        }

        return true;
    }

462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
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
479
480
481
482
483
484
485
486
};

class ProcessDeclarators: protected ASTVisitor
{
    QList<DeclaratorIdAST *> _declarators;
    bool _visitFunctionDeclarator;

public:
Roberto Raggi's avatar
Roberto Raggi committed
487
488
489
    ProcessDeclarators(TranslationUnit *translationUnit)
        : ASTVisitor(translationUnit),
          _visitFunctionDeclarator(true)
Roberto Raggi's avatar
Roberto Raggi committed
490
491
492
493
494
495
496
497
498
    { }

    QList<DeclaratorIdAST *> operator()(FunctionDefinitionAST *ast)
    {
        _declarators.clear();

        if (ast) {
            if (ast->declarator) {
                _visitFunctionDeclarator = true;
Roberto Raggi's avatar
Roberto Raggi committed
499
                accept(ast->declarator->postfix_declarator_list);
Roberto Raggi's avatar
Roberto Raggi committed
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
            }

            _visitFunctionDeclarator = false;
            accept(ast->function_body);
        }

        return _declarators;
    }

protected:
    using ASTVisitor::visit;

    virtual bool visit(FunctionDeclaratorAST *)
    { return _visitFunctionDeclarator; }

    virtual bool visit(DeclaratorIdAST *ast)
    {
        _declarators.append(ast);
        return true;
    }
};

522
523
class FindFunctionDefinitions: protected SymbolVisitor
{
Roberto Raggi's avatar
Roberto Raggi committed
524
    const Name *_declarationName;
525
526
527
528
529
530
531
532
    QList<Function *> *_functions;

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

Roberto Raggi's avatar
Roberto Raggi committed
533
    void operator()(const Name *declarationName, Scope *globals,
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
                    QList<Function *> *functions)
    {
        _declarationName = declarationName;
        _functions = functions;

        for (unsigned i = 0; i < globals->symbolCount(); ++i) {
            accept(globals->symbolAt(i));
        }
    }

protected:
    using SymbolVisitor::visit;

    virtual bool visit(Function *function)
    {
Roberto Raggi's avatar
Roberto Raggi committed
549
550
        const Name *name = function->name();
        if (const QualifiedNameId *q = name->asQualifiedNameId())
551
552
553
554
555
556
557
558
559
            name = q->unqualifiedNameId();

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

        return false;
    }
};

con's avatar
con committed
560
561
} // end of anonymous namespace

Roberto Raggi's avatar
Roberto Raggi committed
562
static const QualifiedNameId *qualifiedNameIdForSymbol(Symbol *s, const LookupContext &context)
con's avatar
con committed
563
{
Roberto Raggi's avatar
Roberto Raggi committed
564
    const Name *symbolName = s->name();
con's avatar
con committed
565
566
567
    if (! symbolName)
        return 0; // nothing to do.

Roberto Raggi's avatar
Roberto Raggi committed
568
    QVector<const Name *> names;
con's avatar
con committed
569
570
571
572

    for (Scope *scope = s->scope(); scope; scope = scope->enclosingScope()) {
        if (scope->isClassScope() || scope->isNamespaceScope()) {
            if (scope->owner() && scope->owner()->name()) {
Roberto Raggi's avatar
Roberto Raggi committed
573
574
                const Name *ownerName = scope->owner()->name();
                if (const QualifiedNameId *q = ownerName->asQualifiedNameId()) {
con's avatar
con committed
575
576
577
578
579
580
581
582
583
584
                    for (unsigned i = 0; i < q->nameCount(); ++i) {
                        names.prepend(q->nameAt(i));
                    }
                } else {
                    names.prepend(ownerName);
                }
            }
        }
    }

Roberto Raggi's avatar
Roberto Raggi committed
585
    if (const QualifiedNameId *q = symbolName->asQualifiedNameId()) {
con's avatar
con committed
586
587
588
589
590
591
592
593
594
595
596
        for (unsigned i = 0; i < q->nameCount(); ++i) {
            names.append(q->nameAt(i));
        }
    } else {
        names.append(symbolName);
    }

    return context.control()->qualifiedNameId(names.constData(), names.size());
}

CPPEditorEditable::CPPEditorEditable(CPPEditor *editor)
hjk's avatar
hjk committed
597
    : BaseTextEditorEditable(editor)
con's avatar
con committed
598
{
599
    Core::UniqueIDManager *uidm = Core::UniqueIDManager::instance();
600
    m_context << uidm->uniqueIdentifier(CppEditor::Constants::C_CPPEDITOR);
601
602
    m_context << uidm->uniqueIdentifier(ProjectExplorer::Constants::LANG_CXX);
    m_context << uidm->uniqueIdentifier(TextEditor::Constants::C_TEXTEDITOR);
con's avatar
con committed
603
604
}

605
606
CPPEditor::CPPEditor(QWidget *parent)
    : TextEditor::BaseTextEditor(parent)
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
607
    , m_currentRenameSelection(-1)
608
    , m_inRename(false)
mae's avatar
mae committed
609
610
    , m_inRenameChanged(false)
    , m_firstRenameChange(false)
con's avatar
con committed
611
{
Roberto Raggi's avatar
Roberto Raggi committed
612
    m_initialized = false;
613
    qRegisterMetaType<CppEditor::Internal::SemanticInfo>("CppEditor::Internal::SemanticInfo");
Roberto Raggi's avatar
Roberto Raggi committed
614
615
616
617

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

con's avatar
con committed
618
619
    setParenthesesMatchingEnabled(true);
    setMarksVisible(true);
620
    setCodeFoldingSupported(true);
con's avatar
con committed
621
    setCodeFoldingVisible(true);
622
    baseTextDocument()->setSyntaxHighlighter(new CppHighlighter);
con's avatar
con committed
623

Roberto Raggi's avatar
Roberto Raggi committed
624
    m_modelManager = CppTools::CppModelManagerInterface::instance();
con's avatar
con committed
625
626
627
628
629
630
631
632
633

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

CPPEditor::~CPPEditor()
{
634
635
    Core::EditorManager::instance()->hideEditorInfoBar(QLatin1String("CppEditor.Rename"));

Roberto Raggi's avatar
Roberto Raggi committed
636
637
    m_semanticHighlighter->abort();
    m_semanticHighlighter->wait();
con's avatar
con committed
638
639
640
641
642
643
644
645
646
647
648
649
650
}

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

void CPPEditor::createToolBar(CPPEditorEditable *editable)
{
    m_methodCombo = new QComboBox;
    m_methodCombo->setMinimumContentsLength(22);
651
652
653
654
655
656

    // Make the combo box prefer to expand
    QSizePolicy policy = m_methodCombo->sizePolicy();
    policy.setHorizontalPolicy(QSizePolicy::Expanding);
    m_methodCombo->setSizePolicy(policy);

657
    QTreeView *methodView = new OverviewTreeView;
con's avatar
con committed
658
659
660
661
662
663
    methodView->header()->hide();
    methodView->setItemsExpandable(false);
    m_methodCombo->setView(methodView);
    m_methodCombo->setMaxVisibleItems(20);

    m_overviewModel = new OverviewModel(this);
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
    m_proxyModel = new QSortFilterProxyModel(this);
    m_proxyModel->setSourceModel(m_overviewModel);
    if (CppPlugin::instance()->sortedMethodOverview())
        m_proxyModel->sort(0, Qt::AscendingOrder);
    else
        m_proxyModel->sort(-1, Qt::AscendingOrder); // don't sort yet, but set column for sortedMethodOverview()
    m_proxyModel->setDynamicSortFilter(true);
    m_proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
    m_methodCombo->setModel(m_proxyModel);

    m_methodCombo->setContextMenuPolicy(Qt::ActionsContextMenu);
    m_sortAction = new QAction(tr("Sort alphabetically"), m_methodCombo);
    m_sortAction->setCheckable(true);
    m_sortAction->setChecked(sortedMethodOverview());
    connect(m_sortAction, SIGNAL(toggled(bool)), CppPlugin::instance(), SLOT(setSortedMethodOverview(bool)));
    m_methodCombo->addAction(m_sortAction);
con's avatar
con committed
680

Roberto Raggi's avatar
Roberto Raggi committed
681
682
683
684
685
    m_updateMethodBoxTimer = new QTimer(this);
    m_updateMethodBoxTimer->setSingleShot(true);
    m_updateMethodBoxTimer->setInterval(UPDATE_METHOD_BOX_INTERVAL);
    connect(m_updateMethodBoxTimer, SIGNAL(timeout()), this, SLOT(updateMethodBoxIndexNow()));

Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
686
687
688
689
690
    m_updateUsesTimer = new QTimer(this);
    m_updateUsesTimer->setSingleShot(true);
    m_updateUsesTimer->setInterval(UPDATE_USES_INTERVAL);
    connect(m_updateUsesTimer, SIGNAL(timeout()), this, SLOT(updateUsesNow()));

con's avatar
con committed
691
692
    connect(m_methodCombo, SIGNAL(activated(int)), this, SLOT(jumpToMethod(int)));
    connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateMethodBoxIndex()));
693
    connect(m_methodCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateMethodBoxToolTip()));
694
    connect(document(), SIGNAL(contentsChange(int,int,int)), this, SLOT(onContentsChanged(int,int,int)));
con's avatar
con committed
695
696
697

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

Roberto Raggi's avatar
Roberto Raggi committed
698
699
700
701
702

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

703
704
    connect(m_semanticHighlighter, SIGNAL(changed(CppEditor::Internal::SemanticInfo)),
            this, SLOT(updateSemanticInfo(CppEditor::Internal::SemanticInfo)));
Roberto Raggi's avatar
Roberto Raggi committed
705

con's avatar
con committed
706
    QToolBar *toolBar = static_cast<QToolBar*>(editable->toolBar());
con's avatar
con committed
707
    QList<QAction*> actions = toolBar->actions();
708
709
    QWidget *w = toolBar->widgetForAction(actions.first());
    static_cast<QHBoxLayout*>(w->layout())->insertWidget(0, m_methodCombo, 1);
con's avatar
con committed
710
711
}

712
713
714
715
716
717
718
void CPPEditor::inAllRenameSelections(EditOperation operation,
                                      const QTextEdit::ExtraSelection &currentRenameSelection,
                                      QTextCursor cursor,
                                      const QString &text)
{
    cursor.beginEditBlock();

719
720
721
    const int startOffset = cursor.selectionStart() - currentRenameSelection.cursor.anchor();
    const int endOffset = cursor.selectionEnd() - currentRenameSelection.cursor.anchor();
    const int length = endOffset - startOffset;
722
723
724
725
726

    for (int i = 0; i < m_renameSelections.size(); ++i) {
        QTextEdit::ExtraSelection &s = m_renameSelections[i];
        int pos = s.cursor.anchor();
        int endPos = s.cursor.position();
727
728
729

        s.cursor.setPosition(pos + startOffset);
        s.cursor.setPosition(pos + endOffset, QTextCursor::KeepAnchor);
730
731
732
733

        switch (operation) {
        case DeletePreviousChar:
            s.cursor.deletePreviousChar();
734
            endPos -= qMax(1, length);
735
736
737
            break;
        case DeleteChar:
            s.cursor.deleteChar();
738
            endPos -= qMax(1, length);
739
740
741
            break;
        case InsertText:
            s.cursor.insertText(text);
742
            endPos += text.length() - length;
743
744
745
746
747
748
749
750
751
752
753
754
755
            break;
        }

        s.cursor.setPosition(pos);
        s.cursor.setPosition(endPos, QTextCursor::KeepAnchor);
    }

    cursor.endEditBlock();

    setExtraSelections(CodeSemanticsSelection, m_renameSelections);
    setTextCursor(cursor);
}

mae's avatar
mae committed
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
void CPPEditor::paste()
{
    if (m_currentRenameSelection == -1) {
        BaseTextEditor::paste();
        return;
    }

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

void CPPEditor::cut()
{
    if (m_currentRenameSelection == -1) {
        BaseTextEditor::cut();
        return;
    }

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

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

816
817
void CPPEditor::abortRename()
{
mae's avatar
mae committed
818
819
    if (m_currentRenameSelection < 0)
        return;
820
    m_renameSelections[m_currentRenameSelection].format = m_occurrencesFormat;
821
    m_currentRenameSelection = -1;
mae's avatar
mae committed
822
823
    m_currentRenameSelectionBegin = QTextCursor();
    m_currentRenameSelectionEnd = QTextCursor();
824
825
826
    setExtraSelections(CodeSemanticsSelection, m_renameSelections);
}

con's avatar
con committed
827
828
829
830
831
void CPPEditor::onDocumentUpdated(Document::Ptr doc)
{
    if (doc->fileName() != file()->fileName())
        return;

832
833
834
    if (doc->editorRevision() != editorRevision())
        return;

Roberto Raggi's avatar
Roberto Raggi committed
835
836
837
838
839
840
841
    if (! m_initialized) {
        m_initialized = true;

        const SemanticHighlighter::Source source = currentSource(/*force = */ true);
        m_semanticHighlighter->rehighlight(source);
    }

con's avatar
con committed
842
    m_overviewModel->rebuild(doc);
843
844
    OverviewTreeView *treeView = static_cast<OverviewTreeView *>(m_methodCombo->view());
    treeView->sync();
Roberto Raggi's avatar
Roberto Raggi committed
845
    updateMethodBoxIndexNow();
con's avatar
con committed
846
847
}

848
849
850
CPlusPlus::Symbol *CPPEditor::findCanonicalSymbol(const QTextCursor &cursor,
                                                  Document::Ptr doc,
                                                  const Snapshot &snapshot) const
Roberto Raggi's avatar
Roberto Raggi committed
851
{
852
853
854
    if (! doc)
        return 0;

855
    QTextCursor tc = cursor;
Roberto Raggi's avatar
Roberto Raggi committed
856
857
    int line, col;
    convertPosition(tc.position(), &line, &col);
858
    ++col; // 1-based line and 1-based column
Roberto Raggi's avatar
Roberto Raggi committed
859

860
861
862
863
864
    int pos = tc.position();
    while (document()->characterAt(pos).isLetterOrNumber() ||
           document()->characterAt(pos) == QLatin1Char('_'))
        ++pos;
    tc.setPosition(pos);
Roberto Raggi's avatar
Roberto Raggi committed
865
866
867

    ExpressionUnderCursor expressionUnderCursor;
    const QString code = expressionUnderCursor(tc);
868
    // qDebug() << "code:" << code;
Roberto Raggi's avatar
Roberto Raggi committed
869
870
871
872
873
874

    TypeOfExpression typeOfExpression;
    typeOfExpression.setSnapshot(snapshot);

    Symbol *lastVisibleSymbol = doc->findSymbolAt(line, col);

875
876
877
    const QList<LookupItem> results = typeOfExpression(code, doc,
                                                   lastVisibleSymbol,
                                                   TypeOfExpression::Preprocess);
Roberto Raggi's avatar
Roberto Raggi committed
878

879
880
    NamespaceBindingPtr glo = bind(doc, snapshot);
    Symbol *canonicalSymbol = LookupContext::canonicalSymbol(results, glo.data());
881

882
883
884
    return canonicalSymbol;
}

Christian Kamm's avatar
Christian Kamm committed
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
const Macro *CPPEditor::findCanonicalMacro(const QTextCursor &cursor,
                                                  Document::Ptr doc) const
{
    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;
}
902
903

void CPPEditor::findUsages()
904
{
905
    if (Symbol *canonicalSymbol = markSymbols()) {
Erik Verbruggen's avatar
Erik Verbruggen committed
906
        m_modelManager->findUsages(m_lastSemanticInfo.doc, canonicalSymbol);
Christian Kamm's avatar
Christian Kamm committed
907
908
    } else if (const Macro *macro = findCanonicalMacro(textCursor(), m_lastSemanticInfo.doc)) {
        m_modelManager->findMacroUsages(*macro);
909
    }
910
911
912
}

void CPPEditor::renameUsages()
913
{
914
915
916
    renameUsagesNow();
}

917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
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();
}

940
941
void CPPEditor::hideRenameNotification()
{
942
    setShowWarningMessage(false);
943
    Core::EditorManager::instance()->hideEditorInfoBar(QLatin1String("CppEditor.Rename"));
944
945
946
947
}

void CPPEditor::renameUsagesNow()
{
948
    if (Symbol *canonicalSymbol = markSymbols()) {
949
        if (canonicalSymbol->identifier() != 0) {
950
951
952
953
954
955
            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()));
            }
956

Erik Verbruggen's avatar
Erik Verbruggen committed
957
            m_modelManager->renameUsages(m_lastSemanticInfo.doc, canonicalSymbol);
958
        }
959
960
961
962
963
964
    }
}

Symbol *CPPEditor::markSymbols()
{
    updateSemanticInfo(m_semanticHighlighter->semanticInfo(currentSource()));
965

mae's avatar
mae committed
966
    abortRename();
967
968
969
970
971

    QList<QTextEdit::ExtraSelection> selections;

    SemanticInfo info = m_lastSemanticInfo;

972
973
974
    Symbol *canonicalSymbol = findCanonicalSymbol(textCursor(), info.doc, info.snapshot);
    if (canonicalSymbol) {
        TranslationUnit *unit = info.doc->translationUnit();
975

976
977
978
979
        const QList<int> references = m_modelManager->references(canonicalSymbol, info.doc, info.snapshot);
        foreach (int index, references) {
            unsigned line, column;
            unit->getTokenPosition(index, &line, &column);
980

981
982
            if (column)
                --column;  // adjust the column position.
983

984
            const int len = unit->tokenAt(index).f.length;
985

986
987
988
            QTextCursor cursor(document()->findBlockByNumber(line - 1));
            cursor.setPosition(cursor.position() + column);
            cursor.setPosition(cursor.position() + len, QTextCursor::KeepAnchor);
989

990
991
992
993
            QTextEdit::ExtraSelection sel;
            sel.format = m_occurrencesFormat;
            sel.cursor = cursor;
            selections.append(sel);
994
        }
Roberto Raggi's avatar
Roberto Raggi committed
995
    }
996
997
998

    setExtraSelections(CodeSemanticsSelection, selections);
    return canonicalSymbol;
Roberto Raggi's avatar
Roberto Raggi committed
999
1000
}