Commit 0c27b276 authored by Erik Verbruggen's avatar Erik Verbruggen Committed by Nikolai Kosjar

C++ Detach the CppEditor from code-model internals.

- Moved document update handling into CppTools.
- Moved semantic info calculation into CppTools.
- Moved semantic highlighting into CppTools.

Change-Id: I253861bf074a64b1f657f7a4a8e6583871b5285f
Reviewed-by: default avatarNikolai Kosjar <>
parent e8d59fb7
This diff is collapsed.
......@@ -69,75 +69,6 @@ namespace Internal {
class CPPEditorWidget;
class SemanticHighlighter: public QThread, CPlusPlus::TopLevelDeclarationProcessor
SemanticHighlighter(QObject *parent = 0);
virtual ~SemanticHighlighter();
virtual bool processDeclaration(CPlusPlus::DeclarationAST *) { return m_done; }
void abort();
struct Source
CPlusPlus::Snapshot snapshot;
QString fileName;
QString code;
int line;
int column;
unsigned revision;
bool force;
: line(0), column(0), revision(0), force(false)
{ }
Source(const CPlusPlus::Snapshot &snapshot,
const QString &fileName,
const QString &code,
int line, int column,
unsigned revision)
: snapshot(snapshot), fileName(fileName),
code(code), line(line), column(column),
revision(revision), force(false)
{ }
void clear()
snapshot = CPlusPlus::Snapshot();
line = 0;
column = 0;
revision = 0;
force = false;
CppTools::SemanticInfo semanticInfo(const Source &source);
void rehighlight(const Source &source);
void changed(const CppTools::SemanticInfo &semanticInfo);
virtual void run();
bool isOutdated();
QMutex m_mutex;
QWaitCondition m_condition;
bool m_done;
Source m_source;
CppTools::SemanticInfo m_lastSemanticInfo;
class CPPEditor : public TextEditor::BaseTextEditor
......@@ -210,6 +141,7 @@ public Q_SLOTS:
void findUsages();
void renameUsagesNow(const QString &replacement = QString());
void semanticRehighlight(bool force = false);
void highlighterStarted(QFuture<TextEditor::HighlightingResult> highlighter, unsigned revision);
bool event(QEvent *e);
......@@ -235,7 +167,7 @@ private Q_SLOTS:
void updateFunctionDeclDefLink();
void updateFunctionDeclDefLinkNow();
void onFunctionDeclDefLinkFound(QSharedPointer<FunctionDeclDefLink> link);
void onDocumentUpdated(CPlusPlus::Document::Ptr doc);
void onDocumentUpdated();
void onContentsChanged(int position, int charsRemoved, int charsAdded);
void updateSemanticInfo(const CppTools::SemanticInfo &semanticInfo);
......@@ -258,8 +190,6 @@ private:
TextEditor::ITextEditor *openCppEditorAt(const QString &fileName, int line,
int column = 0);
SemanticHighlighter::Source currentSource(bool force = false);
void highlightUses(const QList<TextEditor::HighlightingResult> &uses,
QList<QTextEdit::ExtraSelection> *selections);
......@@ -310,11 +240,9 @@ private:
QTextCursor m_currentRenameSelectionBegin;
QTextCursor m_currentRenameSelectionEnd;
SemanticHighlighter *m_semanticHighlighter;
CppTools::SemanticInfo m_lastSemanticInfo;
QList<TextEditor::QuickFixOperation::Ptr> m_quickFixes;
bool m_objcEnabled;
bool m_initialized;
QFuture<TextEditor::HighlightingResult> m_highlighter;
QFutureWatcher<TextEditor::HighlightingResult> m_highlightWatcher;
......@@ -331,7 +259,6 @@ private:
CppTools::CommentsSettings m_commentsSettings;
CppTools::CppCompletionSupport *m_completionSupport;
CppTools::CppHighlightingSupport *m_highlightingSupport;
......@@ -64,6 +64,10 @@ public:
CppHighlightingSupport(TextEditor::ITextEditor *editor);
virtual ~CppHighlightingSupport() = 0;
virtual bool requiresSemanticInfo() const = 0;
virtual bool hightlighterHandlesDiagnostics() const = 0;
virtual QFuture<TextEditor::HighlightingResult> highlightingFuture(
const CPlusPlus::Document::Ptr &doc,
const CPlusPlus::Snapshot &snapshot) const = 0;
......@@ -82,8 +86,6 @@ public:
virtual ~CppHighlightingSupportFactory() = 0;
virtual CppHighlightingSupport *highlightingSupport(TextEditor::ITextEditor *editor) = 0;
virtual bool hightlighterHandlesDiagnostics() const = 0;
} // namespace CppTools
......@@ -43,6 +43,12 @@ public:
CppHighlightingSupportInternal(TextEditor::ITextEditor *editor);
virtual ~CppHighlightingSupportInternal();
virtual bool requiresSemanticInfo() const
{ return true; }
virtual bool hightlighterHandlesDiagnostics() const
{ return false; }
virtual QFuture<TextEditor::HighlightingResult> highlightingFuture(
const CPlusPlus::Document::Ptr &doc,
const CPlusPlus::Snapshot &snapshot) const;
......@@ -54,9 +60,6 @@ public:
virtual ~CppHighlightingSupportInternalFactory();
virtual CppHighlightingSupport *highlightingSupport(TextEditor::ITextEditor *editor);
virtual bool hightlighterHandlesDiagnostics() const
{ return false; }
} // namespace Internal
This diff is collapsed.
......@@ -59,11 +59,11 @@ namespace CPlusPlus { class ParseManager; }
namespace CppTools {
class CppCompletionSupportFactory;
class CppEditorSupport;
class CppHighlightingSupportFactory;
namespace Internal {
class CppEditorSupport;
class CppPreprocessor;
class CppFindReferences;
......@@ -95,16 +95,11 @@ public:
virtual bool isCppEditor(Core::IEditor *editor) const;
CppEditorSupport *editorSupport(TextEditor::ITextEditor *editor) const
{ return m_editorSupport.value(editor); }
void emitDocumentUpdated(CPlusPlus::Document::Ptr doc);
void stopEditorSelectionsUpdate()
{ m_updateEditorSelectionsTimer->stop(); }
virtual void addEditorSupport(AbstractEditorSupport *editorSupport);
virtual void removeEditorSupport(AbstractEditorSupport *editorSupport);
virtual CppEditorSupport *cppEditorSupport(TextEditor::BaseTextEditor *editor);
virtual QList<int> references(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context);
......@@ -115,10 +110,8 @@ public:
virtual void findMacroUsages(const CPlusPlus::Macro &macro);
virtual void renameMacroUsages(const CPlusPlus::Macro &macro, const QString &replacement);
virtual void setExtraDiagnostics(const QString &fileName, int key,
virtual void setExtraDiagnostics(const QString &fileName, const QString &key,
const QList<Document::DiagnosticMessage> &diagnostics);
virtual QList<Document::DiagnosticMessage> extraDiagnostics(
const QString &fileName, int key = AllExtraDiagnostics) const;
void finishedRefreshingSourceFiles(const QStringList &files);
......@@ -161,24 +154,17 @@ Q_SIGNALS:
void aboutToRemoveFiles(const QStringList &files);
public Q_SLOTS:
void editorOpened(Core::IEditor *editor);
void editorAboutToClose(Core::IEditor *editor);
virtual void updateModifiedSourceFiles();
private Q_SLOTS:
// this should be executed in the GUI thread.
void onDocumentUpdated(CPlusPlus::Document::Ptr doc);
void onExtraDiagnosticsUpdated(const QString &fileName);
void onAboutToRemoveProject(ProjectExplorer::Project *project);
void onAboutToUnloadSession();
void onCoreAboutToClose();
void onProjectAdded(ProjectExplorer::Project *project);
void postEditorUpdate();
void updateEditorSelections();
void updateEditor(Document::Ptr doc);
void replaceSnapshot(const CPlusPlus::Snapshot &newSnapshot);
WorkingCopy buildWorkingCopyList();
......@@ -206,7 +192,8 @@ private:
QByteArray m_definedMacros;
// editor integration
QMap<TextEditor::ITextEditor *, CppEditorSupport *> m_editorSupport;
mutable QMutex m_editorSupportMutex;
QMap<TextEditor::BaseTextEditor *, CppEditorSupport *> m_editorSupport;
QSet<AbstractEditorSupport *> m_addtionalEditorSupport;
......@@ -216,28 +203,9 @@ private:
mutable QMutex m_mutex;
mutable QMutex m_protectSnapshot;
struct Editor {
: revision(-1)
, updateSelections(true)
int revision;
bool updateSelections;
QPointer<TextEditor::ITextEditor> textEditor;
QList<QTextEdit::ExtraSelection> selections;
QList<TextEditor::BaseTextEditorWidget::BlockRange> ifdefedOutBlocks;
QList<Editor> m_todo;
QTimer *m_updateEditorSelectionsTimer;
CppFindReferences *m_findReferences;
bool m_indexerEnabled;
mutable QMutex m_protectExtraDiagnostics;
QHash<QString, QHash<int, QList<Document::DiagnosticMessage> > > m_extraDiagnostics;
QMap<QString, QList<CppTools::ProjectPart::Ptr> > m_srcToProjectPart;
CppCompletionAssistProvider *m_completionAssistProvider;
......@@ -44,11 +44,13 @@
namespace Core { class IEditor; }
namespace CPlusPlus { class LookupContext; }
namespace ProjectExplorer { class Project; }
namespace TextEditor { class BaseTextEditor; }
namespace CppTools {
class AbstractEditorSupport;
class CppCompletionSupport;
class CppCompletionAssistProvider;
class CppEditorSupport;
class CppHighlightingSupport;
class CppHighlightingSupportFactory;
class CppIndexingSupport;
......@@ -187,13 +189,6 @@ public:
Table _elements;
enum ExtraDiagnosticKind
AllExtraDiagnostics = -1,
static const QString configurationFileName();
......@@ -215,6 +210,7 @@ public:
virtual void addEditorSupport(CppTools::AbstractEditorSupport *editorSupport) = 0;
virtual void removeEditorSupport(CppTools::AbstractEditorSupport *editorSupport) = 0;
virtual CppEditorSupport *cppEditorSupport(TextEditor::BaseTextEditor *editor) = 0;
virtual QList<int> references(CPlusPlus::Symbol *symbol,
const CPlusPlus::LookupContext &context) = 0;
......@@ -226,10 +222,8 @@ public:
virtual void renameMacroUsages(const CPlusPlus::Macro &macro, const QString &replacement = QString()) = 0;
virtual void findMacroUsages(const CPlusPlus::Macro &macro) = 0;
virtual void setExtraDiagnostics(const QString &fileName, int key,
virtual void setExtraDiagnostics(const QString &fileName, const QString &kind,
const QList<CPlusPlus::Document::DiagnosticMessage> &diagnostics) = 0;
virtual QList<CPlusPlus::Document::DiagnosticMessage> extraDiagnostics(
const QString &fileName, int key = AllExtraDiagnostics) const = 0;
virtual CppTools::CppCompletionSupport *completionSupport(Core::IEditor *editor) const = 0;
virtual void setCppCompletionAssistProvider(CppTools::CppCompletionAssistProvider *completionAssistProvider) = 0;
......@@ -243,7 +237,6 @@ public:
void documentUpdated(CPlusPlus::Document::Ptr doc);
void sourceFilesRefreshed(const QStringList &files);
void extraDiagnosticsUpdated(QString fileName);
/// \brief Emitted after updateProjectInfo method is called on the model-manager.
......@@ -42,6 +42,33 @@ namespace CppTools {
class CPPTOOLS_EXPORT SemanticInfo
struct Source
const CPlusPlus::Snapshot snapshot;
const QString fileName;
const QString code;
const int line;
const int column;
const unsigned revision;
const bool force;
: line(0), column(0), revision(0), force(false)
{ }
Source(const CPlusPlus::Snapshot &snapshot,
const QString &fileName,
const QString &code,
int line, int column,
unsigned revision,
bool force)
: snapshot(snapshot), fileName(fileName),
code(code), line(line), column(column),
revision(revision), force(force)
{ }
typedef TextEditor::HighlightingResult Use;
......@@ -30,63 +30,154 @@
#include "cpphighlightingsupport.h"
#include "cppmodelmanager.h"
#include "cppsemanticinfo.h"
#include <cplusplus/CppDocument.h>
#include <QFuture>
#include <QObject>
#include <QPointer>
#include <QFuture>
class QTimer;
#include <QTimer>
namespace CPlusPlus { class AST; }
namespace TextEditor {
class ITextEditor;
class BaseTextEditor;
class ITextMark;
} // namespace TextEditor
namespace CppTools {
namespace Internal {
class CppModelManager;
class CppEditorSupport: public QObject
* \brief The CppEditorSupport class oversees the actions that happen when a C++ text editor updates
* its document.
* The following steps are taken:
* 1. the text editor fires a contentsChanged() signal that triggers updateDocument
* 2. update document will start a timer, or reset the timer if it was already running. This way
* subsequent updates (e.g. keypresses) get bunched together instead of running the subsequent
* actions for every key press
* 3. when the timer from step 2 fires, updateDocumentNow() is triggered. That tells the
* model-manager to update the CPlusPlus::Document by re-indexing it.
* 4. when the model-manager finishes, it fires a documentUpdated(CPlusPlus::Document::Ptr) signal,
* that is connected to onDocumentUpdated(CPlusPlus::Document::Ptr), which does 4 things:
* a) updates the ifdeffed-out blocks in the EditorUpdate
* b) calls setExtraDiagnostics with the diagnostics from the parser, which in turn calls
* onDiagnosticsChanged on the UI thread, and that schedules an editor update timer. When this
* timer fires, updateEditorNow() is called, which will apply the updates to the editor.
* c) a semantic-info recalculation is started in a future
* d) the documentUpdated() signal is emitted, which can be used by a widget to do things
* 5. semantic-info calculation from 4c is done by a future that calls recalculateSemanticInfoNow(),
* which emits semanticInfoUpdated() when it is finished. Editors can also listen in on this
* signal to do things like highlighting the local usages.
* 6. the semanticInfoUpdated() is connected to the startHighlighting() slot, which will start
* another future for doing the semantic highlighting. The highlighterStarted signal is emitted,
* with the highlighting future as a parameter, so editors can hook it up to a QFutureWatcher
* and get notifications.
* Both the semantic info calculation and the highlighting calculation will cancel an already running
* future. They will also check that the result of a previous step is not already outdated, meaning
* that they check the revision of the editor document to see if a user changed the document while
* the calculation was running.
class CPPTOOLS_EXPORT CppEditorSupport: public QObject
CppEditorSupport(CppModelManager *modelManager);
CppEditorSupport(Internal::CppModelManager *modelManager, TextEditor::BaseTextEditor *textEditor);
virtual ~CppEditorSupport();
TextEditor::ITextEditor *textEditor() const;
void setTextEditor(TextEditor::ITextEditor *textEditor);
int updateDocumentInterval() const;
void setUpdateDocumentInterval(int updateDocumentInterval);
QString fileName() const;
QString contents();
QString contents() const;
unsigned editorRevision() const;
void contentsChanged();
void setExtraDiagnostics(const QString &key,
const QList<CPlusPlus::Document::DiagnosticMessage> &messages);
/// Retrieve the semantic info, which will get recalculated on the current
/// thread if it is outdate.
SemanticInfo recalculateSemanticInfo(bool emitSignalWhenFinished = true);
/// Recalculates the semantic info in a future, and will emit the semanticInfoUpdated() signal
/// when finished.
/// \param force do not check if the old semantic info is still valid
void recalculateSemanticInfoDetached(bool force = false);
private Q_SLOTS:
void documentUpdated();
void diagnosticsChanged();
void semanticInfoUpdated(CppTools::SemanticInfo);
void highlighterStarted(QFuture<TextEditor::HighlightingResult>, unsigned revision);
private slots:
void updateDocument();
void updateDocumentNow();
void onDocumentUpdated(CPlusPlus::Document::Ptr doc);
void startHighlighting();
void onDiagnosticsChanged();
void updateEditor();
void updateEditorNow();
typedef TextEditor::BaseTextEditorWidget::BlockRange BlockRange;
struct EditorUpdates {
: revision(-1)
int revision;
QList<QTextEdit::ExtraSelection> selections;
QList<BlockRange> ifdefedOutBlocks;
enum {
UpdateDocumentDefaultInterval = 150,
UpdateEditorInterval = 300
SemanticInfo::Source currentSource(bool force);
void recalculateSemanticInfoNow(const SemanticInfo::Source &source, bool emitSignalWhenFinished,
CPlusPlus::TopLevelDeclarationProcessor *processor = 0);
void recalculateSemanticInfoDetached_helper(QFutureInterface<void> &future,
SemanticInfo::Source source);
CppModelManager *_modelManager;
QPointer<TextEditor::ITextEditor> _textEditor;
QTimer *_updateDocumentTimer;
int _updateDocumentInterval;
unsigned _revision;
QFuture<void> _documentParser;
QString _cachedContents;
Internal::CppModelManager *m_modelManager;
QPointer<TextEditor::BaseTextEditor> m_textEditor;
QTimer *m_updateDocumentTimer;
int m_updateDocumentInterval;
unsigned m_revision;
QFuture<void> m_documentParser;
// content caching
mutable QString m_cachedContents;
mutable int m_cachedContentsEditorRevision;
QTimer *m_updateEditorTimer;
EditorUpdates m_editorUpdates;
QMutex m_diagnosticsMutex;
QHash<QString, QList<CPlusPlus::Document::DiagnosticMessage> > m_allDiagnostics;
// Semantic info:
bool m_initialized;
mutable QMutex m_lastSemanticInfoLock;
SemanticInfo m_lastSemanticInfo;
QFuture<void> m_futureSemanticInfo;
// Highlighting:
unsigned m_lastHighlightRevision;
QFuture<TextEditor::HighlightingResult> m_highlighter;
QScopedPointer<CppTools::CppHighlightingSupport> m_highlightingSupport;
} // namespace Internal
} // namespace CppTools
......@@ -703,9 +703,9 @@ void FindExportedCppTypes::operator()(const CPlusPlus::Document::Ptr &document)
FindExportsVisitor finder(document);
if (CppTools::CppModelManagerInterface *cppModelManager = CppTools::CppModelManagerInterface::instance()) {
document->fileName(), CppTools::CppModelManagerInterface::ExportedQmlTypesDiagnostic,
static const QString kindKey = QLatin1String("QmlJSTools.ExportedQmlTypesDiagnostic");
cppModelManager->setExtraDiagnostics(document->fileName(), kindKey,
// if nothing was found, done
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment