Commit 6d8ecb76 authored by Roberto Raggi's avatar Roberto Raggi

Moved the semantic highlighter in a QFuture.

parent eca8693e
......@@ -38,8 +38,11 @@
#include <AST.h>
#include <SymbolVisitor.h>
#include <QCoreApplication>
#include <QDebug>
#include <QtCore/QCoreApplication>
#include <QtCore/QThreadPool>
#include <QtCore/QDebug>
#include <qtconcurrent/runextensions.h>
using namespace CPlusPlus;
......@@ -252,11 +255,17 @@ protected:
} // end of anonymous namespace
CheckUndefinedSymbols::CheckUndefinedSymbols(TranslationUnit *unit, const LookupContext &context)
: ASTVisitor(unit), _context(context)
CheckUndefinedSymbols::Future CheckUndefinedSymbols::go(Document::Ptr doc, const LookupContext &context)
{
Q_ASSERT(doc);
return QtConcurrent::run(&CheckUndefinedSymbols::runFunctor, new CheckUndefinedSymbols(doc, context));
}
CheckUndefinedSymbols::CheckUndefinedSymbols(Document::Ptr doc, const LookupContext &context)
: ASTVisitor(doc->translationUnit()), _doc(doc), _context(context), _future(0)
{
_fileName = context.thisDocument()->fileName();
CollectTypes collectTypes(context.thisDocument(), context.snapshot());
_fileName = doc->fileName();
CollectTypes collectTypes(doc, context.snapshot());
_potentialTypes = collectTypes.types();
_scopes = collectTypes.scopes();
}
......@@ -264,11 +273,13 @@ CheckUndefinedSymbols::CheckUndefinedSymbols(TranslationUnit *unit, const Lookup
CheckUndefinedSymbols::~CheckUndefinedSymbols()
{ }
QList<Document::DiagnosticMessage> CheckUndefinedSymbols::operator()(AST *ast)
void CheckUndefinedSymbols::runFunctor(QFutureInterface<Use> &future)
{
_future = &future;
_diagnosticMessages.clear();
accept(ast);
return _diagnosticMessages;
if (_doc->translationUnit())
accept(_doc->translationUnit()->ast());
}
bool CheckUndefinedSymbols::warning(unsigned line, unsigned column, const QString &text, unsigned length)
......@@ -291,6 +302,14 @@ bool CheckUndefinedSymbols::warning(AST *ast, const QString &text)
return false;
}
bool CheckUndefinedSymbols::preVisit(AST *)
{
if (_future->isCanceled())
return false;
return true;
}
bool CheckUndefinedSymbols::visit(NamespaceAST *ast)
{
if (ast->identifier_token) {
......@@ -299,7 +318,7 @@ bool CheckUndefinedSymbols::visit(NamespaceAST *ast)
unsigned line, column;
getTokenStartPosition(ast->identifier_token, &line, &column);
Use use(line, column, tok.length());
_typeUsages.append(use);
addTypeUsage(use);
}
}
......@@ -329,7 +348,7 @@ void CheckUndefinedSymbols::checkNamespace(NameAST *name)
unsigned line, column;
getTokenStartPosition(name->firstToken(), &line, &column);
Scope *enclosingScope = _context.thisDocument()->scopeAt(line, column);
Scope *enclosingScope = _doc->scopeAt(line, column);
if (ClassOrNamespace *b = _context.lookupType(name->name, enclosingScope)) {
foreach (Symbol *s, b->symbols()) {
if (s->isNamespace())
......@@ -443,6 +462,11 @@ void CheckUndefinedSymbols::endVisit(TemplateDeclarationAST *)
_templateDeclarationStack.takeFirst();
}
void CheckUndefinedSymbols::addTypeUsage(const Use &use)
{
_future->reportResult(use); // ### TODO: compress
}
void CheckUndefinedSymbols::addTypeUsage(ClassOrNamespace *b, NameAST *ast)
{
if (! b)
......@@ -459,8 +483,8 @@ void CheckUndefinedSymbols::addTypeUsage(ClassOrNamespace *b, NameAST *ast)
unsigned line, column;
getTokenStartPosition(startToken, &line, &column);
const unsigned length = tok.length();
Use use(line, column, length);
_typeUsages.append(use);
const Use use(line, column, length);
addTypeUsage(use);
//qDebug() << "added use" << oo(ast->name) << line << column << length;
}
......@@ -486,19 +510,14 @@ void CheckUndefinedSymbols::addTypeUsage(const QList<Symbol *> &candidates, Name
else if (c->isTypedef() || c->isNamespace() ||
c->isClass() || c->isEnum() ||
c->isForwardClassDeclaration() || c->isTypenameArgument()) {
Use use(line, column, length);
_typeUsages.append(use);
const Use use(line, column, length);
addTypeUsage(use);
//qDebug() << "added use" << oo(ast->name) << line << column << length;
break;
}
}
}
QList<CheckUndefinedSymbols::Use> CheckUndefinedSymbols::typeUsages() const
{
return _typeUsages;
}
unsigned CheckUndefinedSymbols::startOfTemplateDeclaration(TemplateDeclarationAST *ast) const
{
if (ast->declaration) {
......@@ -525,7 +544,7 @@ Scope *CheckUndefinedSymbols::findScope(AST *ast) const
}
if (! scope)
scope = _context.thisDocument()->globalSymbols();
scope = _doc->globalSymbols();
return scope;
}
......@@ -36,25 +36,29 @@
#include <cplusplus/LookupContext.h>
#include <ASTVisitor.h>
#include <QtCore/QSet>
#include <QtCore/QFuture>
#include <QtCore/QtConcurrentRun>
namespace CPlusPlus {
class CheckUndefinedSymbols: protected ASTVisitor
{
public:
CheckUndefinedSymbols(TranslationUnit *unit, const LookupContext &context);
virtual ~CheckUndefinedSymbols();
QList<Document::DiagnosticMessage> operator()(AST *ast);
typedef CppEditor::Internal::SemanticInfo::Use Use;
QList<Use> typeUsages() const;
void runFunctor(QFutureInterface<Use> &future);
typedef QFuture<Use> Future;
static Future go(Document::Ptr doc, const LookupContext &context);
protected:
using ASTVisitor::visit;
using ASTVisitor::endVisit;
CheckUndefinedSymbols(Document::Ptr doc, const LookupContext &context);
bool warning(unsigned line, unsigned column, const QString &text, unsigned length = 0);
bool warning(AST *ast, const QString &text);
......@@ -62,6 +66,9 @@ protected:
void checkNamespace(NameAST *name);
void addTypeUsage(ClassOrNamespace *b, NameAST *ast);
void addTypeUsage(const QList<Symbol *> &candidates, NameAST *ast);
void addTypeUsage(const Use &use);
virtual bool preVisit(AST *);
virtual bool visit(NamespaceAST *);
virtual bool visit(UsingDirectiveAST *);
......@@ -83,13 +90,14 @@ protected:
Scope *findScope(AST *ast) const;
private:
Document::Ptr _doc;
LookupContext _context;
QString _fileName;
QList<Document::DiagnosticMessage> _diagnosticMessages;
QSet<QByteArray> _potentialTypes;
QList<ScopedSymbol *> _scopes;
QList<Use> _typeUsages;
QList<TemplateDeclarationAST *> _templateDeclarationStack;
QFutureInterface<Use> *_future;
};
} // end of namespace CPlusPlus
......
......@@ -104,6 +104,72 @@ enum {
using namespace CPlusPlus;
using namespace CppEditor::Internal;
static QList<QTextEdit::ExtraSelection> createSelections(QTextDocument *document,
const QList<CPlusPlus::Document::DiagnosticMessage> &msgs,
const QTextCharFormat &format)
{
QList<QTextEdit::ExtraSelection> selections;
foreach (const Document::DiagnosticMessage &m, msgs) {
const int pos = document->findBlockByNumber(m.line() - 1).position() + m.column() - 1;
if (pos < 0)
continue;
QTextCursor cursor(document);
cursor.setPosition(pos);
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, m.length());
QTextEdit::ExtraSelection sel;
sel.cursor = cursor;
sel.format = format;
sel.format.setToolTip(m.text());
selections.append(sel);
}
return selections;
}
static QList<QTextEdit::ExtraSelection> createSelections(QTextDocument *document,
const QList<SemanticInfo::Use> &msgs,
const QTextCharFormat &format)
{
QList<QTextEdit::ExtraSelection> selections;
QTextBlock currentBlock = document->firstBlock();
unsigned currentLine = 1;
foreach (const SemanticInfo::Use &use, msgs) {
QTextCursor cursor(document);
if (currentLine != use.line) {
int delta = use.line - currentLine;
if (delta >= 0) {
while (delta--)
currentBlock = currentBlock.next();
} else {
currentBlock = document->findBlockByNumber(use.line - 1);
}
currentLine = use.line;
}
const int pos = currentBlock.position() + use.column - 1;
if (pos < 0)
continue;
cursor.setPosition(pos);
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, use.length);
QTextEdit::ExtraSelection sel;
sel.cursor = cursor;
sel.format = format;
selections.append(sel);
}
return selections;
}
namespace {
class OverviewTreeView : public QTreeView
......@@ -550,6 +616,9 @@ CPPEditor::CPPEditor(QWidget *parent)
connect(m_modelManager, SIGNAL(documentUpdated(CPlusPlus::Document::Ptr)),
this, SLOT(onDocumentUpdated(CPlusPlus::Document::Ptr)));
}
m_highlighteRevision = 0;
connect(&m_highlightWatcher, SIGNAL(finished()), SLOT(highlightTypeUsages()));
}
CPPEditor::~CPPEditor()
......@@ -834,10 +903,11 @@ void CPPEditor::markSymbols(Symbol *canonicalSymbol, const SemanticInfo &info)
QList<QTextEdit::ExtraSelection> selections;
if (canonicalSymbol) {
if (info.doc && canonicalSymbol) {
TranslationUnit *unit = info.doc->translationUnit();
const QList<int> references = m_modelManager->references(canonicalSymbol, info.context);
LookupContext context(info.doc, info.snapshot);
const QList<int> references = m_modelManager->references(canonicalSymbol, context);
foreach (int index, references) {
unsigned line, column;
unit->getTokenPosition(index, &line, &column);
......@@ -1027,6 +1097,7 @@ void CPPEditor::updateMethodBoxToolTip()
void CPPEditor::updateUses()
{
m_updateUsesTimer->start();
m_highlighter.cancel();
}
void CPPEditor::updateUsesNow()
......@@ -1037,6 +1108,18 @@ void CPPEditor::updateUsesNow()
semanticRehighlight();
}
void CPPEditor::highlightTypeUsages()
{
if (editorRevision() != m_highlighteRevision)
return; // outdated
else if (m_highlighter.isCanceled())
return; // aborted
const QList<SemanticInfo::Use> typeUsages = m_highlighter.results();
setExtraSelections(TypeSelection, createSelections(document(), typeUsages, m_typeFormat));
}
void CPPEditor::switchDeclarationDefinition()
{
if (! m_modelManager)
......@@ -1725,64 +1808,6 @@ void CPPEditor::semanticRehighlight()
m_semanticHighlighter->rehighlight(currentSource());
}
static QList<QTextEdit::ExtraSelection> createSelections(QTextDocument *document,
const QList<CPlusPlus::Document::DiagnosticMessage> &msgs,
const QTextCharFormat &format)
{
QList<QTextEdit::ExtraSelection> selections;
foreach (const Document::DiagnosticMessage &m, msgs) {
QTextCursor cursor(document);
cursor.setPosition(document->findBlockByNumber(m.line() - 1).position() + m.column() - 1);
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, m.length());
QTextEdit::ExtraSelection sel;
sel.cursor = cursor;
sel.format = format;
sel.format.setToolTip(m.text());
selections.append(sel);
}
return selections;
}
static QList<QTextEdit::ExtraSelection> createSelections(QTextDocument *document,
const QList<SemanticInfo::Use> &msgs,
const QTextCharFormat &format)
{
QList<QTextEdit::ExtraSelection> selections;
QTextBlock currentBlock = document->firstBlock();
unsigned currentLine = 1;
foreach (const SemanticInfo::Use &use, msgs) {
QTextCursor cursor(document);
if (currentLine != use.line) {
int delta = use.line - currentLine;
if (delta >= 0) {
while (delta--)
currentBlock = currentBlock.next();
} else {
currentBlock = document->findBlockByNumber(use.line - 1);
}
currentLine = use.line;
}
cursor.setPosition(currentBlock.position() + use.column - 1);
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, use.length);
QTextEdit::ExtraSelection sel;
sel.cursor = cursor;
sel.format = format;
selections.append(sel);
}
return selections;
}
void CPPEditor::updateSemanticInfo(const SemanticInfo &semanticInfo)
{
if (semanticInfo.revision != editorRevision()) {
......@@ -1828,16 +1853,26 @@ void CPPEditor::updateSemanticInfo(const SemanticInfo &semanticInfo)
QTextCharFormat diagnosticMessageFormat;
diagnosticMessageFormat.setUnderlineColor(Qt::darkYellow); // ### hardcoded
diagnosticMessageFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline); // ### hardcoded
setExtraSelections(UndefinedSymbolSelection, createSelections(document(),
semanticInfo.diagnosticMessages,
diagnosticMessageFormat));
setExtraSelections(TypeSelection, createSelections(document(),
semanticInfo.typeUsages,
m_typeFormat));
m_highlighter.cancel();
if (semanticInfo.doc) {
LookupContext context(semanticInfo.doc, semanticInfo.snapshot);
CheckUndefinedSymbols::Future f = CheckUndefinedSymbols::go(semanticInfo.doc, context);
m_highlighter = f;
m_highlighteRevision = semanticInfo.revision;
m_highlightWatcher.setFuture(m_highlighter);
}
#if 0 // ### TODO: enable objc semantic highlighting
setExtraSelections(ObjCSelection, createSelections(document(),
semanticInfo.objcKeywords,
m_keywordFormat));
#endif
}
setExtraSelections(UnusedSymbolSelection, unusedSelections);
......@@ -2044,9 +2079,7 @@ SemanticInfo SemanticHighlighter::semanticInfo(const Source &source)
snapshot = m_lastSemanticInfo.snapshot; // ### TODO: use the new snapshot.
doc = m_lastSemanticInfo.doc;
diagnosticMessages = m_lastSemanticInfo.diagnosticMessages;
typeUsages = m_lastSemanticInfo.typeUsages;
objcKeywords = m_lastSemanticInfo.objcKeywords;
context = m_lastSemanticInfo.context;
m_mutex.unlock();
}
......@@ -2057,6 +2090,7 @@ SemanticInfo SemanticHighlighter::semanticInfo(const Source &source)
doc = snapshot.documentFromSource(preprocessedCode, source.fileName);
doc->check();
#if 0
context = LookupContext(doc, snapshot);
if (TranslationUnit *unit = doc->translationUnit()) {
......@@ -2067,6 +2101,7 @@ SemanticInfo SemanticHighlighter::semanticInfo(const Source &source)
FindObjCKeywords findObjCKeywords(unit); // ### remove me
objcKeywords = findObjCKeywords();
}
#endif
}
TranslationUnit *translationUnit = doc->translationUnit();
......@@ -2087,9 +2122,7 @@ SemanticInfo SemanticHighlighter::semanticInfo(const Source &source)
semanticInfo.hasD = useTable.hasD;
semanticInfo.forced = source.force;
semanticInfo.diagnosticMessages = diagnosticMessages;
semanticInfo.typeUsages = typeUsages;
semanticInfo.objcKeywords = objcKeywords;
semanticInfo.context = context;
return semanticInfo;
}
......@@ -41,6 +41,7 @@
#include <QtCore/QThread>
#include <QtCore/QMutex>
#include <QtCore/QWaitCondition>
#include <QtCore/QFutureWatcher>
QT_BEGIN_NAMESPACE
class QComboBox;
......@@ -224,6 +225,7 @@ private Q_SLOTS:
void semanticRehighlight();
void updateSemanticInfo(const CppEditor::Internal::SemanticInfo &semanticInfo);
void highlightTypeUsages();
void performQuickFix(int index);
......@@ -282,6 +284,10 @@ private:
QList<TextEditor::QuickFixOperation::Ptr> m_quickFixes;
bool m_objcEnabled;
bool m_initialized;
QFuture<SemanticInfo::Use> m_highlighter;
QFutureWatcher<SemanticInfo::Use> m_highlightWatcher;
unsigned m_highlighteRevision; // the editor revision that requested the highlight
};
......
......@@ -66,6 +66,7 @@ class CppQuickFixState: public TextEditor::QuickFixState
{
public:
QList<CPlusPlus::AST *> path;
Snapshot snapshot;
SemanticInfo info;
};
......@@ -1236,7 +1237,7 @@ int CppQuickFixOperation::match(TextEditor::QuickFixState *state)
_document = s->info.doc;
if (_refactoringChanges)
delete _refactoringChanges;
_refactoringChanges = new CppRefactoringChanges(s->info.snapshot);
_refactoringChanges = new CppRefactoringChanges(s->snapshot);
return match(s->path);
}
......@@ -1377,6 +1378,7 @@ TextEditor::QuickFixState *CppQuickFixCollector::initializeCompletion(TextEditor
CppQuickFixState *state = new CppQuickFixState;
state->path = path;
state->info = info;
state->snapshot = CppTools::CppModelManagerInterface::instance()->snapshot();
return state;
}
}
......
......@@ -60,11 +60,9 @@ public:
bool hasQ: 1;
bool hasD: 1;
bool forced: 1;
CPlusPlus::Snapshot snapshot; // ### remove
CPlusPlus::Document::Ptr doc; // ### remove
CPlusPlus::LookupContext context;
LocalUseMap localUses; // ### rename
QList<Use> typeUsages;
CPlusPlus::Snapshot snapshot;
CPlusPlus::Document::Ptr doc;
LocalUseMap localUses;
QList<Use> objcKeywords;
QList<CPlusPlus::Document::DiagnosticMessage> diagnosticMessages;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment