diff --git a/src/plugins/cppeditor/cppcheckundefinedsymbols.cpp b/src/plugins/cppeditor/cppcheckundefinedsymbols.cpp index d5f8e3337aa..bf3f3dfdd9b 100644 --- a/src/plugins/cppeditor/cppcheckundefinedsymbols.cpp +++ b/src/plugins/cppeditor/cppcheckundefinedsymbols.cpp @@ -38,8 +38,11 @@ #include #include -#include -#include +#include +#include +#include + +#include 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) { - _fileName = context.thisDocument()->fileName(); - CollectTypes collectTypes(context.thisDocument(), context.snapshot()); + 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 = 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 CheckUndefinedSymbols::operator()(AST *ast) +void CheckUndefinedSymbols::runFunctor(QFutureInterface &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 &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::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; } diff --git a/src/plugins/cppeditor/cppcheckundefinedsymbols.h b/src/plugins/cppeditor/cppcheckundefinedsymbols.h index 6788dd4284d..f331efdc96c 100644 --- a/src/plugins/cppeditor/cppcheckundefinedsymbols.h +++ b/src/plugins/cppeditor/cppcheckundefinedsymbols.h @@ -36,25 +36,29 @@ #include #include #include +#include +#include namespace CPlusPlus { class CheckUndefinedSymbols: protected ASTVisitor { public: - CheckUndefinedSymbols(TranslationUnit *unit, const LookupContext &context); virtual ~CheckUndefinedSymbols(); - QList operator()(AST *ast); - typedef CppEditor::Internal::SemanticInfo::Use Use; - QList typeUsages() const; + void runFunctor(QFutureInterface &future); + + typedef QFuture 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 &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 _diagnosticMessages; QSet _potentialTypes; QList _scopes; - QList _typeUsages; QList _templateDeclarationStack; + QFutureInterface *_future; }; } // end of namespace CPlusPlus diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index 5838f742516..600ff99abdc 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -104,6 +104,72 @@ enum { using namespace CPlusPlus; using namespace CppEditor::Internal; +static QList createSelections(QTextDocument *document, + const QList &msgs, + const QTextCharFormat &format) +{ + QList 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 createSelections(QTextDocument *document, + const QList &msgs, + const QTextCharFormat &format) +{ + QList 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 selections; - if (canonicalSymbol) { + if (info.doc && canonicalSymbol) { TranslationUnit *unit = info.doc->translationUnit(); - const QList references = m_modelManager->references(canonicalSymbol, info.context); + LookupContext context(info.doc, info.snapshot); + const QList 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 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 createSelections(QTextDocument *document, - const QList &msgs, - const QTextCharFormat &format) -{ - QList 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 createSelections(QTextDocument *document, - const QList &msgs, - const QTextCharFormat &format) -{ - QList 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; } diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h index abe4e39b072..a6b991b81ce 100644 --- a/src/plugins/cppeditor/cppeditor.h +++ b/src/plugins/cppeditor/cppeditor.h @@ -41,6 +41,7 @@ #include #include #include +#include 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 m_quickFixes; bool m_objcEnabled; bool m_initialized; + + QFuture m_highlighter; + QFutureWatcher m_highlightWatcher; + unsigned m_highlighteRevision; // the editor revision that requested the highlight }; diff --git a/src/plugins/cppeditor/cppquickfix.cpp b/src/plugins/cppeditor/cppquickfix.cpp index 7531d23bbbc..5ad8e5f1faf 100644 --- a/src/plugins/cppeditor/cppquickfix.cpp +++ b/src/plugins/cppeditor/cppquickfix.cpp @@ -66,6 +66,7 @@ class CppQuickFixState: public TextEditor::QuickFixState { public: QList 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; } } diff --git a/src/plugins/cppeditor/cppsemanticinfo.h b/src/plugins/cppeditor/cppsemanticinfo.h index f57f7655c89..7f374c8ffd7 100644 --- a/src/plugins/cppeditor/cppsemanticinfo.h +++ b/src/plugins/cppeditor/cppsemanticinfo.h @@ -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 typeUsages; + CPlusPlus::Snapshot snapshot; + CPlusPlus::Document::Ptr doc; + LocalUseMap localUses; QList objcKeywords; QList diagnosticMessages; };