cpptoolseditorsupport.cpp 20.4 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
con's avatar
con committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
con's avatar
con committed
7
**
hjk's avatar
hjk committed
8 9 10 11 12 13 14
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17 18 19 20 21 22 23 24 25
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
26 27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
con's avatar
con committed
29

30
#include "cppcodemodelsettings.h"
31
#include "cppcompletionassistprovider.h"
32
#include "cpptoolseditorsupport.h"
33
#include "cpptoolsplugin.h"
con's avatar
con committed
34
#include "cppmodelmanager.h"
35 36
#include "cpplocalsymbols.h"

37 38
#include <coreplugin/editormanager/editormanager.h>

39
#include <utils/qtcassert.h>
40
#include <utils/runextensions.h>
con's avatar
con committed
41

42 43 44
#include <QList>
#include <QMutexLocker>
#include <QTextBlock>
45
#include <QTimer>
con's avatar
con committed
46

47
using namespace CppTools;
con's avatar
con committed
48
using namespace CppTools::Internal;
Roberto Raggi's avatar
Roberto Raggi committed
49
using namespace CPlusPlus;
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
using namespace TextEditor;

namespace {
class FunctionDefinitionUnderCursor: protected ASTVisitor
{
    unsigned _line;
    unsigned _column;
    DeclarationAST *_functionDefinition;

public:
    FunctionDefinitionUnderCursor(TranslationUnit *translationUnit)
        : ASTVisitor(translationUnit),
          _line(0), _column(0)
    { }

    DeclarationAST *operator()(AST *ast, unsigned line, unsigned column)
    {
        _functionDefinition = 0;
        _line = line;
        _column = column;
        accept(ast);
        return _functionDefinition;
    }

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

80
        if (FunctionDefinitionAST *def = ast->asFunctionDefinition())
81 82
            return checkDeclaration(def);

83
        if (ObjCMethodDeclarationAST *method = ast->asObjCMethodDeclaration()) {
84 85 86 87 88 89 90 91 92 93 94 95 96 97
            if (method->function_body)
                return checkDeclaration(method);
        }

        return true;
    }

private:
    bool checkDeclaration(DeclarationAST *ast)
    {
        unsigned startLine, startColumn;
        unsigned endLine, endColumn;
        getTokenStartPosition(ast->firstToken(), &startLine, &startColumn);
        getTokenEndPosition(ast->lastToken() - 1, &endLine, &endColumn);
Roberto Raggi's avatar
Roberto Raggi committed
98

99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
        if (_line > startLine || (_line == startLine && _column >= startColumn)) {
            if (_line < endLine || (_line == endLine && _column < endColumn)) {
                _functionDefinition = ast;
                return false;
            }
        }

        return true;
    }
};

} // anonymous namespace

CppEditorSupport::CppEditorSupport(CppModelManager *modelManager, BaseTextEditor *textEditor)
    : QObject(modelManager)
    , m_modelManager(modelManager)
    , m_textEditor(textEditor)
    , m_updateDocumentInterval(UpdateDocumentDefaultInterval)
    , m_revision(0)
Erik Verbruggen's avatar
Erik Verbruggen committed
118
    , m_editorVisible(textEditor->widget()->isVisible())
119
    , m_cachedContentsEditorRevision(-1)
120
    , m_fileIsBeingReloaded(false)
121 122
    , m_initialized(false)
    , m_lastHighlightRevision(0)
123
    , m_highlightingSupport(modelManager->highlightingSupport(textEditor))
124
    , m_completionAssistProvider(m_modelManager->completionAssistProvider(textEditor))
con's avatar
con committed
125
{
126 127 128
    connect(m_modelManager, SIGNAL(documentUpdated(CPlusPlus::Document::Ptr)),
            this, SLOT(onDocumentUpdated(CPlusPlus::Document::Ptr)));

129 130 131 132 133
    if (m_highlightingSupport && m_highlightingSupport->requiresSemanticInfo()) {
        connect(this, SIGNAL(semanticInfoUpdated(CppTools::SemanticInfo)),
                this, SLOT(startHighlighting()));
    }

134 135 136 137
    m_updateDocumentTimer = new QTimer(this);
    m_updateDocumentTimer->setSingleShot(true);
    m_updateDocumentTimer->setInterval(m_updateDocumentInterval);
    connect(m_updateDocumentTimer, SIGNAL(timeout()), this, SLOT(updateDocumentNow()));
138

139 140 141 142 143 144 145 146 147
    m_updateEditorTimer = new QTimer(this);
    m_updateEditorTimer->setInterval(UpdateEditorInterval);
    m_updateEditorTimer->setSingleShot(true);
    connect(m_updateEditorTimer, SIGNAL(timeout()),
            this, SLOT(updateEditorNow()));

    connect(m_textEditor, SIGNAL(contentsChanged()), this, SLOT(updateDocument()));
    connect(this, SIGNAL(diagnosticsChanged()), this, SLOT(onDiagnosticsChanged()));

148 149
    connect(m_textEditor->document(), SIGNAL(mimeTypeChanged()),
            this, SLOT(onMimeTypeChanged()));
150

151 152 153 154 155
    connect(m_textEditor->document(), SIGNAL(aboutToReload()),
            this, SLOT(onAboutToReload()));
    connect(m_textEditor->document(), SIGNAL(reloadFinished(bool)),
            this, SLOT(onReloadFinished()));

Erik Verbruggen's avatar
Erik Verbruggen committed
156 157 158 159 160 161 162
    connect(Core::EditorManager::instance(), SIGNAL(currentEditorChanged(Core::IEditor *)),
            this, SLOT(onCurrentEditorChanged()));
    m_editorGCTimer = new QTimer(this);
    m_editorGCTimer->setSingleShot(true);
    m_editorGCTimer->setInterval(EditorHiddenGCTimeout);
    connect(m_editorGCTimer, SIGNAL(timeout()), this, SLOT(releaseResources()));

163
    updateDocument();
con's avatar
con committed
164 165 166
}

CppEditorSupport::~CppEditorSupport()
167
{
168
    m_documentParser.cancel();
169 170 171
    m_highlighter.cancel();
    m_futureSemanticInfo.cancel();

172
    m_documentParser.waitForFinished();
173 174 175
    m_highlighter.waitForFinished();
    m_futureSemanticInfo.waitForFinished();
}
con's avatar
con committed
176

177 178
QString CppEditorSupport::fileName() const
{
179
    return m_textEditor->document()->filePath();
180
}
con's avatar
con committed
181

182
QByteArray CppEditorSupport::contents() const
con's avatar
con committed
183
{
184 185
    QMutexLocker locker(&m_cachedContentsLock);

186
    const int editorRev = editorRevision();
187
    if (m_cachedContentsEditorRevision != editorRev && !m_fileIsBeingReloaded) {
188
        m_cachedContentsEditorRevision = editorRev;
189
        m_cachedContents = m_textEditor->textDocument()->contents().toUtf8();
190
    }
con's avatar
con committed
191

192 193
    return m_cachedContents;
}
Roberto Raggi's avatar
Roberto Raggi committed
194

195 196 197
unsigned CppEditorSupport::editorRevision() const
{
    return m_textEditor->editorWidget()->document()->revision();
con's avatar
con committed
198 199
}

200 201
void CppEditorSupport::setExtraDiagnostics(const QString &key,
                                           const QList<Document::DiagnosticMessage> &messages)
con's avatar
con committed
202
{
203 204 205 206
    {
        QMutexLocker locker(&m_diagnosticsMutex);
        m_allDiagnostics.insert(key, messages);
    }
con's avatar
con committed
207

208
    emit diagnosticsChanged();
con's avatar
con committed
209 210
}

211 212 213 214 215 216 217
void CppEditorSupport::setIfdefedOutBlocks(const QList<BlockRange> &ifdefedOutBlocks)
{
    m_editorUpdates.ifdefedOutBlocks = ifdefedOutBlocks;

    emit diagnosticsChanged();
}

218 219 220 221 222
bool CppEditorSupport::initialized()
{
    return m_initialized;
}

223
SemanticInfo CppEditorSupport::recalculateSemanticInfo(bool emitSignalWhenFinished)
224
{
225
    m_futureSemanticInfo.cancel();
226

227 228 229
    SemanticInfo::Source source = currentSource(false);
    recalculateSemanticInfoNow(source, emitSignalWhenFinished);
    return m_lastSemanticInfo;
230 231
}

232 233 234 235 236 237 238
Document::Ptr CppEditorSupport::lastSemanticInfoDocument() const
{
    QMutexLocker locker(&m_lastSemanticInfoLock);

    return m_lastSemanticInfo.doc;
}

239 240
void CppEditorSupport::recalculateSemanticInfoDetached(bool force)
{
241 242 243 244 245
    // Block premature calculation caused by CppEditorPlugin::currentEditorChanged
    // when the editor is created.
    if (!m_initialized)
        return;

246 247 248 249
    m_futureSemanticInfo.cancel();
    SemanticInfo::Source source = currentSource(force);
    m_futureSemanticInfo = QtConcurrent::run<CppEditorSupport, void>(
                &CppEditorSupport::recalculateSemanticInfoDetached_helper, this, source);
con's avatar
con committed
250

251
    if (force && m_highlightingSupport && !m_highlightingSupport->requiresSemanticInfo())
252 253
        startHighlighting();
}
con's avatar
con committed
254

255 256
CppCompletionAssistProvider *CppEditorSupport::completionAssistProvider() const
{
257
    return m_completionAssistProvider;
258 259
}

260 261 262 263
QSharedPointer<SnapshotUpdater> CppEditorSupport::snapshotUpdater()
{
    QSharedPointer<SnapshotUpdater> updater = m_snapshotUpdater;
    if (!updater) {
Orgad Shaneh's avatar
Orgad Shaneh committed
264
        updater = QSharedPointer<SnapshotUpdater>(new SnapshotUpdater(fileName()));
265
        m_snapshotUpdater = updater;
266 267 268

        QSharedPointer<CppCodeModelSettings> cms = CppToolsPlugin::instance()->codeModelSettings();
        updater->setUsePrecompiledHeaders(cms->pchUsage() != CppCodeModelSettings::PchUse_None);
269 270 271 272
    }
    return updater;
}

con's avatar
con committed
273
void CppEditorSupport::updateDocument()
Roberto Raggi's avatar
Roberto Raggi committed
274
{
275
    m_revision = editorRevision();
276

277 278
    if (qobject_cast<BaseTextEditorWidget*>(m_textEditor->widget()) != 0)
        m_updateEditorTimer->stop();
Roberto Raggi's avatar
Roberto Raggi committed
279

280
    m_updateDocumentTimer->start(m_updateDocumentInterval);
Roberto Raggi's avatar
Roberto Raggi committed
281
}
con's avatar
con committed
282

283
static void parse(QFutureInterface<void> &future, QSharedPointer<SnapshotUpdater> updater)
284 285
{
    future.setProgressRange(0, 1);
286 287 288 289
    if (future.isCanceled()) {
        future.setProgressValue(1);
        return;
    }
290 291 292

    CppModelManager *cmm = qobject_cast<CppModelManager *>(CppModelManager::instance());
    updater->update(cmm->workingCopy());
293
    cmm->finishedRefreshingSourceFiles(QStringList(updater->fileInEditor()));
294 295 296 297

    future.setProgressValue(1);
}

con's avatar
con committed
298 299
void CppEditorSupport::updateDocumentNow()
{
300 301 302 303 304
    if (m_documentParser.isRunning() || m_revision != editorRevision()) {
        m_updateDocumentTimer->start(m_updateDocumentInterval);
    } else {
        m_updateDocumentTimer->stop();

305
        if (m_fileIsBeingReloaded || fileName().isEmpty())
306 307 308
            return;

        if (m_highlightingSupport && !m_highlightingSupport->requiresSemanticInfo())
309 310
            startHighlighting();

311
        m_documentParser = QtConcurrent::run(&parse, snapshotUpdater());
312 313 314
    }
}

315 316 317 318 319
bool CppEditorSupport::isUpdatingDocument()
{
    return m_updateDocumentTimer->isActive() || m_documentParser.isRunning();
}

320 321 322 323 324 325 326 327 328 329 330 331
void CppEditorSupport::onDocumentUpdated(Document::Ptr doc)
{
    if (doc.isNull())
        return;

    if (doc->fileName() != fileName())
        return; // some other document got updated

    if (doc->editorRevision() != editorRevision())
        return; // outdated content, wait for a new document to be parsed

    // Update the ifdeffed-out blocks:
332 333 334 335 336 337 338
    if (m_highlightingSupport && !m_highlightingSupport->hightlighterHandlesIfdefedOutBlocks()) {
        QList<Document::Block> skippedBlocks = doc->skippedBlocks();
        QList<BlockRange> ifdefedOutBlocks;
        ifdefedOutBlocks.reserve(skippedBlocks.size());
        foreach (const Document::Block &block, skippedBlocks)
            ifdefedOutBlocks.append(BlockRange(block.begin(), block.end()));
        setIfdefedOutBlocks(ifdefedOutBlocks);
339 340 341 342 343 344 345 346 347
    }

    if (m_highlightingSupport && !m_highlightingSupport->hightlighterHandlesDiagnostics()) {
        // Update the parser errors/warnings:
        static const QString key = QLatin1String("CppTools.ParserDiagnostics");
        setExtraDiagnostics(key, doc->diagnosticMessages());
    }

    // update semantic info in a future
348
    if (!m_initialized ||
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
            (m_textEditor->widget()->isVisible()
             && (m_lastSemanticInfo.doc.isNull()
                 || m_lastSemanticInfo.doc->translationUnit()->ast() == 0
                 || m_lastSemanticInfo.doc->fileName() != fileName()))) {
        m_initialized = true;
        recalculateSemanticInfoDetached(/* force = */ true);
    }

    // notify the editor that the document is updated
    emit documentUpdated();
}

void CppEditorSupport::startHighlighting()
{
    if (!m_highlightingSupport)
        return;

366 367
    // Start highlighting only if the editor is or would be visible
    // (in case another mode is active) in the edit mode.
368
    if (!Core::EditorManager::visibleEditors().contains(m_textEditor))
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
        return;

    if (m_highlightingSupport->requiresSemanticInfo()) {
        Snapshot snapshot;
        Document::Ptr doc;
        unsigned revision;
        bool forced;

        {
            QMutexLocker locker(&m_lastSemanticInfoLock);
            snapshot = m_lastSemanticInfo.snapshot;
            doc = m_lastSemanticInfo.doc;
            revision = m_lastSemanticInfo.revision;
            forced = m_lastSemanticInfo.forced;
        }

        if (doc.isNull())
            return;
        if (!forced && m_lastHighlightRevision == revision)
            return;
        m_highlighter.cancel();

        m_highlighter = m_highlightingSupport->highlightingFuture(doc, snapshot);
        m_lastHighlightRevision = revision;
Orgad Shaneh's avatar
Orgad Shaneh committed
393
        emit highlighterStarted(&m_highlighter, m_lastHighlightRevision);
con's avatar
con committed
394
    } else {
395 396 397 398
        static const Document::Ptr dummyDoc;
        static const Snapshot dummySnapshot;
        m_highlighter = m_highlightingSupport->highlightingFuture(dummyDoc, dummySnapshot);
        m_lastHighlightRevision = editorRevision();
Orgad Shaneh's avatar
Orgad Shaneh committed
399
        emit highlighterStarted(&m_highlighter, m_lastHighlightRevision);
400 401 402
    }
}

403
/// \brief This slot puts the new diagnostics into the editorUpdates. This function has to be called
404 405 406 407 408 409 410 411 412 413 414 415
///        on the UI thread.
void CppEditorSupport::onDiagnosticsChanged()
{
    QList<Document::DiagnosticMessage> allDiagnostics;
    {
        QMutexLocker locker(&m_diagnosticsMutex);
        foreach (const QList<Document::DiagnosticMessage> &msgs, m_allDiagnostics.values())
            allDiagnostics.append(msgs);
    }

    if (!m_textEditor)
        return;
Roberto Raggi's avatar
Roberto Raggi committed
416

417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
    // set up the format for the errors
    QTextCharFormat errorFormat;
    errorFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline);
    errorFormat.setUnderlineColor(Qt::red);

    // set up the format for the warnings.
    QTextCharFormat warningFormat;
    warningFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline);
    warningFormat.setUnderlineColor(Qt::darkYellow);

    QTextDocument *doc = m_textEditor->editorWidget()->document();

    m_editorUpdates.selections.clear();
    foreach (const Document::DiagnosticMessage &m, allDiagnostics) {
        QTextEdit::ExtraSelection sel;
        if (m.isWarning())
            sel.format = warningFormat;
        else
            sel.format = errorFormat;

        QTextCursor c(doc->findBlockByNumber(m.line() - 1));
        const QString text = c.block().text();
        if (m.length() > 0 && m.column() + m.length() < (unsigned)text.size()) {
            int column = m.column() > 0 ? m.column() - 1 : 0;
            c.setPosition(c.position() + column);
            c.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, m.length());
        } else {
            for (int i = 0; i < text.size(); ++i) {
445
                if (!text.at(i).isSpace()) {
446 447 448 449 450 451 452 453 454
                    c.setPosition(c.position() + i);
                    break;
                }
            }
            c.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
        }
        sel.cursor = c;
        sel.format.setToolTip(m.text());
        m_editorUpdates.selections.append(sel);
con's avatar
con committed
455
    }
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477

    m_editorUpdates.revision = doc->revision();

    updateEditor();
}
void CppEditorSupport::updateEditor()
{
    m_updateEditorTimer->start(UpdateEditorInterval);
}

void CppEditorSupport::updateEditorNow()
{
    if (!m_textEditor)
        return;

    BaseTextEditorWidget *editorWidget = m_textEditor->editorWidget();
    if (editorWidget->document()->revision() != m_editorUpdates.revision)
        return; // outdated

    editorWidget->setExtraSelections(BaseTextEditorWidget::CodeWarningsSelection,
                                     m_editorUpdates.selections);
    editorWidget->setIfdefedOutBlocks(m_editorUpdates.ifdefedOutBlocks);
con's avatar
con committed
478 479
}

Erik Verbruggen's avatar
Erik Verbruggen committed
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
void CppEditorSupport::onCurrentEditorChanged()
{
    bool editorVisible = m_textEditor->widget()->isVisible();

    if (m_editorVisible != editorVisible) {
        m_editorVisible = editorVisible;
        if (editorVisible) {
            m_editorGCTimer->stop();
            QMutexLocker locker(&m_lastSemanticInfoLock);
            if (!m_lastSemanticInfo.doc)
                updateDocumentNow();
        } else {
            m_editorGCTimer->start(EditorHiddenGCTimeout);
        }
    }
}

void CppEditorSupport::releaseResources()
{
    snapshotUpdater()->releaseSnapshot();
    QMutexLocker semanticLocker(&m_lastSemanticInfoLock);
    m_lastSemanticInfo = SemanticInfo();
}

504 505 506 507 508
SemanticInfo::Source CppEditorSupport::currentSource(bool force)
{
    int line = 0, column = 0;
    m_textEditor->convertPosition(m_textEditor->editorWidget()->position(), &line, &column);

509
    const Snapshot snapshot = m_snapshotUpdater->snapshot();
510

511
    QByteArray code;
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
    if (force || m_lastSemanticInfo.revision != editorRevision())
        code = contents(); // get the source code only when needed.

    const unsigned revision = editorRevision();
    SemanticInfo::Source source(snapshot, fileName(), code, line, column, revision, force);
    return source;
}

void CppEditorSupport::recalculateSemanticInfoNow(const SemanticInfo::Source &source,
                                                  bool emitSignalWhenFinished,
                                                  TopLevelDeclarationProcessor *processor)
{
    SemanticInfo semanticInfo;

    {
        QMutexLocker locker(&m_lastSemanticInfoLock);
        semanticInfo.revision = m_lastSemanticInfo.revision;
        semanticInfo.forced = source.force;

        if (!source.force
                && m_lastSemanticInfo.revision == source.revision
                && m_lastSemanticInfo.doc
                && m_lastSemanticInfo.doc->translationUnit()->ast()
                && m_lastSemanticInfo.doc->fileName() == source.fileName) {
            semanticInfo.snapshot = m_lastSemanticInfo.snapshot; // ### TODO: use the new snapshot.
            semanticInfo.doc = m_lastSemanticInfo.doc;
        }
    }

    if (semanticInfo.doc.isNull()) {
        semanticInfo.snapshot = source.snapshot;
        if (source.snapshot.contains(source.fileName)) {
            Document::Ptr doc = source.snapshot.preprocessedDocument(source.code, source.fileName);
            if (processor)
                doc->control()->setTopLevelDeclarationProcessor(processor);
            doc->check();
            semanticInfo.doc = doc;
549 550
        } else {
            return;
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
        }
    }

    if (semanticInfo.doc) {
        TranslationUnit *translationUnit = semanticInfo.doc->translationUnit();
        AST * ast = translationUnit->ast();

        FunctionDefinitionUnderCursor functionDefinitionUnderCursor(semanticInfo.doc->translationUnit());
        DeclarationAST *currentFunctionDefinition = functionDefinitionUnderCursor(ast, source.line, source.column);

        const LocalSymbols useTable(semanticInfo.doc, currentFunctionDefinition);
        semanticInfo.revision = source.revision;
        semanticInfo.localUses = useTable.uses;
    }

    {
        QMutexLocker locker(&m_lastSemanticInfoLock);
        m_lastSemanticInfo = semanticInfo;
    }

    if (emitSignalWhenFinished)
        emit semanticInfoUpdated(semanticInfo);
}

void CppEditorSupport::recalculateSemanticInfoDetached_helper(QFutureInterface<void> &future, SemanticInfo::Source source)
{
    class TLDProc: public TopLevelDeclarationProcessor
    {
        QFutureInterface<void> m_theFuture;

    public:
        TLDProc(QFutureInterface<void> &aFuture): m_theFuture(aFuture) {}
        virtual ~TLDProc() {}
        virtual bool processDeclaration(DeclarationAST *ast) {
            Q_UNUSED(ast);
            return m_theFuture.isCanceled();
        }
    };

    TLDProc tldProc(future);
    recalculateSemanticInfoNow(source, true, &tldProc);
}
593 594 595 596 597 598 599 600 601 602 603 604 605 606

void CppEditorSupport::onMimeTypeChanged()
{
    m_highlighter.cancel();
    m_highlighter.waitForFinished();

    m_highlightingSupport.reset(m_modelManager->highlightingSupport(m_textEditor));

    disconnect(this, SIGNAL(semanticInfoUpdated(CppTools::SemanticInfo)),
               this, SLOT(startHighlighting()));
    if (m_highlightingSupport && m_highlightingSupport->requiresSemanticInfo())
        connect(this, SIGNAL(semanticInfoUpdated(CppTools::SemanticInfo)),
                this, SLOT(startHighlighting()));

607 608
    m_completionAssistProvider = m_modelManager->completionAssistProvider(m_textEditor);

609 610
    updateDocumentNow();
}
611 612 613 614 615 616 617 618 619 620 621 622 623

void CppEditorSupport::onAboutToReload()
{
    QTC_CHECK(!m_fileIsBeingReloaded);
    m_fileIsBeingReloaded = true;
}

void CppEditorSupport::onReloadFinished()
{
    QTC_CHECK(m_fileIsBeingReloaded);
    m_fileIsBeingReloaded = false;
    updateDocument();
}