cppeditor.cpp 71.7 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
**
9
**
10
** GNU Lesser General Public License Usage
11
**
hjk's avatar
hjk committed
12 13 14 15 16 17
** 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.
18
**
con's avatar
con committed
19
** In addition, as a special exception, Nokia gives you certain additional
hjk's avatar
hjk committed
20
** rights. These rights are described in the Nokia Qt LGPL Exception
con's avatar
con committed
21 22
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
23 24 25 26 27
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
con's avatar
con committed
28
** If you have questions regarding the use of this file, please contact
29
** Nokia at qt-info@nokia.com.
con's avatar
con committed
30
**
31
**************************************************************************/
hjk's avatar
hjk committed
32

con's avatar
con committed
33 34 35 36
#include "cppeditor.h"
#include "cppeditorconstants.h"
#include "cppplugin.h"
#include "cpphighlighter.h"
Roberto Raggi's avatar
Roberto Raggi committed
37
#include "cppchecksymbols.h"
38
#include "cpplocalsymbols.h"
39
#include "cppautocompleter.h"
Leandro Melo's avatar
Leandro Melo committed
40
#include "cppquickfixassistant.h"
Roberto Raggi's avatar
Roberto Raggi committed
41

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

Roberto Raggi's avatar
Roberto Raggi committed
64
#include <cpptools/cpptoolsplugin.h>
65
#include <cpptools/cpptoolsconstants.h>
Christian Kamm's avatar
Christian Kamm committed
66
#include <cpptools/cppcodeformatter.h>
Leandro Melo's avatar
Leandro Melo committed
67
#include <cpptools/cppcompletionassist.h>
68 69
#include <cpptools/cppqtstyleindenter.h>
#include <cpptools/cppcodestylesettings.h>
70
#include <cpptools/cpprefactoringchanges.h>
71
#include <cpptools/cpptoolsreuse.h>
con's avatar
con committed
72 73

#include <coreplugin/icore.h>
74
#include <coreplugin/actionmanager/actionmanager.h>
75
#include <coreplugin/actionmanager/actioncontainer.h>
76
#include <coreplugin/actionmanager/command.h>
77
#include <coreplugin/id.h>
con's avatar
con committed
78 79
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/editormanager/editormanager.h>
dt's avatar
dt committed
80
#include <coreplugin/mimedatabase.h>
81
#include <utils/qtcassert.h>
82
#include <utils/uncommentselection.h>
83
#include <extensionsystem/pluginmanager.h>
con's avatar
con committed
84 85
#include <projectexplorer/projectexplorerconstants.h>
#include <texteditor/basetextdocument.h>
86
#include <texteditor/basetextdocumentlayout.h>
con's avatar
con committed
87
#include <texteditor/fontsettings.h>
88
#include <texteditor/tabsettings.h>
con's avatar
con committed
89
#include <texteditor/texteditorconstants.h>
90
#include <texteditor/refactoroverlay.h>
91
#include <texteditor/semantichighlighter.h>
Leandro Melo's avatar
Leandro Melo committed
92 93 94
#include <texteditor/codeassist/basicproposalitemlistmodel.h>
#include <texteditor/codeassist/basicproposalitem.h>
#include <texteditor/codeassist/genericproposal.h>
con's avatar
con committed
95 96 97 98

#include <QtCore/QDebug>
#include <QtCore/QTime>
#include <QtCore/QTimer>
99
#include <QtCore/QStack>
100
#include <QtCore/QSettings>
101
#include <QtCore/QSignalMapper>
con's avatar
con committed
102
#include <QtGui/QAction>
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
103
#include <QtGui/QApplication>
104
#include <QtGui/QHeaderView>
con's avatar
con committed
105 106 107 108 109
#include <QtGui/QLayout>
#include <QtGui/QMenu>
#include <QtGui/QShortcut>
#include <QtGui/QTextEdit>
#include <QtGui/QComboBox>
con's avatar
con committed
110
#include <QtGui/QToolBar>
con's avatar
con committed
111
#include <QtGui/QTreeView>
112
#include <QtGui/QSortFilterProxyModel>
113
#include <QtGui/QMainWindow>
con's avatar
con committed
114

115 116
#include <sstream>

Roberto Raggi's avatar
Roberto Raggi committed
117
enum {
118
    UPDATE_OUTLINE_INTERVAL = 500,
119 120
    UPDATE_USES_INTERVAL = 500,
    UPDATE_FUNCTION_DECL_DEF_LINK_INTERVAL = 200
Roberto Raggi's avatar
Roberto Raggi committed
121 122
};

Roberto Raggi's avatar
Roberto Raggi committed
123 124 125
using namespace CPlusPlus;
using namespace CppEditor::Internal;

126 127 128 129
namespace {
bool semanticHighlighterDisabled = qstrcmp(qVersion(), "4.7.0") == 0;
}

con's avatar
con committed
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
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();
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
    }

    void adjustWidth()
    {
        const int w = Core::ICore::instance()->mainWindow()->geometry().width();
        setMaximumWidth(w);
        setMinimumWidth(qMin(qMax(sizeHintForColumn(0), minimumSizeHint().width()), w));
    }
};

class OverviewCombo : public QComboBox
{
public:
    OverviewCombo(QWidget *parent = 0) : QComboBox(parent)
    {}

    void showPopup()
    {
        static_cast<OverviewTreeView *>(view())->adjustWidth();
        QComboBox::showPopup();
con's avatar
con committed
165 166 167
    }
};

168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
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
193 194 195 196
class FunctionDefinitionUnderCursor: protected ASTVisitor
{
    unsigned _line;
    unsigned _column;
197
    DeclarationAST *_functionDefinition;
Roberto Raggi's avatar
Roberto Raggi committed
198 199

public:
Roberto Raggi's avatar
Roberto Raggi committed
200 201
    FunctionDefinitionUnderCursor(TranslationUnit *translationUnit)
        : ASTVisitor(translationUnit),
Roberto Raggi's avatar
Roberto Raggi committed
202
          _line(0), _column(0)
Roberto Raggi's avatar
Roberto Raggi committed
203 204
    { }

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

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

        else if (FunctionDefinitionAST *def = ast->asFunctionDefinition()) {
221 222 223 224 225 226
            return checkDeclaration(def);
        }

        else if (ObjCMethodDeclarationAST *method = ast->asObjCMethodDeclaration()) {
            if (method->function_body)
                return checkDeclaration(method);
Roberto Raggi's avatar
Roberto Raggi committed
227 228 229 230 231
        }

        return true;
    }

232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
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
249 250
};

251 252
class FindFunctionDefinitions: protected SymbolVisitor
{
Roberto Raggi's avatar
Roberto Raggi committed
253
    const Name *_declarationName;
254 255 256 257 258 259 260 261
    QList<Function *> *_functions;

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

Roberto Raggi's avatar
Roberto Raggi committed
262
    void operator()(const Name *declarationName, Scope *globals,
263 264 265 266 267
                    QList<Function *> *functions)
    {
        _declarationName = declarationName;
        _functions = functions;

Roberto Raggi's avatar
Roberto Raggi committed
268 269
        for (unsigned i = 0; i < globals->memberCount(); ++i) {
            accept(globals->memberAt(i));
270 271 272 273 274 275 276 277
        }
    }

protected:
    using SymbolVisitor::visit;

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

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

        return false;
    }
};

289

290
struct CanonicalSymbol
291
{
292
    CPPEditorWidget *editor;
293 294 295
    TypeOfExpression typeOfExpression;
    SemanticInfo info;

296
    CanonicalSymbol(CPPEditorWidget *editor, const SemanticInfo &info)
Erik Verbruggen's avatar
Erik Verbruggen committed
297
        : editor(editor), info(info)
298 299 300 301 302 303 304 305 306
    {
        typeOfExpression.init(info.doc, info.snapshot);
    }

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

307
    static inline bool isIdentifierChar(const QChar &ch)
308 309 310 311
    {
        return ch.isLetterOrNumber() || ch == QLatin1Char('_');
    }

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

317
    static Scope *getScopeAndExpression(CPPEditorWidget *editor, const SemanticInfo &info,
318 319
                                        const QTextCursor &cursor,
                                        QString *code)
320 321 322 323 324 325 326 327 328 329 330 331
    {
        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();
332 333 334 335 336 337

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

        while (isIdentifierChar(document->characterAt(pos)))
338 339 340
            ++pos;
        tc.setPosition(pos);

341 342 343 344 345 346 347 348 349 350 351
        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);
352

353 354 355 356 357 358 359 360 361 362
        return 0;
    }

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

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

Roberto Raggi's avatar
Roberto Raggi committed
365 366
        for (int i = results.size() - 1; i != -1; --i) {
            const LookupItem &r = results.at(i);
367
            Symbol *decl = r.declaration();
Roberto Raggi's avatar
Roberto Raggi committed
368

369
            if (! (decl && decl->enclosingScope()))
Roberto Raggi's avatar
Roberto Raggi committed
370 371
                break;

372
            if (Class *classScope = r.declaration()->enclosingScope()->asClass()) {
373 374 375 376 377 378 379 380 381 382 383
                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
384 385 386
        }

        for (int i = 0; i < results.size(); ++i) {
387 388 389 390 391 392 393 394
            const LookupItem &r = results.at(i);

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

        return 0;
    }
395

396 397
};

398 399 400

int numberOfClosedEditors = 0;

con's avatar
con committed
401 402
} // end of anonymous namespace

403 404
CPPEditor::CPPEditor(CPPEditorWidget *editor)
    : BaseTextEditor(editor)
con's avatar
con committed
405
{
406 407 408
    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
409 410
}

411 412
CPPEditorWidget::CPPEditorWidget(QWidget *parent)
    : TextEditor::BaseTextEditorWidget(parent)
413
    , m_currentRenameSelection(NoCurrentRenameSelection)
414
    , m_inRename(false)
mae's avatar
mae committed
415 416
    , m_inRenameChanged(false)
    , m_firstRenameChange(false)
417
    , m_objcEnabled(false)
con's avatar
con committed
418
{
Roberto Raggi's avatar
Roberto Raggi committed
419
    m_initialized = false;
420
    qRegisterMetaType<CppEditor::Internal::SemanticInfo>("CppEditor::Internal::SemanticInfo");
Roberto Raggi's avatar
Roberto Raggi committed
421 422 423 424

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

con's avatar
con committed
425 426
    setParenthesesMatchingEnabled(true);
    setMarksVisible(true);
427
    setCodeFoldingSupported(true);
428
    setIndenter(new CppTools::CppQtStyleIndenter);
429
    setAutoCompleter(new CppAutoCompleter);
dt's avatar
dt committed
430

431
    baseTextDocument()->setSyntaxHighlighter(new CppHighlighter);
con's avatar
con committed
432

433
    m_modelManager = CppModelManagerInterface::instance();
con's avatar
con committed
434 435 436 437 438

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

440
    m_highlightRevision = 0;
441 442
    connect(&m_highlightWatcher, SIGNAL(resultsReadyAt(int,int)), SLOT(highlightSymbolUsages(int,int)));
    connect(&m_highlightWatcher, SIGNAL(finished()), SLOT(finishHighlightSymbolUsages()));
443 444 445 446

    m_referencesRevision = 0;
    m_referencesCursorPosition = 0;
    connect(&m_referencesWatcher, SIGNAL(finished()), SLOT(markSymbolsNow()));
447 448 449 450 451 452 453

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

    m_declDefLinkFinder = new FunctionDeclDefLinkFinder(this);
    connect(m_declDefLinkFinder, SIGNAL(foundLink(QSharedPointer<FunctionDeclDefLink>)),
            this, SLOT(onFunctionDeclDefLinkFound(QSharedPointer<FunctionDeclDefLink>)));
con's avatar
con committed
454 455
}

456
CPPEditorWidget::~CPPEditorWidget()
con's avatar
con committed
457
{
Roberto Raggi's avatar
Roberto Raggi committed
458 459
    m_semanticHighlighter->abort();
    m_semanticHighlighter->wait();
460 461 462 463 464 465

    ++numberOfClosedEditors;
    if (numberOfClosedEditors == 5) {
        m_modelManager->GC();
        numberOfClosedEditors = 0;
    }
con's avatar
con committed
466 467
}

468
TextEditor::BaseTextEditor *CPPEditorWidget::createEditor()
con's avatar
con committed
469
{
470
    CPPEditor *editable = new CPPEditor(this);
con's avatar
con committed
471 472 473 474
    createToolBar(editable);
    return editable;
}

475
void CPPEditorWidget::createToolBar(CPPEditor *editor)
con's avatar
con committed
476
{
477
    m_outlineCombo = new OverviewCombo;
Kai Koehne's avatar
Kai Koehne committed
478
    m_outlineCombo->setMinimumContentsLength(22);
479 480

    // Make the combo box prefer to expand
Kai Koehne's avatar
Kai Koehne committed
481
    QSizePolicy policy = m_outlineCombo->sizePolicy();
482
    policy.setHorizontalPolicy(QSizePolicy::Expanding);
Kai Koehne's avatar
Kai Koehne committed
483
    m_outlineCombo->setSizePolicy(policy);
484

Kai Koehne's avatar
Kai Koehne committed
485 486 487 488
    QTreeView *outlineView = new OverviewTreeView;
    outlineView->header()->hide();
    outlineView->setItemsExpandable(false);
    m_outlineCombo->setView(outlineView);
489
    m_outlineCombo->setMaxVisibleItems(40);
con's avatar
con committed
490

Kai Koehne's avatar
Kai Koehne committed
491 492 493
    m_outlineModel = new OverviewModel(this);
    m_proxyModel = new OverviewProxyModel(m_outlineModel, this);
    if (CppPlugin::instance()->sortedOutline())
494 495
        m_proxyModel->sort(0, Qt::AscendingOrder);
    else
Kai Koehne's avatar
Kai Koehne committed
496
        m_proxyModel->sort(-1, Qt::AscendingOrder); // don't sort yet, but set column for sortedOutline()
497 498
    m_proxyModel->setDynamicSortFilter(true);
    m_proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
Kai Koehne's avatar
Kai Koehne committed
499
    m_outlineCombo->setModel(m_proxyModel);
500

Kai Koehne's avatar
Kai Koehne committed
501 502
    m_outlineCombo->setContextMenuPolicy(Qt::ActionsContextMenu);
    m_sortAction = new QAction(tr("Sort Alphabetically"), m_outlineCombo);
503
    m_sortAction->setCheckable(true);
Kai Koehne's avatar
Kai Koehne committed
504 505 506
    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
507

508 509 510 511 512
    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
513 514 515 516
    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
517

Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
518 519 520 521 522
    m_updateUsesTimer = new QTimer(this);
    m_updateUsesTimer->setSingleShot(true);
    m_updateUsesTimer->setInterval(UPDATE_USES_INTERVAL);
    connect(m_updateUsesTimer, SIGNAL(timeout()), this, SLOT(updateUsesNow()));

523 524 525 526 527
    m_updateFunctionDeclDefLinkTimer = new QTimer(this);
    m_updateFunctionDeclDefLinkTimer->setSingleShot(true);
    m_updateFunctionDeclDefLinkTimer->setInterval(UPDATE_FUNCTION_DECL_DEF_LINK_INTERVAL);
    connect(m_updateFunctionDeclDefLinkTimer, SIGNAL(timeout()), this, SLOT(updateFunctionDeclDefLinkNow()));

Kai Koehne's avatar
Kai Koehne committed
528 529 530
    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()));
531
    connect(document(), SIGNAL(contentsChange(int,int,int)), this, SLOT(onContentsChanged(int,int,int)));
con's avatar
con committed
532 533 534

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

535 536 537
    // 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
538 539 540 541 542

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

543 544
    connect(m_semanticHighlighter, SIGNAL(changed(CppEditor::Internal::SemanticInfo)),
            this, SLOT(updateSemanticInfo(CppEditor::Internal::SemanticInfo)));
Roberto Raggi's avatar
Roberto Raggi committed
545

546
    editor->insertExtraToolBarWidget(TextEditor::BaseTextEditor::Left, m_outlineCombo);
con's avatar
con committed
547 548
}

549
void CPPEditorWidget::paste()
mae's avatar
mae committed
550
{
551
    if (m_currentRenameSelection == NoCurrentRenameSelection) {
552
        BaseTextEditorWidget::paste();
mae's avatar
mae committed
553 554 555 556
        return;
    }

    startRename();
557
    BaseTextEditorWidget::paste();
mae's avatar
mae committed
558 559 560
    finishRename();
}

561
void CPPEditorWidget::cut()
mae's avatar
mae committed
562
{
563
    if (m_currentRenameSelection == NoCurrentRenameSelection) {
564
        BaseTextEditorWidget::cut();
mae's avatar
mae committed
565 566 567 568
        return;
    }

    startRename();
569
    BaseTextEditorWidget::cut();
mae's avatar
mae committed
570 571 572
    finishRename();
}

573
CppModelManagerInterface *CPPEditorWidget::modelManager() const
574 575 576 577
{
    return m_modelManager;
}

578
void CPPEditorWidget::setMimeType(const QString &mt)
579
{
580
    BaseTextEditorWidget::setMimeType(mt);
581 582 583
    setObjCEnabled(mt == CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE);
}

584
void CPPEditorWidget::setObjCEnabled(bool onoff)
585 586 587 588
{
    m_objcEnabled = onoff;
}

589
bool CPPEditorWidget::isObjCEnabled() const
590 591
{ return m_objcEnabled; }

592
void CPPEditorWidget::startRename()
mae's avatar
mae committed
593 594 595 596
{
    m_inRenameChanged = false;
}

597
void CPPEditorWidget::finishRename()
mae's avatar
mae committed
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
{
    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;
}

628
void CPPEditorWidget::abortRename()
629
{
630
    if (m_currentRenameSelection <= NoCurrentRenameSelection)
mae's avatar
mae committed
631
        return;
632
    m_renameSelections[m_currentRenameSelection].format = m_occurrencesFormat;
633
    m_currentRenameSelection = NoCurrentRenameSelection;
mae's avatar
mae committed
634 635
    m_currentRenameSelectionBegin = QTextCursor();
    m_currentRenameSelectionEnd = QTextCursor();
636 637 638
    setExtraSelections(CodeSemanticsSelection, m_renameSelections);
}

639
void CPPEditorWidget::onDocumentUpdated(Document::Ptr doc)
con's avatar
con committed
640 641 642 643
{
    if (doc->fileName() != file()->fileName())
        return;

644 645 646
    if (doc->editorRevision() != editorRevision())
        return;

647 648 649 650 651
    if (! m_initialized ||
            (Core::EditorManager::instance()->currentEditor() == editor()
             && (!m_lastSemanticInfo.doc
                 || !m_lastSemanticInfo.doc->translationUnit()->ast()
                 || m_lastSemanticInfo.doc->fileName() != file()->fileName()))) {
Roberto Raggi's avatar
Roberto Raggi committed
652
        m_initialized = true;
653
        semanticRehighlight(/* force = */ true);
Roberto Raggi's avatar
Roberto Raggi committed
654 655
    }

656
    m_updateOutlineTimer->start();
con's avatar
con committed
657 658
}

659
const Macro *CPPEditorWidget::findCanonicalMacro(const QTextCursor &cursor, Document::Ptr doc) const
Christian Kamm's avatar
Christian Kamm committed
660 661 662 663 664 665 666 667 668 669 670 671 672 673 674
{
    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;
}
675

676
void CPPEditorWidget::findUsages()
677
{
678
    SemanticInfo info = m_lastSemanticInfo;
679
    info.snapshot = CppModelManagerInterface::instance()->snapshot();
680
    info.snapshot.insert(info.doc);
681

682
    CanonicalSymbol cs(this, info);
683 684 685 686
    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
687
        m_modelManager->findMacroUsages(*macro);
688
    }
689 690
}

691

692
void CPPEditorWidget::renameUsagesNow(const QString &replacement)
693 694
{
    SemanticInfo info = m_lastSemanticInfo;
695
    info.snapshot = CppModelManagerInterface::instance()->snapshot();
696 697 698
    info.snapshot.insert(info.doc);

    CanonicalSymbol cs(this, info);
699 700
    if (Symbol *canonicalSymbol = cs(textCursor()))
        if (canonicalSymbol->identifier() != 0)
701 702 703
            m_modelManager->renameUsages(canonicalSymbol, cs.context(), replacement);
}

704
void CPPEditorWidget::renameUsages()
705
{
706 707 708
    renameUsagesNow();
}

709
void CPPEditorWidget::markSymbolsNow()
710
{
711 712 713 714 715 716
    if (m_references.isCanceled())
        return;
    else if (m_referencesCursorPosition != position())
        return;
    else if (m_referencesRevision != editorRevision())
        return;
717

718 719 720
    const SemanticInfo info = m_lastSemanticInfo;
    TranslationUnit *unit = info.doc->translationUnit();
    const QList<int> result = m_references.result();
721 722 723

    QList<QTextEdit::ExtraSelection> selections;

724 725 726
    foreach (int index, result) {
        unsigned line, column;
        unit->getTokenPosition(index, &line, &column);
727

728 729
        if (column)
            --column;  // adjust the column position.
730

731
        const int len = unit->tokenAt(index).f.length;
732

733 734 735
        QTextCursor cursor(document()->findBlockByNumber(line - 1));
        cursor.setPosition(cursor.position() + column);
        cursor.setPosition(cursor.position() + len, QTextCursor::KeepAnchor);
736

737 738 739 740
        QTextEdit::ExtraSelection sel;
        sel.format = m_occurrencesFormat;
        sel.cursor = cursor;
        selections.append(sel);
741

Roberto Raggi's avatar
Roberto Raggi committed
742
    }
743 744

    setExtraSelections(CodeSemanticsSelection, selections);
Roberto Raggi's avatar
Roberto Raggi committed
745 746
}

747
static QList<int> lazyFindReferences(Scope *scope, QString code, Document::Ptr doc, Snapshot snapshot)
748 749
{
    TypeOfExpression typeOfExpression;
750 751 752
    snapshot.insert(doc);
    typeOfExpression.init(doc, snapshot);
    if (Symbol *canonicalSymbol = CanonicalSymbol::canonicalSymbol(scope, code, typeOfExpression)) {
753
        return CppModelManagerInterface::instance()->references(canonicalSymbol, typeOfExpression.context());
754
    }
755 756 757
    return QList<int>();
}

758
void CPPEditorWidget::markSymbols(const QTextCursor &tc, const SemanticInfo &info)
759 760 761 762 763 764 765 766 767 768 769 770
{
    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();
771
        m_references = QtConcurrent::run(&lazyFindReferences, scope, expression, info.doc, info.snapshot);
772
        m_referencesWatcher.setFuture(m_references);
773 774 775 776 777
    } else {
        const QList<QTextEdit::ExtraSelection> selections = extraSelections(CodeSemanticsSelection);

        if (! selections.isEmpty())
            setExtraSelections(CodeSemanticsSelection, QList<QTextEdit::ExtraSelection>());
778 779 780
    }
}

781
void CPPEditorWidget::renameSymbolUnderCursor()
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
782
{
Roberto Raggi's avatar
Roberto Raggi committed
783
    updateSemanticInfo(m_semanticHighlighter->semanticInfo(currentSource()));
mae's avatar
mae committed
784
    abortRename();
785

Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
786 787 788 789 790
    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()
791
                && c.position() <= s.cursor.position()) {
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
792
            m_currentRenameSelection = i;
mae's avatar
mae committed
793 794 795 796 797
            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());
798
            m_renameSelections[i].format = m_occurrenceRenameFormat;
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
799 800 801 802
            setExtraSelections(CodeSemanticsSelection, m_renameSelections);
            break;
        }
    }
803 804

    if (m_renameSelections.isEmpty())
805
        renameUsages();
Thorbjørn Lindeijer's avatar
Thorbjørn Lindeijer committed
806 807
}

808
void CPPEditorWidget::onContentsChanged(int position, int charsRemoved, int charsAdded)
809
{
810 811
    Q_UNUSED(position)

812
    if (m_currentRenameSelection == NoCurrentRenameSelection || m_inRename)
813 814
        return;

mae's avatar
mae committed
815 816 817 818 819 820 821 822 823 824 825
    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)
826 827 828 829 830 831
        abortRename();

    if (charsRemoved > 0)
        updateUses();
}

832
void CPPEditorWidget::updateFileName()
con's avatar
con committed
833 834
{ }

835
void CPPEditorWidget::jumpToOutlineElement(int)
con's avatar
con committed
836
{
Kai Koehne's avatar
Kai Koehne committed
837 838
    QModelIndex index = m_proxyModel->mapToSource(m_outlineCombo->view()->currentIndex());
    Symbol *symbol = m_outlineModel->symbolFromIndex(index);
con's avatar
con committed
839 840 841
    if (! symbol)
        return;

842
    openCppEditorAt(linkToSymbol(symbol));
con's avatar
con committed
843 844
}

845
void CPPEditorWidget::setSortedOutline(bool sort)
846
{
Kai Koehne's avatar
Kai Koehne committed
847
    if (sort != sortedOutline()) {
848 849 850 851 852 853 854
        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
855
        updateOutlineIndexNow();
856 857 858
    }
}

859
bool CPPEditorWidget::sortedOutline() const
860 861 862 863
{
    return (m_proxyModel->sortColumn() == 0);
}

864
void CPPEditorWidget::updateOutlineNow()
865 866 867 868 869 870 871 872 873 874 875 876
{
    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
877
    m_outlineModel->rebuild(document);
878

Kai Koehne's avatar
Kai Koehne committed
879
    OverviewTreeView *treeView = static_cast<OverviewTreeView *>(m_outlineCombo->view());
880
    treeView->sync();
Kai Koehne's avatar
Kai Koehne committed
881
    updateOutlineIndexNow();
882 883
}

884
void CPPEditorWidget::updateOutlineIndex()
con's avatar
con committed
885
{
Kai Koehne's avatar
Kai Koehne committed
886
    m_updateOutlineIndexTimer->start();
Roberto Raggi's avatar
Roberto Raggi committed
887 888
}

889
void CPPEditorWidget::highlightUses(const QList<SemanticInfo::Use> &uses,
890
                              const SemanticInfo &semanticInfo,
891
                              QList<QTextEdit::ExtraSelection> *selections)
Roberto Raggi's avatar
Roberto Raggi committed
892
{
Roberto Raggi's avatar
Roberto Raggi committed
893
    bool isUnused = false;
Roberto Raggi's avatar
Roberto Raggi committed
894 895

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

Roberto Raggi's avatar
Roberto Raggi committed
898
    foreach (const SemanticInfo::Use &use, uses) {
Roberto Raggi's avatar
Roberto Raggi committed
899
        QTextEdit::ExtraSelection sel;
Roberto Raggi's avatar
Roberto Raggi committed
900

Roberto Raggi's avatar
Roberto Raggi committed
901
        if (isUnused)
902
            sel.format = m_occurrencesUnusedFormat;
Roberto Raggi's avatar
Roberto Raggi committed
903
        else
904
            sel.format = m_occurrencesFormat;
Roberto Raggi's avatar
Roberto Raggi committed
905

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

909
        sel.cursor = QTextCursor(document());
Roberto Raggi's avatar
Roberto Raggi committed
910 911
        sel.cursor.setPosition(anchor);
        sel.cursor.setPosition(position, QTextCursor::KeepAnchor);
Roberto Raggi's avatar
Roberto Raggi committed
912

913 914 915 916 917 918 919 920
        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
921
        selections->append(sel);
Roberto Raggi's avatar
Roberto Raggi committed
922 923 924
    }
}

925
void CPPEditorWidget::updateOutlineIndexNow()
Roberto Raggi's avatar
Roberto Raggi committed
926
{
Kai Koehne's avatar
Kai Koehne committed
927
    if (!m_outlineModel->document())
928 929
        return;

Kai Koehne's avatar
Kai Koehne committed
<