diff options
Diffstat (limited to 'src')
70 files changed, 2787 insertions, 1098 deletions
diff --git a/src/plugins/clangcodemodel/clangcodemodel.pro b/src/plugins/clangcodemodel/clangcodemodel.pro index 28b111b42e..ebbb29c8e4 100644 --- a/src/plugins/clangcodemodel/clangcodemodel.pro +++ b/src/plugins/clangcodemodel/clangcodemodel.pro @@ -17,18 +17,14 @@ contains(DEFINES, CLANG_COMPLETION) { } contains(DEFINES, CLANG_HIGHLIGHTING) { - HEADERS += cppcreatemarkers.h clanghighlightingsupport.h - SOURCES += cppcreatemarkers.cpp clanghighlightingsupport.cpp + HEADERS += cppcreatemarkers.h + SOURCES += cppcreatemarkers.cpp } -HEADERS += clangutils.h \ - cxprettyprinter.h - -SOURCES += clangutils.cpp \ - cxprettyprinter.cpp - SOURCES += \ $$PWD/clangcodemodelplugin.cpp \ + $$PWD/clangeditordocumentparser.cpp \ + $$PWD/clangeditordocumentprocessor.cpp \ $$PWD/sourcemarker.cpp \ $$PWD/symbol.cpp \ $$PWD/sourcelocation.cpp \ @@ -48,6 +44,8 @@ SOURCES += \ HEADERS += \ $$PWD/clangcodemodelplugin.h \ + $$PWD/clangeditordocumentparser.h \ + $$PWD/clangeditordocumentprocessor.h \ $$PWD/clang_global.h \ $$PWD/sourcemarker.h \ $$PWD/constants.h \ @@ -68,6 +66,12 @@ HEADERS += \ $$PWD/raii/scopedclangoptions.h \ $$PWD/clangmodelmanagersupport.h +HEADERS += clangutils.h \ + cxprettyprinter.h + +SOURCES += clangutils.cpp \ + cxprettyprinter.cpp + contains(DEFINES, CLANG_INDEXING) { HEADERS += \ $$PWD/clangindexer.h \ diff --git a/src/plugins/clangcodemodel/clangcodemodel.qbs b/src/plugins/clangcodemodel/clangcodemodel.qbs index 499f2e0492..1da1f421d6 100644 --- a/src/plugins/clangcodemodel/clangcodemodel.qbs +++ b/src/plugins/clangcodemodel/clangcodemodel.qbs @@ -94,8 +94,6 @@ QtcPlugin { name: "Highlighting support" condition: product.clangHighlighting files: [ - "clanghighlightingsupport.cpp", - "clanghighlightingsupport.h", "cppcreatemarkers.cpp", "cppcreatemarkers.h", ] @@ -156,6 +154,10 @@ QtcPlugin { files: [ "clang_global.h", + "clangeditordocumentparser.cpp", + "clangeditordocumentparser.h", + "clangeditordocumentprocessor.cpp", + "clangeditordocumentprocessor.h", "clangmodelmanagersupport.cpp", "clangmodelmanagersupport.h", "clangcodemodelplugin.cpp", diff --git a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp index f6297b84a5..57e94003c2 100644 --- a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp +++ b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp @@ -29,7 +29,6 @@ #include "clangcodemodelplugin.h" #include "clangprojectsettingspropertiespage.h" -#include "fastindexer.h" #include "pchmanager.h" #include "utils.h" @@ -65,11 +64,9 @@ bool ClangCodeModelPlugin::initialize(const QStringList &arguments, QString *err ClangCodeModel::Internal::initializeClang(); PchManager *pchManager = new PchManager(this); - FastIndexer *fastIndexer = 0; #ifdef CLANG_INDEXING m_indexer.reset(new ClangIndexer); - fastIndexer = m_indexer.data(); CppTools::CppModelManagerInterface::instance()->setIndexingSupport(m_indexer->indexingSupport()); #endif // CLANG_INDEXING @@ -80,7 +77,7 @@ bool ClangCodeModelPlugin::initialize(const QStringList &arguments, QString *err connect(CppTools::CppModelManagerInterface::instance(), SIGNAL(projectPartsUpdated(ProjectExplorer::Project*)), pchManager, SLOT(onProjectPartsUpdated(ProjectExplorer::Project*))); - m_modelManagerSupport.reset(new ModelManagerSupport(fastIndexer)); + m_modelManagerSupport.reset(new ModelManagerSupport); CppTools::CppModelManagerInterface::instance()->addModelManagerSupport( m_modelManagerSupport.data()); diff --git a/src/plugins/clangcodemodel/clangcompletion.cpp b/src/plugins/clangcodemodel/clangcompletion.cpp index b4456c61b3..9fbd1d0f29 100644 --- a/src/plugins/clangcodemodel/clangcompletion.cpp +++ b/src/plugins/clangcodemodel/clangcompletion.cpp @@ -203,15 +203,14 @@ IAssistProcessor *ClangCompletionAssistProvider::createProcessor() const } IAssistInterface *ClangCompletionAssistProvider::createAssistInterface( - ProjectExplorer::Project *project, TextEditor::BaseTextEditor *editor, + ProjectExplorer::Project *project, const QString &filePath, QTextDocument *document, bool isObjCEnabled, int position, AssistReason reason) const { Q_UNUSED(project); Q_UNUSED(isObjCEnabled); - QString fileName = editor->document()->filePath(); CppModelManagerInterface *modelManager = CppModelManagerInterface::instance(); - QList<ProjectPart::Ptr> parts = modelManager->projectPart(fileName); + QList<ProjectPart::Ptr> parts = modelManager->projectPart(filePath); if (parts.isEmpty()) parts += modelManager->fallbackProjectPart(); ProjectPart::HeaderPaths headerPaths; @@ -220,7 +219,7 @@ IAssistInterface *ClangCompletionAssistProvider::createAssistInterface( foreach (ProjectPart::Ptr part, parts) { if (part.isNull()) continue; - options = ClangCodeModel::Utils::createClangOptions(part, fileName); + options = ClangCodeModel::Utils::createClangOptions(part, filePath); pchInfo = PchManager::instance()->pchInfo(part); if (!pchInfo.isNull()) options.append(ClangCodeModel::Utils::createPCHInclusionOptions(pchInfo->fileName())); @@ -230,7 +229,7 @@ IAssistInterface *ClangCompletionAssistProvider::createAssistInterface( return new ClangCodeModel::ClangCompletionAssistInterface( m_clangCompletionWrapper, - document, position, fileName, reason, + document, position, filePath, reason, options, headerPaths, pchInfo); } diff --git a/src/plugins/clangcodemodel/clangcompletion.h b/src/plugins/clangcodemodel/clangcompletion.h index 180d7ec763..152439c54a 100644 --- a/src/plugins/clangcodemodel/clangcompletion.h +++ b/src/plugins/clangcodemodel/clangcompletion.h @@ -58,7 +58,7 @@ public: virtual TextEditor::IAssistProcessor *createProcessor() const; virtual TextEditor::IAssistInterface *createAssistInterface( - ProjectExplorer::Project *project, TextEditor::BaseTextEditor *editor, + ProjectExplorer::Project *project, const QString &filePath, QTextDocument *document, bool isObjCEnabled, int position, TextEditor::AssistReason reason) const; diff --git a/src/plugins/clangcodemodel/clangeditordocumentparser.cpp b/src/plugins/clangcodemodel/clangeditordocumentparser.cpp new file mode 100644 index 0000000000..f5e40bf6e2 --- /dev/null +++ b/src/plugins/clangcodemodel/clangeditordocumentparser.cpp @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +** GNU Lesser General Public License Usage +** 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 +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "clangeditordocumentparser.h" +#include "clangutils.h" +#include "pchinfo.h" +#include "pchmanager.h" + +#include <cpptools/cppmodelmanagerinterface.h> +#include <cpptools/cppprojects.h> +#include <cpptools/cppworkingcopy.h> + +#include <utils/hostosinfo.h> +#include <utils/qtcassert.h> + +static const bool DebugTiming = qgetenv("QTC_CLANG_VERBOSE") == "1"; + +namespace { + +QStringList createOptions(const QString &filePath, const CppTools::ProjectPart::Ptr &part) +{ + using namespace ClangCodeModel; + + QStringList options; + if (part.isNull()) + return options; + + options += QLatin1String("-fspell-checking"); + options += ClangCodeModel::Utils::createClangOptions(part, filePath); + + if (Internal::PchInfo::Ptr pchInfo = Internal::PchManager::instance()->pchInfo(part)) + options.append(ClangCodeModel::Utils::createPCHInclusionOptions(pchInfo->fileName())); + + return options; +} + +QString commandLine(const QStringList &options, const QString &fileName) +{ + const QStringList allOptions = QStringList(options) + << QLatin1String("-fsyntax-only") << fileName; + QStringList allOptionsQuoted; + foreach (const QString &option, allOptions) + allOptionsQuoted.append(QLatin1Char('\'') + option + QLatin1Char('\'')); + return ::Utils::HostOsInfo::withExecutableSuffix(QLatin1String("clang")) + + QLatin1Char(' ') + allOptionsQuoted.join(QLatin1Char(' ')); +} + +} // anonymous namespace + +namespace ClangCodeModel { + +ClangEditorDocumentParser::ClangEditorDocumentParser(const QString &filePath) + : BaseEditorDocumentParser(filePath) + , m_marker(new ClangCodeModel::SemanticMarker) +{ +} + +void ClangEditorDocumentParser::update(CppTools::WorkingCopy workingCopy) +{ + QTC_ASSERT(m_marker, return); + QMutexLocker lock(m_marker->mutex()); + QMutexLocker lock2(&m_mutex); + + updateProjectPart(); + const QStringList options = createOptions(filePath(), projectPart()); + + QTime t; + if (DebugTiming) { + qDebug("*** Reparse options (cmd line equivalent): %s", + commandLine(options, filePath()).toUtf8().constData()); + t.start(); + } + + m_marker->setFileName(filePath()); + m_marker->setCompilationOptions(options); + const Internal::UnsavedFiles unsavedFiles = Utils::createUnsavedFiles(workingCopy); + m_marker->reparse(unsavedFiles); + + if (DebugTiming) + qDebug() << "*** Reparse took" << t.elapsed() << "ms."; +} + +QList<Diagnostic> ClangEditorDocumentParser::diagnostics() const +{ + QTC_ASSERT(m_marker, return QList<Diagnostic>()); + QMutexLocker(m_marker->mutex()); + return m_marker->diagnostics(); +} + +QList<SemanticMarker::Range> ClangEditorDocumentParser::ifdefedOutBlocks() const +{ + QTC_ASSERT(m_marker, return QList<SemanticMarker::Range>()); + QMutexLocker(m_marker->mutex()); + return m_marker->ifdefedOutBlocks(); +} + +SemanticMarker::Ptr ClangEditorDocumentParser::semanticMarker() const +{ + return m_marker; +} + +} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clanghighlightingsupport.h b/src/plugins/clangcodemodel/clangeditordocumentparser.h index 69b525f9f5..98017b6512 100644 --- a/src/plugins/clangcodemodel/clanghighlightingsupport.h +++ b/src/plugins/clangcodemodel/clangeditordocumentparser.h @@ -27,43 +27,42 @@ ** ****************************************************************************/ -#ifndef CLANG_CLANGHIGHLIGHTINGSUPPORT_H -#define CLANG_CLANGHIGHLIGHTINGSUPPORT_H -#include "clangutils.h" -#include "cppcreatemarkers.h" -#include "fastindexer.h" +#ifndef CLANGEDITORDOCUMENTPARSER_H +#define CLANGEDITORDOCUMENTPARSER_H -#include <cpptools/cpphighlightingsupport.h> +#include "semanticmarker.h" -#include <QObject> -#include <QScopedPointer> +#include <cpptools/baseeditordocumentparser.h> + +#include <utils/qtcoverride.h> + +namespace CppTools { class WorkingCopy; } namespace ClangCodeModel { -class ClangHighlightingSupport: public CppTools::CppHighlightingSupport +class ClangEditorDocumentParser : public CppTools::BaseEditorDocumentParser { -public: - ClangHighlightingSupport(TextEditor::BaseTextDocument *baseTextDocument, - Internal::FastIndexer *fastIndexer); - ~ClangHighlightingSupport(); + Q_OBJECT - virtual bool requiresSemanticInfo() const - { return false; } +public: + typedef QSharedPointer<ClangEditorDocumentParser> Ptr; - virtual bool hightlighterHandlesDiagnostics() const - { return true; } +public: + ClangEditorDocumentParser(const QString &filePath); - virtual bool hightlighterHandlesIfdefedOutBlocks() const; + void update(CppTools::WorkingCopy workingCopy) QTC_OVERRIDE; - virtual QFuture<TextEditor::HighlightingResult> highlightingFuture( - const CPlusPlus::Document::Ptr &doc, const CPlusPlus::Snapshot &snapshot) const; + QList<Diagnostic> diagnostics() const; + QList<SemanticMarker::Range> ifdefedOutBlocks() const; + SemanticMarker::Ptr semanticMarker() const; private: - Internal::FastIndexer *m_fastIndexer; - ClangCodeModel::SemanticMarker::Ptr m_semanticMarker; + SemanticMarker::Ptr m_marker; + QStringList m_options; + Internal::UnsavedFiles m_unsavedFiles; }; } // namespace ClangCodeModel -#endif // CLANG_CLANGHIGHLIGHTINGSUPPORT_H +#endif // CLANGEDITORDOCUMENTPARSER_H diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp new file mode 100644 index 0000000000..b73d1015c5 --- /dev/null +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp @@ -0,0 +1,184 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +** GNU Lesser General Public License Usage +** 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 +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "clangeditordocumentprocessor.h" + +#include "cppcreatemarkers.h" +#include "diagnostic.h" +#include "pchinfo.h" + +#include <cpptools/cpptoolsplugin.h> +#include <cpptools/cppworkingcopy.h> + +#include <cplusplus/CppDocument.h> + +#include <utils/qtcassert.h> +#include <utils/QtConcurrentTools> + +static const bool DebugTiming = qgetenv("QTC_CLANG_VERBOSE") == "1"; + +namespace { + +typedef CPlusPlus::Document::DiagnosticMessage CppToolsDiagnostic; +QList<CppToolsDiagnostic> toCppToolsDiagnostics( + const QString &filePath, + const QList<ClangCodeModel::Diagnostic> &diagnostics) +{ + using namespace ClangCodeModel; + + QList<CppToolsDiagnostic> converted; + foreach (const ClangCodeModel::Diagnostic &d, diagnostics) { + if (DebugTiming) + qDebug() << d.severityAsString() << d.location() << d.spelling(); + + if (d.location().fileName() != filePath) + continue; + + // TODO: retrieve fix-its for this diagnostic + + int level; + switch (d.severity()) { + case Diagnostic::Fatal: level = CppToolsDiagnostic::Fatal; break; + case Diagnostic::Error: level = CppToolsDiagnostic::Error; break; + case Diagnostic::Warning: level = CppToolsDiagnostic::Warning; break; + default: continue; + } + converted.append(CppToolsDiagnostic(level, d.location().fileName(), d.location().line(), + d.location().column(), d.spelling(), d.length())); + } + + return converted; +} + +QList<TextEditor::BlockRange> toTextEditorBlocks( + const QList<ClangCodeModel::SemanticMarker::Range> &ranges) +{ + QList<TextEditor::BlockRange> result; + result.reserve(ranges.size()); + foreach (const ClangCodeModel::SemanticMarker::Range &range, ranges) + result.append(TextEditor::BlockRange(range.first, range.last)); + return result; +} + +} // anonymous namespace + +namespace ClangCodeModel { + +ClangEditorDocumentProcessor::ClangEditorDocumentProcessor(TextEditor::BaseTextDocument *document) + : BaseEditorDocumentProcessor(document) + , m_parser(new ClangEditorDocumentParser(document->filePath())) + , m_parserRevision(0) + , m_semanticHighlighter(document) + , m_builtinProcessor(document, /*enableSemanticHighlighter=*/ false) +{ + // Forwarding the semantic info from the builtin processor enables us to provide all + // editor (widget) related features that are not yet implemented by the clang plugin. + connect(&m_builtinProcessor, &CppTools::BuiltinEditorDocumentProcessor::cppDocumentUpdated, + this, &ClangEditorDocumentProcessor::cppDocumentUpdated); + connect(&m_builtinProcessor, &CppTools::BuiltinEditorDocumentProcessor::semanticInfoUpdated, + this, &ClangEditorDocumentProcessor::semanticInfoUpdated); + + m_semanticHighlighter.setHighlightingRunner( + [this]() -> QFuture<TextEditor::HighlightingResult> { + const int firstLine = 1; + const int lastLine = baseTextDocument()->document()->blockCount(); + + CreateMarkers *createMarkers = CreateMarkers::create(m_parser->semanticMarker(), + baseTextDocument()->filePath(), + firstLine, lastLine); + return createMarkers->start(); + }); +} + +ClangEditorDocumentProcessor::~ClangEditorDocumentProcessor() +{ + m_parserWatcher.cancel(); + m_parserWatcher.waitForFinished(); +} + +void ClangEditorDocumentProcessor::run() +{ + // Run clang parser + const CppTools::WorkingCopy workingCopy + = CppTools::CppModelManagerInterface::instance()->workingCopy(); + + disconnect(&m_parserWatcher, &QFutureWatcher<void>::finished, + this, &ClangEditorDocumentProcessor::onParserFinished); + m_parserWatcher.cancel(); + m_parserWatcher.setFuture(QFuture<void>()); + + m_parserRevision = revision(); + connect(&m_parserWatcher, &QFutureWatcher<void>::finished, + this, &ClangEditorDocumentProcessor::onParserFinished); + const QFuture<void> future = QtConcurrent::run(&runParser, parser(), workingCopy); + m_parserWatcher.setFuture(future); + + // Run builtin processor + m_builtinProcessor.run(); +} + +void ClangEditorDocumentProcessor::semanticRehighlight(bool force) +{ + m_builtinProcessor.semanticRehighlight(force); +} + +CppTools::SemanticInfo ClangEditorDocumentProcessor::recalculateSemanticInfo() +{ + return m_builtinProcessor.recalculateSemanticInfo(); +} + +CppTools::BaseEditorDocumentParser *ClangEditorDocumentProcessor::parser() +{ + return m_parser.data(); +} + +bool ClangEditorDocumentProcessor::isParserRunning() const +{ + return m_parserWatcher.isRunning(); +} + +void ClangEditorDocumentProcessor::onParserFinished() +{ + if (revision() != m_parserRevision) + return; + + // Emit ifdefed out blocks + const auto ifdefoutBlocks = toTextEditorBlocks(m_parser->ifdefedOutBlocks()); + emit ifdefedOutBlocksUpdated(revision(), ifdefoutBlocks); + + // Emit code warnings + const auto diagnostics = toCppToolsDiagnostics(filePath(), m_parser->diagnostics()); + const auto codeWarnings = toTextEditorSelections(diagnostics, textDocument()); + emit codeWarningsUpdated(revision(), codeWarnings); + + // Run semantic highlighter + m_semanticHighlighter.run(); +} + +} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.h b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h new file mode 100644 index 0000000000..cffddbffd5 --- /dev/null +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +** GNU Lesser General Public License Usage +** 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 +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CLANGEDITORDOCUMENTPROCESSOR_H +#define CLANGEDITORDOCUMENTPROCESSOR_H + +#include "clangeditordocumentparser.h" + +#include <cpptools/baseeditordocumentprocessor.h> +#include <cpptools/builtineditordocumentprocessor.h> +#include <cpptools/semantichighlighter.h> + +#include <utils/qtcoverride.h> + +#include <QFutureWatcher> + +namespace ClangCodeModel { + +class ClangEditorDocumentProcessor : public CppTools::BaseEditorDocumentProcessor +{ + Q_OBJECT + +public: + ClangEditorDocumentProcessor(TextEditor::BaseTextDocument *document); + ~ClangEditorDocumentProcessor(); + + // BaseEditorDocumentProcessor interface + void run() QTC_OVERRIDE; + void semanticRehighlight(bool force) QTC_OVERRIDE; + CppTools::SemanticInfo recalculateSemanticInfo() QTC_OVERRIDE; + CppTools::BaseEditorDocumentParser *parser() QTC_OVERRIDE; + bool isParserRunning() const QTC_OVERRIDE; + +private slots: + void onParserFinished(); + +private: + QScopedPointer<ClangEditorDocumentParser> m_parser; + QFutureWatcher<void> m_parserWatcher; + unsigned m_parserRevision; + + CppTools::SemanticHighlighter m_semanticHighlighter; + CppTools::BuiltinEditorDocumentProcessor m_builtinProcessor; +}; + +} // namespace ClangCodeModel + +#endif // CLANGEDITORDOCUMENTPROCESSOR_H diff --git a/src/plugins/clangcodemodel/clanghighlightingsupport.cpp b/src/plugins/clangcodemodel/clanghighlightingsupport.cpp deleted file mode 100644 index 85d2b559a3..0000000000 --- a/src/plugins/clangcodemodel/clanghighlightingsupport.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of Qt Creator. -** -** 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. -** -** GNU Lesser General Public License Usage -** 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 -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#include "clanghighlightingsupport.h" - -#include <texteditor/basetextdocument.h> - -#include <QTextBlock> -#include <QTextEdit> -#include "pchmanager.h" - -using namespace ClangCodeModel; -using namespace ClangCodeModel::Internal; -using namespace CppTools; - -ClangHighlightingSupport::ClangHighlightingSupport(TextEditor::BaseTextDocument *baseTextDocument, - FastIndexer *fastIndexer) - : CppHighlightingSupport(baseTextDocument) - , m_fastIndexer(fastIndexer) - , m_semanticMarker(new ClangCodeModel::SemanticMarker) -{ -} - -ClangHighlightingSupport::~ClangHighlightingSupport() -{ -} - -bool ClangHighlightingSupport::hightlighterHandlesIfdefedOutBlocks() const -{ -#if CINDEX_VERSION_MINOR >= 21 - return true; -#else - return false; -#endif -} - -QFuture<TextEditor::HighlightingResult> ClangHighlightingSupport::highlightingFuture( - const CPlusPlus::Document::Ptr &doc, - const CPlusPlus::Snapshot &snapshot) const -{ - Q_UNUSED(doc); - Q_UNUSED(snapshot); - - int firstLine = 1; - int lastLine = baseTextDocument()->document()->blockCount(); - - const QString fileName = baseTextDocument()->filePath(); - CppModelManagerInterface *modelManager = CppModelManagerInterface::instance(); - QList<ProjectPart::Ptr> parts = modelManager->projectPart(fileName); - if (parts.isEmpty()) - parts += modelManager->fallbackProjectPart(); - QStringList options; - PchInfo::Ptr pchInfo; - foreach (const ProjectPart::Ptr &part, parts) { - if (part.isNull()) - continue; - options = Utils::createClangOptions(part, fileName); - pchInfo = PchManager::instance()->pchInfo(part); - if (!pchInfo.isNull()) - options.append(ClangCodeModel::Utils::createPCHInclusionOptions(pchInfo->fileName())); - if (!options.isEmpty()) - break; - } - - CreateMarkers *createMarkers = CreateMarkers::create(m_semanticMarker, - fileName, options, - firstLine, lastLine, - m_fastIndexer, pchInfo); - return createMarkers->start(); -} diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 4f7430ee5a..289ab8bde4 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -28,7 +28,7 @@ ****************************************************************************/ #include "clangcompletion.h" -#include "clanghighlightingsupport.h" +#include "clangeditordocumentprocessor.h" #include "clangmodelmanagersupport.h" #include <QCoreApplication> @@ -36,9 +36,8 @@ using namespace ClangCodeModel; using namespace ClangCodeModel::Internal; -ModelManagerSupport::ModelManagerSupport(FastIndexer *fastIndexer) +ModelManagerSupport::ModelManagerSupport() : m_completionAssistProvider(new ClangCompletionAssistProvider) - , m_fastIndexer(fastIndexer) { } @@ -63,8 +62,8 @@ CppTools::CppCompletionAssistProvider *ModelManagerSupport::completionAssistProv return m_completionAssistProvider.data(); } -CppTools::CppHighlightingSupport *ModelManagerSupport::highlightingSupport( +CppTools::BaseEditorDocumentProcessor *ModelManagerSupport::editorDocumentProcessor( TextEditor::BaseTextDocument *baseTextDocument) { - return new ClangHighlightingSupport(baseTextDocument, m_fastIndexer); + return new ClangCodeModel::ClangEditorDocumentProcessor(baseTextDocument); } diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.h b/src/plugins/clangcodemodel/clangmodelmanagersupport.h index ef1205be74..8855ecd514 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.h +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.h @@ -37,26 +37,23 @@ namespace ClangCodeModel { namespace Internal { -class FastIndexer; - class ModelManagerSupport: public CppTools::ModelManagerSupport { Q_DISABLE_COPY(ModelManagerSupport) public: - ModelManagerSupport(FastIndexer *fastIndexer); + ModelManagerSupport(); virtual ~ModelManagerSupport(); virtual QString id() const; virtual QString displayName() const; virtual CppTools::CppCompletionAssistProvider *completionAssistProvider(); - virtual CppTools::CppHighlightingSupport *highlightingSupport( - TextEditor::BaseTextDocument *baseTextDocument); + virtual CppTools::BaseEditorDocumentProcessor *editorDocumentProcessor( + TextEditor::BaseTextDocument *baseTextDocument); private: QScopedPointer<CppTools::CppCompletionAssistProvider> m_completionAssistProvider; - FastIndexer *m_fastIndexer; }; } // namespace Internal diff --git a/src/plugins/clangcodemodel/cppcreatemarkers.cpp b/src/plugins/clangcodemodel/cppcreatemarkers.cpp index b88849f3c5..2bfde48a8d 100644 --- a/src/plugins/clangcodemodel/cppcreatemarkers.cpp +++ b/src/plugins/clangcodemodel/cppcreatemarkers.cpp @@ -30,11 +30,7 @@ #include "clangutils.h" #include "cppcreatemarkers.h" -#include <cpptools/cppmodelmanagerinterface.h> -#include <cpptools/cppworkingcopy.h> - #include <cplusplus/CppDocument.h> -#include <utils/hostosinfo.h> #include <utils/runextensions.h> #include <QCoreApplication> @@ -51,119 +47,52 @@ using namespace CppTools; CreateMarkers *CreateMarkers::create(SemanticMarker::Ptr semanticMarker, const QString &fileName, - const QStringList &options, - unsigned firstLine, unsigned lastLine, - FastIndexer *fastIndexer, - const Internal::PchInfo::Ptr &pchInfo) + unsigned firstLine, unsigned lastLine) { if (semanticMarker.isNull()) return 0; else - return new CreateMarkers(semanticMarker, fileName, options, firstLine, lastLine, fastIndexer, pchInfo); + return new CreateMarkers(semanticMarker, fileName, firstLine, lastLine); } CreateMarkers::CreateMarkers(SemanticMarker::Ptr semanticMarker, const QString &fileName, - const QStringList &options, - unsigned firstLine, unsigned lastLine, - FastIndexer *fastIndexer, - const Internal::PchInfo::Ptr &pchInfo) + unsigned firstLine, unsigned lastLine) : m_marker(semanticMarker) - , m_pchInfo(pchInfo) , m_fileName(fileName) - , m_options(options) , m_firstLine(firstLine) , m_lastLine(lastLine) - , m_fastIndexer(fastIndexer) { Q_ASSERT(!semanticMarker.isNull()); m_flushRequested = false; m_flushLine = 0; - - m_unsavedFiles = Utils::createUnsavedFiles(CppModelManagerInterface::instance()->workingCopy()); } CreateMarkers::~CreateMarkers() { } -static QString commandLine(const QStringList &options, const QString &fileName) -{ - const QStringList allOptions = QStringList(options) - << QLatin1String("-fsyntax-only") << fileName; - QStringList allOptionsQuoted; - foreach (const QString &option, allOptions) - allOptionsQuoted.append(QLatin1Char('\'') + option + QLatin1Char('\'')); - return ::Utils::HostOsInfo::withExecutableSuffix(QLatin1String("clang")) - + QLatin1Char(' ') + allOptionsQuoted.join(QLatin1Char(' ')); -} - void CreateMarkers::run() { QMutexLocker lock(m_marker->mutex()); if (isCanceled()) return; - m_options += QLatin1String("-fspell-checking"); - QTime t; if (DebugTiming) { qDebug() << "*** Highlighting from" << m_firstLine << "to" << m_lastLine << "of" << m_fileName; - qDebug("***** Options (cmd line equivalent): %s", - commandLine(m_options, m_fileName).toUtf8().constData()); t.start(); } m_usages.clear(); - m_marker->setFileName(m_fileName); - m_marker->setCompilationOptions(m_options); - - m_marker->reparse(m_unsavedFiles); - - if (DebugTiming) - qDebug() << "*** Reparse for highlighting took" << t.elapsed() << "ms."; - - m_pchInfo.clear(); - - typedef CPlusPlus::Document::DiagnosticMessage OtherDiagnostic; - QList<OtherDiagnostic> msgs; - foreach (const ClangCodeModel::Diagnostic &d, m_marker->diagnostics()) { - if (DebugTiming) - qDebug() << d.severityAsString() << d.location() << d.spelling(); - - if (d.location().fileName() != m_marker->fileName()) - continue; - // TODO: retrieve fix-its for this diagnostic - - int level; - switch (d.severity()) { - case Diagnostic::Fatal: level = OtherDiagnostic::Fatal; break; - case Diagnostic::Error: level = OtherDiagnostic::Error; break; - case Diagnostic::Warning: level = OtherDiagnostic::Warning; break; - default: continue; - } - msgs.append(OtherDiagnostic(level, d.location().fileName(), d.location().line(), - d.location().column(), d.spelling(), d.length())); - } if (isCanceled()) { reportFinished(); return; } - CppModelManagerInterface *mmi = CppModelManagerInterface::instance(); - static const QString key = QLatin1String("ClangCodeModel.Diagnostics"); - mmi->setExtraDiagnostics(m_marker->fileName(), key, msgs); -#if CINDEX_VERSION_MINOR >= 21 - mmi->setIfdefedOutBlocks(m_marker->fileName(), m_marker->ifdefedOutBlocks()); -#endif - - if (isCanceled()) { - reportFinished(); - return; - } - - QList<ClangCodeModel::SourceMarker> markers = m_marker->sourceMarkersInRange(m_firstLine, m_lastLine); + const QList<ClangCodeModel::SourceMarker> markers + = m_marker->sourceMarkersInRange(m_firstLine, m_lastLine); foreach (const ClangCodeModel::SourceMarker &m, markers) addUse(SourceMarker(m.location().line(), m.location().column(), m.length(), m.kind())); @@ -179,12 +108,6 @@ void CreateMarkers::run() qDebug() << "*** Highlighting took" << t.elapsed() << "ms in total."; t.restart(); } - - if (m_fastIndexer) - m_fastIndexer->indexNow(m_marker->unit()); - - if (DebugTiming) - qDebug() << "*** Fast re-indexing took" << t.elapsed() << "ms in total."; } void CreateMarkers::addUse(const SourceMarker &marker) diff --git a/src/plugins/clangcodemodel/cppcreatemarkers.h b/src/plugins/clangcodemodel/cppcreatemarkers.h index c372e4b08e..e602161302 100644 --- a/src/plugins/clangcodemodel/cppcreatemarkers.h +++ b/src/plugins/clangcodemodel/cppcreatemarkers.h @@ -37,7 +37,6 @@ #include <texteditor/semantichighlighter.h> -#include <QSet> #include <QFuture> #include <QtConcurrentRun> @@ -70,35 +69,23 @@ public: } static CreateMarkers *create(ClangCodeModel::SemanticMarker::Ptr semanticMarker, - const QString &fileName, - const QStringList &options, - unsigned firstLine, unsigned lastLine, - Internal::FastIndexer *fastIndexer, - const Internal::PchInfo::Ptr &pchInfo); + const QString &fileName, unsigned firstLine, unsigned lastLine); void addUse(const SourceMarker &marker); void flush(); protected: CreateMarkers(ClangCodeModel::SemanticMarker::Ptr semanticMarker, - const QString &fileName, const QStringList &options, - unsigned firstLine, unsigned lastLine, - Internal::FastIndexer *fastIndexer, - const Internal::PchInfo::Ptr &pchInfo); + const QString &fileName, unsigned firstLine, unsigned lastLine); private: ClangCodeModel::SemanticMarker::Ptr m_marker; - Internal::PchInfo::Ptr m_pchInfo; QString m_fileName; - QStringList m_options; unsigned m_firstLine; unsigned m_lastLine; - Internal::FastIndexer *m_fastIndexer; QVector<SourceMarker> m_usages; bool m_flushRequested; unsigned m_flushLine; - - ClangCodeModel::Internal::UnsavedFiles m_unsavedFiles; }; } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/semanticmarker.cpp b/src/plugins/clangcodemodel/semanticmarker.cpp index f1b9a71a25..e367c3a0f7 100644 --- a/src/plugins/clangcodemodel/semanticmarker.cpp +++ b/src/plugins/clangcodemodel/semanticmarker.cpp @@ -32,6 +32,8 @@ #include "utils_p.h" #include "cxraii.h" +#include <utils/qtcassert.h> + using namespace ClangCodeModel; using namespace ClangCodeModel::Internal; @@ -74,7 +76,7 @@ void SemanticMarker::setFileName(const QString &fileName) void SemanticMarker::setCompilationOptions(const QStringList &options) { - Q_ASSERT(m_unit); + QTC_ASSERT(m_unit, return); if (m_unit->compilationOptions() == options) return; @@ -84,7 +86,7 @@ void SemanticMarker::setCompilationOptions(const QStringList &options) void SemanticMarker::reparse(const UnsavedFiles &unsavedFiles) { - Q_ASSERT(m_unit); + QTC_ASSERT(m_unit, return); m_unit->setUnsavedFiles(unsavedFiles); if (m_unit->isLoaded()) @@ -169,9 +171,9 @@ QList<Diagnostic> SemanticMarker::diagnostics() const return diagnostics; } -QList<TextEditor::BlockRange> SemanticMarker::ifdefedOutBlocks() const +QList<SemanticMarker::Range> SemanticMarker::ifdefedOutBlocks() const { - QList<TextEditor::BlockRange> blocks; + QList<Range> blocks; if (!m_unit || !m_unit->isLoaded()) return blocks; @@ -188,7 +190,7 @@ QList<TextEditor::BlockRange> SemanticMarker::ifdefedOutBlocks() const const SourceLocation &spellEnd = Internal::getSpellingLocation(clang_getRangeEnd(r)); const int begin = spellBegin.offset() + 1; const int end = spellEnd.offset() - spellEnd.column(); - blocks.append(TextEditor::BlockRange(begin, end)); + blocks.append(Range(begin, end)); } clang_disposeSourceRangeList(skippedRanges); #endif @@ -322,9 +324,8 @@ static const QSet<QString> ObjcPseudoKeywords = QSet<QString>() QList<SourceMarker> SemanticMarker::sourceMarkersInRange(unsigned firstLine, unsigned lastLine) { - Q_ASSERT(m_unit); - QList<SourceMarker> result; + QTC_ASSERT(m_unit, return result); if (!m_unit->isLoaded()) return result; diff --git a/src/plugins/clangcodemodel/semanticmarker.h b/src/plugins/clangcodemodel/semanticmarker.h index 744aece1c6..0ec3979ffc 100644 --- a/src/plugins/clangcodemodel/semanticmarker.h +++ b/src/plugins/clangcodemodel/semanticmarker.h @@ -36,8 +36,6 @@ #include "sourcemarker.h" #include "utils.h" -#include <texteditor/basetexteditor.h> - #include <QMutex> #include <QScopedPointer> #include <QSharedPointer> @@ -53,6 +51,16 @@ class CLANG_EXPORT SemanticMarker public: typedef QSharedPointer<SemanticMarker> Ptr; + class Range + { + Range(); + public: + Range(int first, int last) : first(first), last(last) {} + + int first; + int last; + }; + public: SemanticMarker(); ~SemanticMarker(); @@ -69,7 +77,7 @@ public: QList<Diagnostic> diagnostics() const; - QList<TextEditor::BlockRange> ifdefedOutBlocks() const; + QList<Range> ifdefedOutBlocks() const; QList<SourceMarker> sourceMarkersInRange(unsigned firstLine, unsigned lastLine); diff --git a/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp b/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp index 0cc424c567..892df8b246 100644 --- a/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp +++ b/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp @@ -30,12 +30,13 @@ #include "cppcodemodelinspectordialog.h" #include "ui_cppcodemodelinspectordialog.h" #include "cppeditor.h" +#include "cppeditordocument.h" #include <coreplugin/editormanager/editormanager.h> #include <coreplugin/icore.h> +#include <cpptools/builtineditordocumentparser.h> #include <cpptools/cppcodemodelinspectordumper.h> #include <cpptools/cppmodelmanager.h> -#include <cpptools/cpptoolseditorsupport.h> #include <cpptools/cppworkingcopy.h> #include <projectexplorer/project.h> @@ -1358,11 +1359,13 @@ void CppCodeModelInspectorDialog::refresh() dumper.dumpSnapshot(globalSnapshot, globalSnapshotTitle, /*isGlobalSnapshot=*/ true); TextEditor::BaseTextEditor *editor = currentEditor(); - CppEditorSupport *editorSupport = 0; + EditorDocumentHandle *editorDocument = 0; if (editor) { - editorSupport = cmmi->cppEditorSupport(editor); - if (editorSupport) { - const CPlusPlus::Snapshot editorSnapshot = editorSupport->documentParser()->snapshot(); + const QString editorFilePath = editor->document()->filePath(); + editorDocument = cmmi->editorDocument(editorFilePath); + if (editorDocument) { + const CPlusPlus::Snapshot editorSnapshot + = BuiltinEditorDocumentParser::get(editorFilePath)->snapshot(); m_snapshotInfos->append(SnapshotInfo(editorSnapshot, SnapshotInfo::EditorSnapshot)); const QString editorSnapshotTitle = QString::fromLatin1("Current Editor's Snapshot (%1 Documents)") @@ -1412,8 +1415,8 @@ void CppCodeModelInspectorDialog::refresh() onSnapshotSelected(snapshotIndex); // Project Parts - const ProjectPart::Ptr editorsProjectPart = editorSupport - ? editorSupport->documentParser()->projectPart() + const ProjectPart::Ptr editorsProjectPart = editorDocument + ? editorDocument->processor()->parser()->projectPart() : ProjectPart::Ptr(); const QList<ProjectInfo> projectInfos = cmmi->projectInfos(); diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index c832a33453..c133b3c3e3 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -33,6 +33,7 @@ #include "cppcanonicalsymbol.h" #include "cppdocumentationcommenthelper.h" #include "cppeditorconstants.h" +#include "cppeditordocument.h" #include "cppeditoroutline.h" #include "cppeditorplugin.h" #include "cppfollowsymbolundercursor.h" @@ -40,18 +41,18 @@ #include "cpplocalrenaming.h" #include "cpppreprocessordialog.h" #include "cppquickfixassistant.h" +#include "cppuseselectionsupdater.h" #include <coreplugin/actionmanager/actioncontainer.h> #include <coreplugin/actionmanager/actionmanager.h> #include <cpptools/cppchecksymbols.h> +#include <cpptools/cppchecksymbols.h> #include <cpptools/cppcodeformatter.h> #include <cpptools/cppcompletionassistprovider.h> -#include <cpptools/cpphighlightingsupport.h> #include <cpptools/cppmodelmanagerinterface.h> #include <cpptools/cppsemanticinfo.h> #include <cpptools/cpptoolsconstants.h> -#include <cpptools/cpptoolseditorsupport.h> #include <cpptools/cpptoolsplugin.h> #include <cpptools/cpptoolsreuse.h> #include <cpptools/cppworkingcopy.h> @@ -67,14 +68,11 @@ #include <texteditor/fontsettings.h> #include <texteditor/refactoroverlay.h> -#include <utils/qtcassert.h> - #include <cplusplus/ASTPath.h> -#include <cplusplus/BackwardsScanner.h> -#include <cplusplus/ExpressionUnderCursor.h> -#include <cplusplus/OverviewModel.h> +#include <utils/qtcassert.h> #include <QAction> +#include <QElapsedTimer> #include <QFutureWatcher> #include <QMenu> #include <QPointer> @@ -83,10 +81,7 @@ #include <QTimer> #include <QToolButton> -enum { - UPDATE_USES_INTERVAL = 500, - UPDATE_FUNCTION_DECL_DEF_LINK_INTERVAL = 200 -}; +enum { UPDATE_FUNCTION_DECL_DEF_LINK_INTERVAL = 200 }; using namespace CPlusPlus; using namespace CppTools; @@ -103,7 +98,9 @@ CPPEditor::CPPEditor() setDuplicateSupported(true); setCommentStyle(Utils::CommentDefinition::CppStyle); setCompletionAssistProvider([this] () -> TextEditor::CompletionAssistProvider * { - return CppModelManagerInterface::instance()->cppEditorSupport(this)->completionAssistProvider(); + if (CPPEditorDocument *document = qobject_cast<CPPEditorDocument *>(textDocument())) + return document->completionAssistProvider(); + return 0; }); } @@ -122,21 +119,14 @@ public: CppDocumentationCommentHelper m_cppDocumentationCommentHelper; - QTimer m_updateUsesTimer; QTimer m_updateFunctionDeclDefLinkTimer; - QHash<int, QTextCharFormat> m_semanticHighlightFormatMap; CppLocalRenaming m_localRenaming; CppTools::SemanticInfo m_lastSemanticInfo; QList<TextEditor::QuickFixOperation::Ptr> m_quickFixes; - QScopedPointer<QFutureWatcher<TextEditor::HighlightingResult> > m_highlightWatcher; - unsigned m_highlightRevision; // the editor revision that requested the highlight - - QScopedPointer<QFutureWatcher<QList<int> > > m_referencesWatcher; - unsigned m_referencesRevision; - int m_referencesCursorPosition; + CppUseSelectionsUpdater m_useSelectionsUpdater; FunctionDeclDefLinkFinder *m_declDefLinkFinder; QSharedPointer<FunctionDeclDefLink> m_declDefLink; @@ -151,9 +141,7 @@ CppEditorWidgetPrivate::CppEditorWidgetPrivate(CppEditorWidget *q) , m_cppEditorOutline(new CppEditorOutline(q)) , m_cppDocumentationCommentHelper(q) , m_localRenaming(q) - , m_highlightRevision(0) - , m_referencesRevision(0) - , m_referencesCursorPosition(0) + , m_useSelectionsUpdater(q) , m_declDefLinkFinder(new FunctionDeclDefLinkFinder(q)) , m_followSymbolUnderCursor(new FollowSymbolUnderCursor(q)) , m_preprocessorButton(0) @@ -162,28 +150,27 @@ CppEditorWidgetPrivate::CppEditorWidgetPrivate(CppEditorWidget *q) CppEditorWidget::CppEditorWidget(TextEditor::BaseTextDocumentPtr doc, CPPEditor *editor) { + qRegisterMetaType<SemanticInfo>("CppTools::SemanticInfo"); + editor->setEditorWidget(this); setTextDocument(doc); d.reset(new CppEditorWidgetPrivate(this)); setAutoCompleter(new CppAutoCompleter); - - qRegisterMetaType<SemanticInfo>("CppTools::SemanticInfo"); - - setParenthesesMatchingEnabled(true); - setMarksVisible(true); + setLanguageSettingsId(CppTools::Constants::CPP_SETTINGS_ID); setCodeFoldingSupported(true); + setMarksVisible(true); + setParenthesesMatchingEnabled(true); setRevisionsVisible(true); - if (d->m_modelManager) { - CppEditorSupport *editorSupport = d->m_modelManager->cppEditorSupport(editor); - connect(editorSupport, SIGNAL(documentUpdated()), - this, SLOT(onDocumentUpdated())); - connect(editorSupport, SIGNAL(semanticInfoUpdated(CppTools::SemanticInfo)), - this, SLOT(updateSemanticInfo(CppTools::SemanticInfo))); - connect(editorSupport, SIGNAL(highlighterStarted(QFuture<TextEditor::HighlightingResult>*,uint)), - this, SLOT(highlighterStarted(QFuture<TextEditor::HighlightingResult>*,uint))); - } + connect(d->m_cppEditorDocument, &CPPEditorDocument::codeWarningsUpdated, + this, &CppEditorWidget::onCodeWarningsUpdated); + connect(d->m_cppEditorDocument, &CPPEditorDocument::ifdefedOutBlocksUpdated, + this, &CppEditorWidget::onIfdefedOutBlocksUpdated); + connect(d->m_cppEditorDocument, SIGNAL(cppDocumentUpdated(CPlusPlus::Document::Ptr)), + this, SLOT(onCppDocumentUpdated())); + connect(d->m_cppEditorDocument, SIGNAL(semanticInfoUpdated(CppTools::SemanticInfo)), + this, SLOT(updateSemanticInfo(CppTools::SemanticInfo))); connect(d->m_declDefLinkFinder, SIGNAL(foundLink(QSharedPointer<FunctionDeclDefLink>)), this, SLOT(onFunctionDeclDefLinkFound(QSharedPointer<FunctionDeclDefLink>))); @@ -191,39 +178,42 @@ CppEditorWidget::CppEditorWidget(TextEditor::BaseTextDocumentPtr doc, CPPEditor connect(textDocument(), SIGNAL(filePathChanged(QString,QString)), this, SLOT(onFilePathChanged())); - connect(&d->m_localRenaming, SIGNAL(finished()), - this, SLOT(onLocalRenamingFinished())); - connect(&d->m_localRenaming, SIGNAL(processKeyPressNormally(QKeyEvent*)), - this, SLOT(onLocalRenamingProcessKeyPressNormally(QKeyEvent*))); - - // Tool bar creation - d->m_updateUsesTimer.setSingleShot(true); - d->m_updateUsesTimer.setInterval(UPDATE_USES_INTERVAL); - - connect(&d->m_updateUsesTimer, &QTimer::timeout, - this, &CppEditorWidget::updateUsesNow); + connect(&d->m_useSelectionsUpdater, + SIGNAL(selectionsForVariableUnderCursorUpdated(QList<QTextEdit::ExtraSelection>)), + &d->m_localRenaming, + SLOT(updateSelectionsForVariableUnderCursor(QList<QTextEdit::ExtraSelection>))); - d->m_updateFunctionDeclDefLinkTimer.setSingleShot(true); - d->m_updateFunctionDeclDefLinkTimer.setInterval(UPDATE_FUNCTION_DECL_DEF_LINK_INTERVAL); + connect(&d->m_useSelectionsUpdater, &CppUseSelectionsUpdater::finished, + [this] (CppTools::SemanticInfo::LocalUseMap localUses) { + QTC_CHECK(isSemanticInfoValidExceptLocalUses()); + d->m_lastSemanticInfo.localUsesUpdated = true; + d->m_lastSemanticInfo.localUses = localUses; + }); - connect(&d->m_updateFunctionDeclDefLinkTimer, &QTimer::timeout, - this, &CppEditorWidget::updateFunctionDeclDefLinkNow); + connect(&d->m_localRenaming, &CppLocalRenaming::finished, [this] { + cppEditorDocument()->semanticRehighlight(); + }); + connect(&d->m_localRenaming, &CppLocalRenaming::processKeyPressNormally, + this, &CppEditorWidget::processKeyNormally); connect(this, SIGNAL(cursorPositionChanged()), d->m_cppEditorOutline, SLOT(updateIndex())); - // set up slots to document changes - connect(document(), SIGNAL(contentsChange(int,int,int)), - this, SLOT(onContentsChanged(int,int,int))); - // set up function declaration - definition link + d->m_updateFunctionDeclDefLinkTimer.setSingleShot(true); + d->m_updateFunctionDeclDefLinkTimer.setInterval(UPDATE_FUNCTION_DECL_DEF_LINK_INTERVAL); + connect(&d->m_updateFunctionDeclDefLinkTimer, SIGNAL(timeout()), + this, SLOT(updateFunctionDeclDefLinkNow())); connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateFunctionDeclDefLink())); connect(this, SIGNAL(textChanged()), this, SLOT(updateFunctionDeclDefLink())); - // set up the semantic highlighter - connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateUses())); - connect(this, SIGNAL(textChanged()), this, SLOT(updateUses())); + // set up the use highlighitng + connect(this, &CppEditorWidget::cursorPositionChanged, [this]() { + if (!d->m_localRenaming.isActive()) + d->m_useSelectionsUpdater.scheduleUpdate(); + }); + // Tool bar creation d->m_preprocessorButton = new QToolButton(this); d->m_preprocessorButton->setText(QLatin1String("#")); Core::Command *cmd = Core::ActionManager::command(Constants::OPEN_PREPROCESSOR_DIALOG); @@ -232,13 +222,25 @@ CppEditorWidget::CppEditorWidget(TextEditor::BaseTextDocumentPtr doc, CPPEditor connect(d->m_preprocessorButton, SIGNAL(clicked()), this, SLOT(showPreProcessorWidget())); insertExtraToolBarWidget(TextEditor::BaseTextEditorWidget::Left, d->m_preprocessorButton); insertExtraToolBarWidget(TextEditor::BaseTextEditorWidget::Left, d->m_cppEditorOutline->widget()); - setLanguageSettingsId(CppTools::Constants::CPP_SETTINGS_ID); } CppEditorWidget::~CppEditorWidget() { - if (d->m_modelManager) - d->m_modelManager->deleteCppEditorSupport(editor()); + // non-inline destructor, see section "Forward Declared Pointers" of QScopedPointer. +} + +CppEditorWidget *CppEditorWidget::duplicate(CPPEditor *editor) const +{ + QTC_ASSERT(editor, return 0); + + CppEditorWidget *widget = new CppEditorWidget(textDocumentPtr(), editor); + widget->updateSemanticInfo(semanticInfo()); + widget->updateFunctionDeclDefLink(); + widget->d->m_cppEditorOutline->update(); + const ExtraSelectionKind selectionKind = CodeWarningsSelection; + widget->setExtraSelections(selectionKind, extraSelections(selectionKind)); + + return widget; } CPPEditorDocument *CppEditorWidget::cppEditorDocument() const @@ -266,7 +268,7 @@ void CppEditorWidget::paste() void CppEditorWidget::cut() { - if (d->m_localRenaming.handlePaste()) + if (d->m_localRenaming.handleCut()) return; BaseTextEditorWidget::cut(); @@ -280,13 +282,27 @@ void CppEditorWidget::selectAll() BaseTextEditorWidget::selectAll(); } -/// \brief Called by \c CppEditorSupport when the document corresponding to the -/// file in this editor is updated. -void CppEditorWidget::onDocumentUpdated() +void CppEditorWidget::onCppDocumentUpdated() { d->m_cppEditorOutline->update(); } +void CppEditorWidget::onCodeWarningsUpdated(unsigned revision, + const QList<QTextEdit::ExtraSelection> selections) +{ + if (revision != documentRevision()) + return; + setExtraSelections(BaseTextEditorWidget::CodeWarningsSelection, selections); +} + +void CppEditorWidget::onIfdefedOutBlocksUpdated(unsigned revision, + const QList<TextEditor::BlockRange> ifdefedOutBlocks) +{ + if (revision != documentRevision()) + return; + setIfdefedOutBlocks(ifdefedOutBlocks); +} + void CppEditorWidget::findUsages() { if (!d->m_modelManager) @@ -325,140 +341,23 @@ void CppEditorWidget::renameUsages(const QString &replacement) } } -void CppEditorWidget::markSymbolsNow() -{ - QTC_ASSERT(d->m_referencesWatcher, return); - if (!d->m_referencesWatcher->isCanceled() - && d->m_referencesCursorPosition == position() - && d->m_referencesRevision == editorRevision()) { - const SemanticInfo info = d->m_lastSemanticInfo; - TranslationUnit *unit = info.doc->translationUnit(); - const QList<int> result = d->m_referencesWatcher->result(); - - QList<QTextEdit::ExtraSelection> selections; - - foreach (int index, result) { - unsigned line, column; - unit->getTokenPosition(index, &line, &column); - - if (column) - --column; // adjust the column position. - - const int len = unit->tokenAt(index).utf16chars(); - - QTextCursor cursor(document()->findBlockByNumber(line - 1)); - cursor.setPosition(cursor.position() + column); - cursor.setPosition(cursor.position() + len, QTextCursor::KeepAnchor); - - QTextEdit::ExtraSelection sel; - sel.format = textCharFormat(TextEditor::C_OCCURRENCES); - sel.cursor = cursor; - selections.append(sel); - } - - setExtraSelections(CodeSemanticsSelection, selections); - } - d->m_referencesWatcher.reset(); -} - -static QList<int> lazyFindReferences(Scope *scope, QString code, Document::Ptr doc, - Snapshot snapshot) -{ - TypeOfExpression typeOfExpression; - snapshot.insert(doc); - typeOfExpression.init(doc, snapshot); - // make possible to instantiate templates - typeOfExpression.setExpandTemplates(true); - if (Symbol *canonicalSymbol = CanonicalSymbol::canonicalSymbol(scope, code, typeOfExpression)) - return CppModelManagerInterface::instance()->references(canonicalSymbol, - typeOfExpression.context()); - return QList<int>(); -} - -void CppEditorWidget::markSymbols(const QTextCursor &tc, const SemanticInfo &info) -{ - d->m_localRenaming.stop(); - - if (!info.doc) - return; - const QTextCharFormat &occurrencesFormat = textCharFormat(TextEditor::C_OCCURRENCES); - if (const Macro *macro = CppTools::findCanonicalMacro(textCursor(), info.doc)) { - QList<QTextEdit::ExtraSelection> selections; - - //Macro definition - if (macro->fileName() == info.doc->fileName()) { - QTextCursor cursor(document()); - cursor.setPosition(macro->utf16CharOffset()); - cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, - macro->nameToQString().size()); - - QTextEdit::ExtraSelection sel; - sel.format = occurrencesFormat; - sel.cursor = cursor; - selections.append(sel); - } - - //Other macro uses - foreach (const Document::MacroUse &use, info.doc->macroUses()) { - const Macro &useMacro = use.macro(); - if (useMacro.line() != macro->line() - || useMacro.utf16CharOffset() != macro->utf16CharOffset() - || useMacro.length() != macro->length() - || useMacro.fileName() != macro->fileName()) - continue; - - QTextCursor cursor(document()); - cursor.setPosition(use.utf16charsBegin()); - cursor.setPosition(use.utf16charsEnd(), QTextCursor::KeepAnchor); - - QTextEdit::ExtraSelection sel; - sel.format = occurrencesFormat; - sel.cursor = cursor; - selections.append(sel); - } - - setExtraSelections(CodeSemanticsSelection, selections); - } else { - CanonicalSymbol cs(info.doc, info.snapshot); - QString expression; - if (Scope *scope = cs.getScopeAndExpression(tc, &expression)) { - if (d->m_referencesWatcher) - d->m_referencesWatcher->cancel(); - d->m_referencesWatcher.reset(new QFutureWatcher<QList<int> >); - connect(d->m_referencesWatcher.data(), SIGNAL(finished()), SLOT(markSymbolsNow())); - - d->m_referencesRevision = info.revision; - d->m_referencesCursorPosition = position(); - d->m_referencesWatcher->setFuture( - QtConcurrent::run(&lazyFindReferences, scope, expression, info.doc, info.snapshot)); - } else { - const QList<QTextEdit::ExtraSelection> selections = extraSelections(CodeSemanticsSelection); - - if (!selections.isEmpty()) - setExtraSelections(CodeSemanticsSelection, QList<QTextEdit::ExtraSelection>()); - } - } -} - void CppEditorWidget::renameSymbolUnderCursor() { - if (!d->m_modelManager) - return; + updateSemanticInfo(d->m_cppEditorDocument->recalculateSemanticInfo()); - CppEditorSupport *ces = d->m_modelManager->cppEditorSupport(editor()); - updateSemanticInfo(ces->recalculateSemanticInfo()); + d->m_useSelectionsUpdater.abortSchedule(); - if (!d->m_localRenaming.start()) // Rename local symbol - renameUsages(); // Rename non-local symbol or macro -} - -void CppEditorWidget::onContentsChanged(int position, int charsRemoved, int charsAdded) -{ - Q_UNUSED(position) - Q_UNUSED(charsAdded) + // Trigger once the use selections updater is finished and thus has updated + // the use selections for the local renaming + QSharedPointer<QMetaObject::Connection> connection(new QMetaObject::Connection); + *connection.data() = connect(&d->m_useSelectionsUpdater, &CppUseSelectionsUpdater::finished, + [this, connection] () { + QObject::disconnect(*connection); + if (!d->m_localRenaming.start()) // Rename local symbol + renameUsages(); // Rename non-local symbol or macro + }); - if (charsRemoved > 0) - updateUses(); + d->m_useSelectionsUpdater.update(); } void CppEditorWidget::updatePreprocessorButtonTooltip() @@ -469,80 +368,6 @@ void CppEditorWidget::updatePreprocessorButtonTooltip() d->m_preprocessorButton->setToolTip(cmd->action()->toolTip()); } -QList<QTextEdit::ExtraSelection> CppEditorWidget::createSelectionsFromUses( - const QList<SemanticInfo::Use> &uses) -{ - QList<QTextEdit::ExtraSelection> result; - const bool isUnused = uses.size() == 1; - - foreach (const SemanticInfo::Use &use, uses) { - if (use.isInvalid()) - continue; - - QTextEdit::ExtraSelection sel; - if (isUnused) - sel.format = textCharFormat(TextEditor::C_OCCURRENCES_UNUSED); - else - sel.format = textCharFormat(TextEditor::C_OCCURRENCES); - - const int position = document()->findBlockByNumber(use.line - 1).position() + use.column - 1; - const int anchor = position + use.length; - - sel.cursor = QTextCursor(document()); - sel.cursor.setPosition(anchor); - sel.cursor.setPosition(position, QTextCursor::KeepAnchor); - - result.append(sel); - } - - return result; -} - -void CppEditorWidget::updateUses() -{ - // Block premature semantic info calculation when editor is created. - if (d->m_modelManager && d->m_modelManager->cppEditorSupport(editor())->initialized()) - d->m_updateUsesTimer.start(); -} - -void CppEditorWidget::updateUsesNow() -{ - if (d->m_localRenaming.isActive()) - return; - - semanticRehighlight(); -} - -void CppEditorWidget::highlightSymbolUsages(int from, int to) -{ - if (editorRevision() != d->m_highlightRevision) - return; // outdated - - else if (!d->m_highlightWatcher || d->m_highlightWatcher->isCanceled()) - return; // aborted - - TextEditor::SyntaxHighlighter *highlighter = textDocument()->syntaxHighlighter(); - QTC_ASSERT(highlighter, return); - - TextEditor::SemanticHighlighter::incrementalApplyExtraAdditionalFormats( - highlighter, d->m_highlightWatcher->future(), from, to, d->m_semanticHighlightFormatMap); -} - -void CppEditorWidget::finishHighlightSymbolUsages() -{ - QTC_ASSERT(d->m_highlightWatcher, return); - if (!d->m_highlightWatcher->isCanceled() - && editorRevision() == d->m_highlightRevision - && !d->m_lastSemanticInfo.doc.isNull()) { - TextEditor::SyntaxHighlighter *highlighter = textDocument()->syntaxHighlighter(); - QTC_CHECK(highlighter); - if (highlighter) - TextEditor::SemanticHighlighter::clearExtraAdditionalFormatsUntilEnd(highlighter, - d->m_highlightWatcher->future()); - } - d->m_highlightWatcher.reset(); -} - void CppEditorWidget::switchDeclarationDefinition(bool inNextSplit) { if (!d->m_modelManager) @@ -624,17 +449,19 @@ CppEditorWidget::Link CppEditorWidget::findLinkAt(const QTextCursor &cursor, boo inNextSplit); } -unsigned CppEditorWidget::editorRevision() const +unsigned CppEditorWidget::documentRevision() const { return document()->revision(); } -bool CppEditorWidget::isOutdated() const +bool CppEditorWidget::isSemanticInfoValidExceptLocalUses() const { - if (d->m_lastSemanticInfo.revision != editorRevision()) - return true; + return d->m_lastSemanticInfo.doc && d->m_lastSemanticInfo.revision == documentRevision(); +} - return false; +bool CppEditorWidget::isSemanticInfoValid() const +{ + return isSemanticInfoValidExceptLocalUses() && d->m_lastSemanticInfo.localUsesUpdated; } SemanticInfo CppEditorWidget::semanticInfo() const @@ -665,6 +492,11 @@ void CppEditorWidget::performQuickFix(int index) op->perform(); } +void CppEditorWidget::processKeyNormally(QKeyEvent *e) +{ + BaseTextEditorWidget::keyPressEvent(e); +} + void CppEditorWidget::contextMenuEvent(QContextMenuEvent *e) { // ### enable @@ -681,7 +513,7 @@ void CppEditorWidget::contextMenuEvent(QContextMenuEvent *e) QSignalMapper mapper; connect(&mapper, SIGNAL(mapped(int)), this, SLOT(performQuickFix(int))); - if (!isOutdated()) { + if (isSemanticInfoValid()) { TextEditor::IAssistInterface *interface = createAssistInterface(TextEditor::QuickFix, TextEditor::ExplicitlyInvoked); if (interface) { @@ -735,7 +567,7 @@ void CppEditorWidget::keyPressEvent(QKeyEvent *e) Core::IEditor *CPPEditor::duplicate() { CPPEditor *editor = new CPPEditor; - CppEditorWidget *widget = new CppEditorWidget(editorWidget()->textDocumentPtr(), editor); + CppEditorWidget *widget = qobject_cast<CppEditorWidget *>(editorWidget())->duplicate(editor); CppEditorPlugin::instance()->initializeEditor(widget); editor->configureCodeAssistant(); return editor; @@ -751,32 +583,8 @@ bool CPPEditor::open(QString *errorString, const QString &fileName, const QStrin void CppEditorWidget::applyFontSettings() { - const TextEditor::FontSettings &fs = textDocument()->fontSettings(); - - d->m_semanticHighlightFormatMap[CppHighlightingSupport::TypeUse] = - fs.toTextCharFormat(TextEditor::C_TYPE); - d->m_semanticHighlightFormatMap[CppHighlightingSupport::LocalUse] = - fs.toTextCharFormat(TextEditor::C_LOCAL); - d->m_semanticHighlightFormatMap[CppHighlightingSupport::FieldUse] = - fs.toTextCharFormat(TextEditor::C_FIELD); - d->m_semanticHighlightFormatMap[CppHighlightingSupport::EnumerationUse] = - fs.toTextCharFormat(TextEditor::C_ENUMERATION); - d->m_semanticHighlightFormatMap[CppHighlightingSupport::VirtualMethodUse] = - fs.toTextCharFormat(TextEditor::C_VIRTUAL_METHOD); - d->m_semanticHighlightFormatMap[CppHighlightingSupport::LabelUse] = - fs.toTextCharFormat(TextEditor::C_LABEL); - d->m_semanticHighlightFormatMap[CppHighlightingSupport::MacroUse] = - fs.toTextCharFormat(TextEditor::C_PREPROCESSOR); - d->m_semanticHighlightFormatMap[CppHighlightingSupport::FunctionUse] = - fs.toTextCharFormat(TextEditor::C_FUNCTION); - d->m_semanticHighlightFormatMap[CppHighlightingSupport::PseudoKeywordUse] = - fs.toTextCharFormat(TextEditor::C_KEYWORD); - d->m_semanticHighlightFormatMap[CppHighlightingSupport::StringUse] = - fs.toTextCharFormat(TextEditor::C_STRING); - - // this also makes the document apply font settings + // This also makes the document apply font settings TextEditor::BaseTextEditorWidget::applyFontSettings(); - semanticRehighlight(true); } void CppEditorWidget::slotCodeStyleSettingsChanged(const QVariant &) @@ -820,84 +628,15 @@ bool CppEditorWidget::openCppEditorAt(const Link &link, bool inNextSplit) flags); } -void CppEditorWidget::semanticRehighlight(bool force) -{ - if (d->m_modelManager) { - const CppEditorSupport::ForceReason forceReason = force - ? CppEditorSupport::ForceDueEditorRequest - : CppEditorSupport::NoForce; - d->m_modelManager->cppEditorSupport(editor())->recalculateSemanticInfoDetached(forceReason); - } -} - -void CppEditorWidget::highlighterStarted(QFuture<TextEditor::HighlightingResult> *highlighter, - unsigned revision) -{ - d->m_highlightRevision = revision; - - d->m_highlightWatcher.reset(new QFutureWatcher<TextEditor::HighlightingResult>); - connect(d->m_highlightWatcher.data(), SIGNAL(resultsReadyAt(int,int)), - SLOT(highlightSymbolUsages(int,int))); - connect(d->m_highlightWatcher.data(), SIGNAL(finished()), - SLOT(finishHighlightSymbolUsages())); - - d->m_highlightWatcher->setFuture(QFuture<TextEditor::HighlightingResult>(*highlighter)); -} - void CppEditorWidget::updateSemanticInfo(const SemanticInfo &semanticInfo) { - if (semanticInfo.revision != editorRevision()) { - // got outdated semantic info - semanticRehighlight(); + if (semanticInfo.revision != documentRevision()) return; - } - - d->m_lastSemanticInfo = semanticInfo; // update the semantic info - - int line = 0, column = 0; - convertPosition(position(), &line, &column); - QList<QTextEdit::ExtraSelection> unusedSelections; - QList<QTextEdit::ExtraSelection> selections; + d->m_lastSemanticInfo = semanticInfo; - // We can use the semanticInfo's snapshot (and avoid locking), but not its - // document, since it doesn't contain expanded macros. - LookupContext context(semanticInfo.snapshot.document(textDocument()->filePath()), - semanticInfo.snapshot); - - SemanticInfo::LocalUseIterator it(semanticInfo.localUses); - while (it.hasNext()) { - it.next(); - const QList<SemanticInfo::Use> &uses = it.value(); - - bool good = false; - foreach (const SemanticInfo::Use &use, uses) { - unsigned l = line; - unsigned c = column + 1; // convertCursorPosition() returns a 0-based column number. - if (l == use.line && c >= use.column && c <= (use.column + use.length)) { - good = true; - break; - } - } - - if (uses.size() == 1) { - if (!CppTools::isOwnershipRAIIType(it.key(), context)) - unusedSelections << createSelectionsFromUses(uses); // unused declaration - } else if (good && selections.isEmpty()) { - selections << createSelectionsFromUses(uses); - } - } - - setExtraSelections(UnusedSymbolSelection, unusedSelections); - - if (!selections.isEmpty()) { - setExtraSelections(CodeSemanticsSelection, selections); - d->m_localRenaming.updateLocalUseSelections(selections); - } else { - markSymbols(textCursor(), semanticInfo); - } - - d->m_lastSemanticInfo.forced = false; // clear the forced flag + if (!d->m_localRenaming.isActive()) + d->m_useSelectionsUpdater.update(); // schedule a check for a decl/def link updateFunctionDeclDefLink(); @@ -908,16 +647,17 @@ TextEditor::IAssistInterface *CppEditorWidget::createAssistInterface( TextEditor::AssistReason reason) const { if (kind == TextEditor::Completion) { - CppEditorSupport *ces = CppModelManagerInterface::instance()->cppEditorSupport(editor()); - CppCompletionAssistProvider *cap = ces->completionAssistProvider(); - if (cap) { + if (CppCompletionAssistProvider *cap = cppEditorDocument()->completionAssistProvider()) { return cap->createAssistInterface( ProjectExplorer::ProjectExplorerPlugin::currentProject(), - editor(), document(), cppEditorDocument()->isObjCEnabled(), position(), + textDocument()->filePath(), + document(), + cppEditorDocument()->isObjCEnabled(), + position(), reason); } } else if (kind == TextEditor::QuickFix) { - if (!semanticInfo().doc || isOutdated()) + if (!isSemanticInfoValid()) return 0; return new CppQuickFixAssistInterface(const_cast<CppEditorWidget *>(this), reason); } else { @@ -967,8 +707,10 @@ void CppEditorWidget::updateFunctionDeclDefLinkNow() { if (Core::EditorManager::currentEditor() != editor()) return; + const Snapshot semanticSnapshot = d->m_lastSemanticInfo.snapshot; const Document::Ptr semanticDoc = d->m_lastSemanticInfo.doc; + if (d->m_declDefLink) { // update the change marker const Utils::ChangeSet changes = d->m_declDefLink->changes(semanticSnapshot); @@ -978,7 +720,8 @@ void CppEditorWidget::updateFunctionDeclDefLinkNow() d->m_declDefLink->showMarker(this); return; } - if (semanticDoc.isNull() || isOutdated()) + + if (!isSemanticInfoValidExceptLocalUses()) return; Snapshot snapshot = CppModelManagerInterface::instance()->snapshot(); @@ -1012,8 +755,8 @@ void CppEditorWidget::onFilePathChanged() additionalDirectives = ProjectExplorer::SessionManager::value( projectFile + QLatin1Char(',') + filePath).toString().toUtf8(); - BuiltinEditorDocumentParser::Ptr parser - = d->m_modelManager->cppEditorSupport(editor())->documentParser(); + BaseEditorDocumentParser *parser = BaseEditorDocumentParser::get(filePath); + QTC_ASSERT(parser, return); parser->setProjectPart(d->m_modelManager->projectPartForProjectFile(projectFile)); parser->setEditorDefines(additionalDirectives); } @@ -1052,21 +795,6 @@ void CppEditorWidget::abortDeclDefLink() d->m_declDefLink.clear(); } -void CppEditorWidget::onLocalRenamingFinished() -{ - semanticRehighlight(true); -} - -void CppEditorWidget::onLocalRenamingProcessKeyPressNormally(QKeyEvent *e) -{ - BaseTextEditorWidget::keyPressEvent(e); -} - -QTextCharFormat CppEditorWidget::textCharFormat(TextEditor::TextStyle category) -{ - return textDocument()->fontSettings().toTextCharFormat(category); -} - void CppEditorWidget::showPreProcessorWidget() { const QString &fileName = editor()->document()->filePath(); @@ -1080,8 +808,8 @@ void CppEditorWidget::showPreProcessorWidget() CppPreProcessorDialog preProcessorDialog(this, textDocument()->filePath(), projectParts); if (preProcessorDialog.exec() == QDialog::Accepted) { - BuiltinEditorDocumentParser::Ptr parser - = d->m_modelManager->cppEditorSupport(editor())->documentParser(); + BaseEditorDocumentParser *parser = BaseEditorDocumentParser::get(fileName); + QTC_ASSERT(parser, return); const QString &additionals = preProcessorDialog.additionalPreProcessorDirectives(); parser->setProjectPart(preProcessorDialog.projectPart()); parser->setEditorDefines(additionals.toUtf8()); diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h index d7c6df96f3..fcf09325b5 100644 --- a/src/plugins/cppeditor/cppeditor.h +++ b/src/plugins/cppeditor/cppeditor.h @@ -30,16 +30,11 @@ #ifndef CPPEDITOR_H #define CPPEDITOR_H -#include "cppeditordocument.h" - #include "cppfunctiondecldeflink.h" #include <texteditor/basetexteditor.h> -#include <texteditor/semantichighlighter.h> -#include <texteditor/texteditorconstants.h> #include <utils/qtcoverride.h> -#include <utils/uncommentselection.h> #include <QScopedPointer> @@ -49,9 +44,11 @@ namespace CppTools { class SemanticInfo; } namespace CppEditor { namespace Internal { +class CPPEditorDocument; class CppEditorOutline; class CppEditorWidgetPrivate; class FollowSymbolUnderCursor; +class FunctionDeclDefLink; class CPPEditor : public TextEditor::BaseTextEditor { @@ -78,10 +75,14 @@ public: CppEditorWidget(TextEditor::BaseTextDocumentPtr doc, CPPEditor *editor); ~CppEditorWidget(); + CppEditorWidget *duplicate(CPPEditor *editor) const; + CPPEditorDocument *cppEditorDocument() const; CppEditorOutline *outline() const; CppTools::SemanticInfo semanticInfo() const; + bool isSemanticInfoValidExceptLocalUses() const; + bool isSemanticInfoValid() const; QSharedPointer<FunctionDeclDefLink> declDefLink() const; void applyDeclDefLinkChanges(bool jumpToMatch); @@ -104,10 +105,6 @@ public slots: void renameSymbolUnderCursor(); void renameUsages(const QString &replacement = QString()); - void semanticRehighlight(bool force = false); - void highlighterStarted(QFuture<TextEditor::HighlightingResult> *highlighter, - unsigned revision); - protected: bool event(QEvent *e) QTC_OVERRIDE; void contextMenuEvent(QContextMenuEvent *) QTC_OVERRIDE; @@ -126,40 +123,31 @@ protected slots: void slotCodeStyleSettingsChanged(const QVariant &) QTC_OVERRIDE; private slots: - void updateUses(); - void updateUsesNow(); void updateFunctionDeclDefLink(); void updateFunctionDeclDefLinkNow(); + void abortDeclDefLink(); + void onRefactorMarkerClicked(const TextEditor::RefactorMarker &marker); void onFunctionDeclDefLinkFound(QSharedPointer<FunctionDeclDefLink> link); + void onFilePathChanged(); - void onDocumentUpdated(); - void onContentsChanged(int position, int charsRemoved, int charsAdded); - void updatePreprocessorButtonTooltip(); + void onCppDocumentUpdated(); + + void onCodeWarningsUpdated(unsigned revision, + const QList<QTextEdit::ExtraSelection> selections); + void onIfdefedOutBlocksUpdated(unsigned revision, + const QList<TextEditor::BlockRange> ifdefedOutBlocks); void updateSemanticInfo(const CppTools::SemanticInfo &semanticInfo); - void highlightSymbolUsages(int from, int to); - void finishHighlightSymbolUsages(); + void updatePreprocessorButtonTooltip(); - void markSymbolsNow(); void performQuickFix(int index); - void onRefactorMarkerClicked(const TextEditor::RefactorMarker &marker); - void abortDeclDefLink(); - void onLocalRenamingFinished(); - void onLocalRenamingProcessKeyPressNormally(QKeyEvent *e); + void processKeyNormally(QKeyEvent *e); private: static bool openCppEditorAt(const Link &, bool inNextSplit = false); - unsigned editorRevision() const; - bool isOutdated() const; - - QTextCharFormat textCharFormat(TextEditor::TextStyle category); - - void markSymbols(const QTextCursor &tc, const CppTools::SemanticInfo &info); - - QList<QTextEdit::ExtraSelection> createSelectionsFromUses( - const QList<TextEditor::HighlightingResult> &uses); + unsigned documentRevision() const; private: QScopedPointer<CppEditorWidgetPrivate> d; diff --git a/src/plugins/cppeditor/cppeditor.pro b/src/plugins/cppeditor/cppeditor.pro index f85c581fb9..cba69a39f3 100644 --- a/src/plugins/cppeditor/cppeditor.pro +++ b/src/plugins/cppeditor/cppeditor.pro @@ -33,6 +33,7 @@ HEADERS += \ cppquickfixes.h \ cppsnippetprovider.h \ cpptypehierarchy.h \ + cppuseselectionsupdater.h \ cppvirtualfunctionassistprovider.h \ cppvirtualfunctionproposalitem.h @@ -65,6 +66,7 @@ SOURCES += \ cppquickfixes.cpp \ cppsnippetprovider.cpp \ cpptypehierarchy.cpp \ + cppuseselectionsupdater.cpp \ cppvirtualfunctionassistprovider.cpp \ cppvirtualfunctionproposalitem.cpp diff --git a/src/plugins/cppeditor/cppeditor.qbs b/src/plugins/cppeditor/cppeditor.qbs index 5d6b52aa39..ea5ae12f04 100644 --- a/src/plugins/cppeditor/cppeditor.qbs +++ b/src/plugins/cppeditor/cppeditor.qbs @@ -52,6 +52,7 @@ QtcPlugin { "cppquickfixes.cpp", "cppquickfixes.h", "cppsnippetprovider.cpp", "cppsnippetprovider.h", "cpptypehierarchy.cpp", "cpptypehierarchy.h", + "cppuseselectionsupdater.cpp", "cppuseselectionsupdater.h", "cppvirtualfunctionassistprovider.cpp", "cppvirtualfunctionassistprovider.h", "cppvirtualfunctionproposalitem.cpp", "cppvirtualfunctionproposalitem.h", ] diff --git a/src/plugins/cppeditor/cppeditordocument.cpp b/src/plugins/cppeditor/cppeditordocument.cpp index d91126f84b..2b79e2a991 100644 --- a/src/plugins/cppeditor/cppeditordocument.cpp +++ b/src/plugins/cppeditor/cppeditordocument.cpp @@ -32,25 +32,87 @@ #include "cppeditorconstants.h" #include "cpphighlighter.h" +#include <cpptools/builtineditordocumentprocessor.h> #include <cpptools/cppcodeformatter.h> +#include <cpptools/cppcodemodelsettings.h> +#include <cpptools/cppmodelmanagerinterface.h> #include <cpptools/cppqtstyleindenter.h> #include <cpptools/cpptoolsconstants.h> +#include <cpptools/cpptoolsplugin.h> + +#include <utils/qtcassert.h> +#include <utils/runextensions.h> #include <QTextDocument> +namespace { + +CppTools::CppModelManagerInterface *mm() +{ + return CppTools::CppModelManagerInterface::instance(); +} + +} // anonymous namespace + namespace CppEditor { namespace Internal { +enum { processDocumentIntervalInMs = 150 }; + +class CppEditorDocumentHandle : public CppTools::EditorDocumentHandle +{ +public: + CppEditorDocumentHandle(CppEditor::Internal::CPPEditorDocument *cppEditorDocument) + : m_cppEditorDocument(cppEditorDocument) + , m_registrationFilePath(cppEditorDocument->filePath()) + { + mm()->registerEditorDocument(this); + } + + ~CppEditorDocumentHandle() { mm()->unregisterEditorDocument(m_registrationFilePath); } + + QString filePath() const { return m_cppEditorDocument->filePath(); } + QByteArray contents() const { return m_cppEditorDocument->contentsText(); } + unsigned revision() const { return m_cppEditorDocument->contentsRevision(); } + + CppTools::BaseEditorDocumentProcessor *processor() + { return m_cppEditorDocument->processor(); } + +private: + CppEditor::Internal::CPPEditorDocument * const m_cppEditorDocument; + // The file path of the editor document can change (e.g. by "Save As..."), so make sure + // that un-registration happens with the path the document was registered. + const QString m_registrationFilePath; +}; + CPPEditorDocument::CPPEditorDocument() + : m_fileIsBeingReloaded(false) + , m_isObjCEnabled(false) + , m_cachedContentsRevision(-1) + , m_processorRevision(0) + , m_completionAssistProvider(0) { setId(CppEditor::Constants::CPPEDITOR_ID); - connect(this, SIGNAL(tabSettingsChanged()), - this, SLOT(invalidateFormatterCache())); - connect(this, SIGNAL(mimeTypeChanged()), - this, SLOT(onMimeTypeChanged())); setSyntaxHighlighter(new CppHighlighter); setIndenter(new CppTools::CppQtStyleIndenter); - onMimeTypeChanged(); + + connect(this, SIGNAL(tabSettingsChanged()), this, SLOT(invalidateFormatterCache())); + connect(this, SIGNAL(mimeTypeChanged()), this, SLOT(onMimeTypeChanged())); + + connect(this, SIGNAL(aboutToReload()), this, SLOT(onAboutToReload())); + connect(this, SIGNAL(reloadFinished(bool)), this, SLOT(onReloadFinished())); + connect(this, SIGNAL(filePathChanged(QString,QString)), + this, SLOT(onFilePathChanged(QString,QString))); + + m_processorTimer.setSingleShot(true); + m_processorTimer.setInterval(processDocumentIntervalInMs); + connect(&m_processorTimer, SIGNAL(timeout()), this, SLOT(processDocument())); + + // See also onFilePathChanged() for more initialization +} + +CPPEditorDocument::~CPPEditorDocument() +{ } bool CPPEditorDocument::isObjCEnabled() const @@ -58,6 +120,38 @@ bool CPPEditorDocument::isObjCEnabled() const return m_isObjCEnabled; } +CppTools::CppCompletionAssistProvider *CPPEditorDocument::completionAssistProvider() const +{ + return m_completionAssistProvider; +} + +void CPPEditorDocument::semanticRehighlight() +{ + CppTools::BaseEditorDocumentProcessor *p = processor(); + QTC_ASSERT(p, return); + p->semanticRehighlight(true); +} + +CppTools::SemanticInfo CPPEditorDocument::recalculateSemanticInfo() +{ + CppTools::BaseEditorDocumentProcessor *p = processor(); + QTC_ASSERT(p, CppTools::SemanticInfo()); + return p->recalculateSemanticInfo(); +} + +QByteArray CPPEditorDocument::contentsText() const +{ + QMutexLocker locker(&m_cachedContentsLock); + + const int currentRevision = document()->revision(); + if (m_cachedContentsRevision != currentRevision && !m_fileIsBeingReloaded) { + m_cachedContentsRevision = currentRevision; + m_cachedContents = plainText().toUtf8(); + } + + return m_cachedContents; +} + void CPPEditorDocument::applyFontSettings() { if (TextEditor::SyntaxHighlighter *highlighter = syntaxHighlighter()) { @@ -82,7 +176,94 @@ void CPPEditorDocument::onMimeTypeChanged() { const QString &mt = mimeType(); m_isObjCEnabled = (mt == QLatin1String(CppTools::Constants::OBJECTIVE_C_SOURCE_MIMETYPE) - || mt == QLatin1String(CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE)); + || mt == QLatin1String(CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE)); + m_completionAssistProvider = mm()->completionAssistProvider(mt); +} + +void CPPEditorDocument::onAboutToReload() +{ + QTC_CHECK(!m_fileIsBeingReloaded); + m_fileIsBeingReloaded = true; +} + +void CPPEditorDocument::onReloadFinished() +{ + QTC_CHECK(m_fileIsBeingReloaded); + m_fileIsBeingReloaded = false; +} + +void CPPEditorDocument::onFilePathChanged(const QString &oldPath, const QString &newPath) +{ + Q_UNUSED(oldPath); + + if (!newPath.isEmpty()) { + setMimeType(Core::MimeDatabase::findByFile(QFileInfo(newPath)).type()); + + disconnect(this, SIGNAL(contentsChanged()), this, SLOT(scheduleProcessDocument())); + connect(this, SIGNAL(contentsChanged()), this, SLOT(scheduleProcessDocument())); + + // Un-Register/Register in ModelManager + m_editorDocumentHandle.reset(new CppEditorDocumentHandle(this)); + + resetProcessor(); + m_processorRevision = document()->revision(); + processDocument(); + } +} + +void CPPEditorDocument::scheduleProcessDocument() +{ + m_processorRevision = document()->revision(); + m_processorTimer.start(processDocumentIntervalInMs); +} + +void CPPEditorDocument::processDocument() +{ + if (processor()->isParserRunning() || m_processorRevision != contentsRevision()) { + m_processorTimer.start(); + return; + } + + m_processorTimer.stop(); + if (m_fileIsBeingReloaded || filePath().isEmpty()) + return; + + processor()->run(); +} + +void CPPEditorDocument::resetProcessor() +{ + releaseResources(); + processor(); // creates a new processor +} + +unsigned CPPEditorDocument::contentsRevision() const +{ + return document()->revision(); +} + +void CPPEditorDocument::releaseResources() +{ + if (m_processor) + disconnect(m_processor.data(), 0, this, 0); + m_processor.reset(); +} + +CppTools::BaseEditorDocumentProcessor *CPPEditorDocument::processor() +{ + if (!m_processor) { + m_processor.reset(mm()->editorDocumentProcessor(this)); + connect(m_processor.data(), &CppTools::BaseEditorDocumentProcessor::codeWarningsUpdated, + this, &CPPEditorDocument::codeWarningsUpdated); + connect(m_processor.data(), &CppTools::BaseEditorDocumentProcessor::ifdefedOutBlocksUpdated, + this, &CPPEditorDocument::ifdefedOutBlocksUpdated); + connect(m_processor.data(), &CppTools::BaseEditorDocumentProcessor::cppDocumentUpdated, + this, &CPPEditorDocument::cppDocumentUpdated); + connect(m_processor.data(), &CppTools::BaseEditorDocumentProcessor::semanticInfoUpdated, + this, &CPPEditorDocument::semanticInfoUpdated); + } + + return m_processor.data(); } } // namespace Internal diff --git a/src/plugins/cppeditor/cppeditordocument.h b/src/plugins/cppeditor/cppeditordocument.h index 8e2d8ec3f2..5db4c9375c 100644 --- a/src/plugins/cppeditor/cppeditordocument.h +++ b/src/plugins/cppeditor/cppeditordocument.h @@ -30,28 +30,85 @@ #ifndef CPPEDITORDOCUMENT_H #define CPPEDITORDOCUMENT_H +#include <cpptools/baseeditordocumentprocessor.h> +#include <cpptools/cppcompletionassistprovider.h> +#include <cpptools/cppmodelmanagerinterface.h> +#include <cpptools/cppsemanticinfo.h> +#include <cpptools/editordocumenthandle.h> + #include <texteditor/basetextdocument.h> +#include <QMutex> +#include <QTimer> + namespace CppEditor { namespace Internal { class CPPEditorDocument : public TextEditor::BaseTextDocument { Q_OBJECT + + friend class CppEditorDocumentHandle; + public: explicit CPPEditorDocument(); + ~CPPEditorDocument(); bool isObjCEnabled() const; + CppTools::CppCompletionAssistProvider *completionAssistProvider() const; + + void semanticRehighlight(); + CppTools::SemanticInfo recalculateSemanticInfo(); // TODO: Remove me + +signals: + void codeWarningsUpdated(unsigned contentsRevision, + const QList<QTextEdit::ExtraSelection> selections); + + void ifdefedOutBlocksUpdated(unsigned contentsRevision, + const QList<TextEditor::BlockRange> ifdefedOutBlocks); + + void cppDocumentUpdated(const CPlusPlus::Document::Ptr document); // TODO: Remove me + void semanticInfoUpdated(const CppTools::SemanticInfo semanticInfo); // TODO: Remove me protected: void applyFontSettings(); private slots: void invalidateFormatterCache(); + void onFilePathChanged(const QString &oldPath, const QString &newPath); void onMimeTypeChanged(); + void onAboutToReload(); + void onReloadFinished(); + + void scheduleProcessDocument(); + void processDocument(); + +private: + QByteArray contentsText() const; + unsigned contentsRevision() const; + + CppTools::BaseEditorDocumentProcessor *processor(); + void resetProcessor(); + void releaseResources(); + private: + bool m_fileIsBeingReloaded; bool m_isObjCEnabled; + + // Caching contents + mutable QMutex m_cachedContentsLock; + mutable QByteArray m_cachedContents; + mutable int m_cachedContentsRevision; + + unsigned m_processorRevision; + QTimer m_processorTimer; + QScopedPointer<CppTools::BaseEditorDocumentProcessor> m_processor; + + CppTools::CppCompletionAssistProvider *m_completionAssistProvider; + + // (Un)Registration in CppModelManager + QScopedPointer<CppTools::EditorDocumentHandle> m_editorDocumentHandle; }; } // namespace Internal diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp index 81e5e81653..f9d3c71a78 100644 --- a/src/plugins/cppeditor/cppeditorplugin.cpp +++ b/src/plugins/cppeditor/cppeditorplugin.cpp @@ -32,6 +32,7 @@ #include "cppclasswizard.h" #include "cppcodemodelinspectordialog.h" #include "cppeditorconstants.h" +#include "cppeditordocument.h" #include "cppeditor.h" #include "cppeditoroutline.h" #include "cppfilewizard.h" diff --git a/src/plugins/cppeditor/cppeditortestcase.cpp b/src/plugins/cppeditor/cppeditortestcase.cpp index 4bb20eedcc..5fca9581e8 100644 --- a/src/plugins/cppeditor/cppeditortestcase.cpp +++ b/src/plugins/cppeditor/cppeditortestcase.cpp @@ -31,8 +31,10 @@ #include "cppeditortestcase.h" #include "cppeditor.h" +#include "cppeditordocument.h" #include <coreplugin/editormanager/editormanager.h> +#include <cpptools/baseeditordocumentprocessor.h> #include <cpptools/cppsemanticinfo.h> #include <cplusplus/CppDocument.h> @@ -87,8 +89,10 @@ bool TestCase::openCppEditor(const QString &fileName, CPlusPlus::Document::Ptr TestCase::waitForRehighlightedSemanticDocument( Internal::CppEditorWidget *editorWidget) { - editorWidget->semanticRehighlight(true); - while (editorWidget->semanticInfo().doc.isNull()) + const QString filePath = editorWidget->textDocument()->filePath(); + auto processor = CppTools::BaseEditorDocumentProcessor::get(filePath); + processor->semanticRehighlight(false); + while (!editorWidget->isSemanticInfoValid()) QCoreApplication::processEvents(); return editorWidget->semanticInfo().doc; } diff --git a/src/plugins/cppeditor/cppincludehierarchymodel.cpp b/src/plugins/cppeditor/cppincludehierarchymodel.cpp index ac5e2e26e6..0dfde59238 100644 --- a/src/plugins/cppeditor/cppincludehierarchymodel.cpp +++ b/src/plugins/cppeditor/cppincludehierarchymodel.cpp @@ -32,8 +32,9 @@ #include "cppincludehierarchyitem.h" #include <coreplugin/fileiconprovider.h> +#include <cpptools/builtineditordocumentparser.h> #include <cpptools/cppmodelmanagerinterface.h> -#include <cpptools/cpptoolseditorsupport.h> +#include <cpptools/editordocumenthandle.h> #include <texteditor/basetexteditor.h> #include <cplusplus/CppDocument.h> @@ -43,6 +44,15 @@ using namespace CPlusPlus; using namespace CppTools; +namespace { + +Snapshot globalSnapshot() +{ + return CppTools::CppModelManagerInterface::instance()->snapshot(); +} + +} // anonymous namespace + namespace CppEditor { namespace Internal { @@ -161,18 +171,24 @@ void CppIncludeHierarchyModel::fetchMore(const QModelIndex &parent) return; if (parentItem->needChildrenPopulate()) { + const QString editorFilePath = m_editor->document()->filePath(); QSet<QString> cyclic; - cyclic << m_editor->document()->filePath(); + cyclic << editorFilePath; CppIncludeHierarchyItem *item = parentItem->parent(); while (!(item == m_includesItem || item == m_includedByItem)) { cyclic << item->filePath(); item = item->parent(); } - if (item == m_includesItem) - buildHierarchyIncludes_helper(parentItem->filePath(), parentItem, &cyclic); - else - buildHierarchyIncludedBy_helper(parentItem->filePath(), parentItem, &cyclic); + if (item == m_includesItem) { + const Snapshot editorDocumentSnapshot + = BuiltinEditorDocumentParser::get(editorFilePath)->snapshot(); + buildHierarchyIncludes_helper(parentItem->filePath(), parentItem, + editorDocumentSnapshot, &cyclic); + } else { + buildHierarchyIncludedBy_helper(parentItem->filePath(), parentItem, + globalSnapshot(), &cyclic); + } } } @@ -231,19 +247,21 @@ bool CppIncludeHierarchyModel::isEmpty() const void CppIncludeHierarchyModel::buildHierarchyIncludes(const QString ¤tFilePath) { + if (!m_editor) + return; + + const QString editorFilePath = m_editor->document()->filePath(); + const Snapshot snapshot = BuiltinEditorDocumentParser::get(editorFilePath)->snapshot(); QSet<QString> cyclic; - buildHierarchyIncludes_helper(currentFilePath, m_includesItem, &cyclic); + buildHierarchyIncludes_helper(currentFilePath, m_includesItem, snapshot, &cyclic); } void CppIncludeHierarchyModel::buildHierarchyIncludes_helper(const QString &filePath, CppIncludeHierarchyItem *parent, - QSet<QString> *cyclic, bool recursive) + Snapshot snapshot, + QSet<QString> *cyclic, + bool recursive) { - if (!m_editor) - return; - - CppModelManagerInterface *cppMM = CppModelManagerInterface::instance(); - const Snapshot &snapshot = cppMM->cppEditorSupport(m_editor)->documentParser()->snapshot(); Document::Ptr doc = snapshot.document(filePath); if (!doc) return; @@ -265,7 +283,7 @@ void CppIncludeHierarchyModel::buildHierarchyIncludes_helper(const QString &file } item = new CppIncludeHierarchyItem(includedFilePath, parent); parent->appendChild(item); - buildHierarchyIncludes_helper(includedFilePath, item, cyclic, false); + buildHierarchyIncludes_helper(includedFilePath, item, snapshot, cyclic, false); } cyclic->remove(filePath); @@ -274,16 +292,16 @@ void CppIncludeHierarchyModel::buildHierarchyIncludes_helper(const QString &file void CppIncludeHierarchyModel::buildHierarchyIncludedBy(const QString ¤tFilePath) { QSet<QString> cyclic; - buildHierarchyIncludedBy_helper(currentFilePath, m_includedByItem, &cyclic); + buildHierarchyIncludedBy_helper(currentFilePath, m_includedByItem, globalSnapshot(), &cyclic); } void CppIncludeHierarchyModel::buildHierarchyIncludedBy_helper(const QString &filePath, CppIncludeHierarchyItem *parent, + Snapshot snapshot, QSet<QString> *cyclic, bool recursive) { cyclic->insert(filePath); - const Snapshot &snapshot = CppTools::CppModelManagerInterface::instance()->snapshot(); Snapshot::const_iterator citEnd = snapshot.end(); for (Snapshot::const_iterator cit = snapshot.begin(); cit != citEnd; ++cit) { const QString filePathFromSnapshot = cit.key(); @@ -307,8 +325,9 @@ void CppIncludeHierarchyModel::buildHierarchyIncludedBy_helper(const QString &fi if (isCyclic) continue; - else - buildHierarchyIncludedBy_helper(filePathFromSnapshot, item, cyclic, false); + + buildHierarchyIncludedBy_helper(filePathFromSnapshot, item, snapshot, cyclic, + false); } } } diff --git a/src/plugins/cppeditor/cppincludehierarchymodel.h b/src/plugins/cppeditor/cppincludehierarchymodel.h index 4a96cbe7a1..146c9fc031 100644 --- a/src/plugins/cppeditor/cppincludehierarchymodel.h +++ b/src/plugins/cppeditor/cppincludehierarchymodel.h @@ -41,6 +41,7 @@ enum ItemRole { } // Anonymous +namespace CPlusPlus { class Snapshot; } namespace TextEditor { class BaseTextEditor; } namespace CppEditor { @@ -72,10 +73,12 @@ public: private: void buildHierarchyIncludes(const QString ¤tFilePath); void buildHierarchyIncludes_helper(const QString &filePath, CppIncludeHierarchyItem *parent, + CPlusPlus::Snapshot snapshot, QSet<QString> *cyclic, bool recursive = true); void buildHierarchyIncludedBy(const QString ¤tFilePath); void buildHierarchyIncludedBy_helper(const QString &filePath, CppIncludeHierarchyItem *parent, - QSet<QString> *cyclic, bool recursive = true); + CPlusPlus::Snapshot snapshot, QSet<QString> *cyclic, + bool recursive = true); CppIncludeHierarchyItem *m_rootItem; CppIncludeHierarchyItem *m_includesItem; diff --git a/src/plugins/cppeditor/cpplocalrenaming.cpp b/src/plugins/cppeditor/cpplocalrenaming.cpp index d2a0c02282..e81b8e66ae 100644 --- a/src/plugins/cppeditor/cpplocalrenaming.cpp +++ b/src/plugins/cppeditor/cpplocalrenaming.cpp @@ -72,7 +72,8 @@ CppLocalRenaming::CppLocalRenaming(TextEditor::BaseTextEditorWidget *editorWidge this, SLOT(onContentsChangeOfEditorWidgetDocument(int,int,int))); } -void CppLocalRenaming::updateLocalUseSelections(const QList<QTextEdit::ExtraSelection> &selections) +void CppLocalRenaming::updateSelectionsForVariableUnderCursor( + const QList<QTextEdit::ExtraSelection> &selections) { QTC_ASSERT(!isActive(), return); m_selections = selections; diff --git a/src/plugins/cppeditor/cpplocalrenaming.h b/src/plugins/cppeditor/cpplocalrenaming.h index 0e246321ed..72d4f2c2d4 100644 --- a/src/plugins/cppeditor/cpplocalrenaming.h +++ b/src/plugins/cppeditor/cpplocalrenaming.h @@ -47,8 +47,6 @@ class CppLocalRenaming : public QObject public: explicit CppLocalRenaming(TextEditor::BaseTextEditorWidget *editorWidget); - void updateLocalUseSelections(const QList<QTextEdit::ExtraSelection> &selections); - bool start(); bool isActive() const; void stop(); @@ -62,6 +60,9 @@ public: // to BaseTextEditorWidget::keyPressEvent() bool handleKeyPressEvent(QKeyEvent *e); +public slots: + void updateSelectionsForVariableUnderCursor(const QList<QTextEdit::ExtraSelection> &selections); + signals: void finished(); void processKeyPressNormally(QKeyEvent *e); diff --git a/src/plugins/cppeditor/cppquickfixassistant.cpp b/src/plugins/cppeditor/cppquickfixassistant.cpp index 5ccf31b71f..34a79a5f70 100644 --- a/src/plugins/cppeditor/cppquickfixassistant.cpp +++ b/src/plugins/cppeditor/cppquickfixassistant.cpp @@ -94,7 +94,9 @@ CppQuickFixAssistInterface::CppQuickFixAssistInterface(CppEditorWidget *editor, , m_currentFile(CppRefactoringChanges::file(editor, m_semanticInfo.doc)) , m_context(m_semanticInfo.doc, m_snapshot) { - QTC_CHECK(!m_semanticInfo.doc.isNull()); + QTC_CHECK(m_semanticInfo.doc); + QTC_CHECK(m_semanticInfo.doc->translationUnit()); + QTC_CHECK(m_semanticInfo.doc->translationUnit()->ast()); CPlusPlus::ASTPath astPath(m_semanticInfo.doc); m_path = astPath(editor->textCursor()); } diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 0165339b5a..c6b8001b53 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -30,6 +30,7 @@ #include "cppquickfixes.h" #include "cppeditor.h" +#include "cppeditordocument.h" #include "cppfunctiondecldeflink.h" #include "cppquickfixassistant.h" #include "cppvirtualfunctionassistprovider.h" diff --git a/src/plugins/cppeditor/cppuseselections_test.cpp b/src/plugins/cppeditor/cppuseselections_test.cpp index c99a7a4c2b..e1408c3ade 100644 --- a/src/plugins/cppeditor/cppuseselections_test.cpp +++ b/src/plugins/cppeditor/cppuseselections_test.cpp @@ -135,7 +135,7 @@ SelectionList UseSelectionsTestCase::waitForUseSelections(bool *hasTimedOut) con QList<QTextEdit::ExtraSelection> extraSelections = getExtraSelections(); while (extraSelections.isEmpty()) { - if (timer.hasExpired(500)) { + if (timer.hasExpired(2500)) { if (hasTimedOut) *hasTimedOut = true; break; diff --git a/src/plugins/cppeditor/cppuseselectionsupdater.cpp b/src/plugins/cppeditor/cppuseselectionsupdater.cpp new file mode 100644 index 0000000000..e292ac4bcd --- /dev/null +++ b/src/plugins/cppeditor/cppuseselectionsupdater.cpp @@ -0,0 +1,451 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +** GNU Lesser General Public License Usage +** 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 +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "cppuseselectionsupdater.h" + +#include "cppcanonicalsymbol.h" +#include "cppeditor.h" + +#include <cpptools/cpplocalsymbols.h> +#include <cpptools/cppmodelmanagerinterface.h> +#include <cpptools/cpptoolsreuse.h> +#include <texteditor/basetexteditor.h> +#include <texteditor/fontsettings.h> + +#include <cplusplus/Macro.h> +#include <cplusplus/TranslationUnit.h> + +#include <utils/qtcassert.h> + +#include <QtConcurrentRun> +#include <QTextBlock> +#include <QTextCursor> +#include <QTextEdit> + +using namespace CPlusPlus; + +enum { updateUseSelectionsInternalInMs = 500 }; + +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; + + if (FunctionDefinitionAST *def = ast->asFunctionDefinition()) + return checkDeclaration(def); + + if (ObjCMethodDeclarationAST *method = ast->asObjCMethodDeclaration()) { + 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); + + if (_line > startLine || (_line == startLine && _column >= startColumn)) { + if (_line < endLine || (_line == endLine && _column < endColumn)) { + _functionDefinition = ast; + return false; + } + } + + return true; + } +}; + +QTextEdit::ExtraSelection extraSelection(const QTextCharFormat &format, const QTextCursor &cursor) +{ + QTextEdit::ExtraSelection selection; + selection.format = format; + selection.cursor = cursor; + return selection; +} + +struct Params +{ + // Shared + Document::Ptr document; + + // For local use calculation + int line; + int column; + + // For references calculation + Scope *scope; + QString expression; + Snapshot snapshot; +}; + +using CppEditor::Internal::SemanticUses; + +void splitLocalUses(const CppTools::SemanticInfo::LocalUseMap &uses, + const Params &p, + SemanticUses *selectionsForLocalVariableUnderCursor, + SemanticUses *selectionsForLocalUnusedVariables) +{ + QTC_ASSERT(selectionsForLocalVariableUnderCursor, return); + QTC_ASSERT(selectionsForLocalUnusedVariables, return); + + LookupContext context(p.document, p.snapshot); + + CppTools::SemanticInfo::LocalUseIterator it(uses); + while (it.hasNext()) { + it.next(); + const SemanticUses &uses = it.value(); + + bool good = false; + foreach (const CppTools::SemanticInfo::Use &use, uses) { + unsigned l = p.line; + unsigned c = p.column + 1; // convertCursorPosition() returns a 0-based column number. + if (l == use.line && c >= use.column && c <= (use.column + use.length)) { + good = true; + break; + } + } + + if (uses.size() == 1) { + if (!CppTools::isOwnershipRAIIType(it.key(), context)) + selectionsForLocalUnusedVariables->append(uses); // unused declaration + } else if (good && selectionsForLocalVariableUnderCursor->isEmpty()) { + selectionsForLocalVariableUnderCursor->append(uses); + } + } +} + +CppTools::SemanticInfo::LocalUseMap findLocalUses(const Params &p) +{ + AST *ast = p.document->translationUnit()->ast(); + FunctionDefinitionUnderCursor functionDefinitionUnderCursor(p.document->translationUnit()); + DeclarationAST *declaration = functionDefinitionUnderCursor(ast, p.line, p.column); + return CppTools::LocalSymbols(p.document, declaration).uses; +} + +QList<int> findReferences(const Params &p) +{ + QList<int> result; + if (!p.scope || p.expression.isEmpty()) + return result; + + TypeOfExpression typeOfExpression; + Snapshot snapshot = p.snapshot; + snapshot.insert(p.document); + typeOfExpression.init(p.document, snapshot); + typeOfExpression.setExpandTemplates(true); + + using CppEditor::Internal::CanonicalSymbol; + if (Symbol *s = CanonicalSymbol::canonicalSymbol(p.scope, p.expression, typeOfExpression)) { + CppTools::CppModelManagerInterface *mmi = CppTools::CppModelManagerInterface::instance(); + result = mmi->references(s, typeOfExpression.context()); + } + + return result; +} + +CppEditor::Internal::UseSelectionsResult findUses(const Params p) +{ + CppEditor::Internal::UseSelectionsResult result; + + const CppTools::SemanticInfo::LocalUseMap localUses = findLocalUses(p); + result.localUses = localUses; + splitLocalUses(localUses, p, &result.selectionsForLocalVariableUnderCursor, + &result.selectionsForLocalUnusedVariables); + + if (!result.selectionsForLocalVariableUnderCursor.isEmpty()) + return result; + + result.references = findReferences(p); + return result; // OK, result.selectionsForLocalUnusedVariables will be passed on +} + +} // anonymous namespace + +namespace CppEditor { +namespace Internal { + +CppUseSelectionsUpdater::CppUseSelectionsUpdater(TextEditor::BaseTextEditorWidget *editorWidget) + : m_editorWidget(editorWidget) + , m_findUsesRevision(-1) +{ + m_timer.setSingleShot(true); + m_timer.setInterval(updateUseSelectionsInternalInMs); + connect(&m_timer, SIGNAL(timeout()), this, SLOT(update())); +} + +void CppUseSelectionsUpdater::scheduleUpdate() +{ + m_timer.start(); +} + +void CppUseSelectionsUpdater::abortSchedule() +{ + m_timer.stop(); +} + +void CppUseSelectionsUpdater::update() +{ + CppEditorWidget *cppEditorWidget = qobject_cast<CppEditorWidget *>(m_editorWidget); + QTC_ASSERT(cppEditorWidget, return); + QTC_CHECK(cppEditorWidget->isSemanticInfoValidExceptLocalUses()); + const CppTools::SemanticInfo semanticInfo = cppEditorWidget->semanticInfo(); + const Document::Ptr document = semanticInfo.doc; + const Snapshot snapshot = semanticInfo.snapshot; + + if (!document || document->editorRevision() != static_cast<unsigned>(textDocument()->revision())) + return; + + QTC_ASSERT(document->translationUnit(), return); + QTC_ASSERT(document->translationUnit()->ast(), return); + QTC_ASSERT(!snapshot.isEmpty(), return); + + QTextCursor textCursor = m_editorWidget->textCursor(); + + if (handleMacroCase(textCursor, document)) { + emit finished(CppTools::SemanticInfo::LocalUseMap()); + return; + } + + handleSymbolCase(textCursor, document, snapshot); +} + +void CppUseSelectionsUpdater::onFindUsesFinished() +{ + QTC_ASSERT(m_findUsesWatcher, return); + if (m_findUsesWatcher->isCanceled()) + return; + if (m_findUsesRevision != textDocument()->revision()) + return; + // Optimizable: If the cursor is still on the same identifier the results are valid. + if (m_findUsesCursorPosition != m_editorWidget->position()) + return; + + const UseSelectionsResult result = m_findUsesWatcher->result(); + const bool hasUsesForLocalVariable = !result.selectionsForLocalVariableUnderCursor.isEmpty(); + const bool hasReferences = !result.references.isEmpty(); + + ExtraSelections localVariableSelections; + if (hasUsesForLocalVariable) { + localVariableSelections = toExtraSelections(result.selectionsForLocalVariableUnderCursor, + TextEditor::C_OCCURRENCES); + updateUseSelections(localVariableSelections); + } else if (hasReferences) { + const ExtraSelections selections = toExtraSelections(result.references, + TextEditor::C_OCCURRENCES); + updateUseSelections(selections); + } else { + if (!currentUseSelections().isEmpty()) + updateUseSelections(ExtraSelections()); + } + + updateUnusedSelections(toExtraSelections(result.selectionsForLocalUnusedVariables, + TextEditor::C_OCCURRENCES_UNUSED)); + + m_findUsesWatcher.reset(); + m_document.reset(); + m_snapshot = Snapshot(); + + emit selectionsForVariableUnderCursorUpdated(localVariableSelections); + emit finished(result.localUses); +} + +bool CppUseSelectionsUpdater::handleMacroCase(const QTextCursor &textCursor, + const Document::Ptr document) +{ + const Macro *macro = CppTools::findCanonicalMacro(textCursor, document); + if (!macro) + return false; + + const QTextCharFormat &occurrencesFormat = textCharFormat(TextEditor::C_OCCURRENCES); + ExtraSelections selections; + + // Macro definition + if (macro->fileName() == document->fileName()) { + QTextCursor cursor(textDocument()); + cursor.setPosition(macro->utf16CharOffset()); + cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, + macro->nameToQString().size()); + + selections.append(extraSelection(occurrencesFormat, cursor)); + } + + // Other macro uses + foreach (const Document::MacroUse &use, document->macroUses()) { + const Macro &useMacro = use.macro(); + if (useMacro.line() != macro->line() + || useMacro.utf16CharOffset() != macro->utf16CharOffset() + || useMacro.length() != macro->length() + || useMacro.fileName() != macro->fileName()) + continue; + + QTextCursor cursor(textDocument()); + cursor.setPosition(use.utf16charsBegin()); + cursor.setPosition(use.utf16charsEnd(), QTextCursor::KeepAnchor); + + selections.append(extraSelection(occurrencesFormat, cursor)); + } + + updateUseSelections(selections); + return true; +} + +void CppUseSelectionsUpdater::handleSymbolCase(const QTextCursor &textCursor, + const Document::Ptr document, + const Snapshot &snapshot) +{ + m_document = document; + m_snapshot = snapshot; + + if (m_findUsesWatcher) + m_findUsesWatcher->cancel(); + m_findUsesWatcher.reset(new QFutureWatcher<UseSelectionsResult>); + connect(m_findUsesWatcher.data(), SIGNAL(finished()), this, SLOT(onFindUsesFinished())); + + m_findUsesRevision = textDocument()->revision(); + m_findUsesCursorPosition = m_editorWidget->position(); + + Params params; + params.document = document; + m_editorWidget->convertPosition(m_findUsesCursorPosition, ¶ms.line, ¶ms.column); + CanonicalSymbol canonicalSymbol(document, snapshot); + params.scope = canonicalSymbol.getScopeAndExpression(textCursor, ¶ms.expression); + params.snapshot = snapshot; + + m_findUsesWatcher->setFuture(QtConcurrent::run(&findUses, params)); +} + +ExtraSelections CppUseSelectionsUpdater::toExtraSelections(const SemanticUses &uses, + TextEditor::TextStyle style) const +{ + ExtraSelections result; + + foreach (const CppTools::SemanticInfo::Use &use, uses) { + if (use.isInvalid()) + continue; + + QTextDocument *document = textDocument(); + const int position = document->findBlockByNumber(use.line - 1).position() + use.column - 1; + const int anchor = position + use.length; + + QTextEdit::ExtraSelection sel; + sel.format = textCharFormat(style); + sel.cursor = QTextCursor(document); + sel.cursor.setPosition(anchor); + sel.cursor.setPosition(position, QTextCursor::KeepAnchor); + + result.append(sel); + } + + return result; +} + +ExtraSelections CppUseSelectionsUpdater::toExtraSelections(const QList<int> &references, + TextEditor::TextStyle style) const +{ + ExtraSelections selections; + foreach (int index, references) { + unsigned line, column; + TranslationUnit *unit = m_document->translationUnit(); + unit->getTokenPosition(index, &line, &column); + + if (column) + --column; // adjust the column position. + + const int len = unit->tokenAt(index).utf16chars(); + + QTextCursor cursor(textDocument()->findBlockByNumber(line - 1)); + cursor.setPosition(cursor.position() + column); + cursor.setPosition(cursor.position() + len, QTextCursor::KeepAnchor); + + selections.append(extraSelection(textCharFormat(style), cursor)); + } + + return selections; +} + +QTextCharFormat CppUseSelectionsUpdater::textCharFormat(TextEditor::TextStyle category) const +{ + return m_editorWidget->textDocument()->fontSettings().toTextCharFormat(category); +} + +QTextDocument *CppUseSelectionsUpdater::textDocument() const +{ + return m_editorWidget->document(); +} + +ExtraSelections CppUseSelectionsUpdater::currentUseSelections() const +{ + return m_editorWidget->extraSelections( + TextEditor::BaseTextEditorWidget::CodeSemanticsSelection); +} + +void CppUseSelectionsUpdater::updateUseSelections(const ExtraSelections &selections) +{ + m_editorWidget->setExtraSelections(TextEditor::BaseTextEditorWidget::CodeSemanticsSelection, + selections); +} + +void CppUseSelectionsUpdater::updateUnusedSelections(const ExtraSelections &selections) +{ + m_editorWidget->setExtraSelections(TextEditor::BaseTextEditorWidget::UnusedSymbolSelection, + selections); +} + +} // namespace Internal +} // namespace CppEditor diff --git a/src/plugins/cppeditor/cppuseselectionsupdater.h b/src/plugins/cppeditor/cppuseselectionsupdater.h new file mode 100644 index 0000000000..277785afa2 --- /dev/null +++ b/src/plugins/cppeditor/cppuseselectionsupdater.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +** GNU Lesser General Public License Usage +** 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 +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CPPUSESELECTIONSUPDATER_H +#define CPPUSESELECTIONSUPDATER_H + +#include <cpptools/cppsemanticinfo.h> +#include <texteditor/texteditorconstants.h> + +#include <cplusplus/CppDocument.h> + +#include <QFutureWatcher> +#include <QTextEdit> +#include <QTimer> + +QT_BEGIN_NAMESPACE +class QTextCharFormat; +class QTextCursor; +QT_END_NAMESPACE + +namespace TextEditor { class BaseTextEditorWidget; } + +namespace CppEditor { +namespace Internal { + +typedef QList<QTextEdit::ExtraSelection> ExtraSelections; +typedef QList<CppTools::SemanticInfo::Use> SemanticUses; + +struct UseSelectionsResult +{ + CppTools::SemanticInfo::LocalUseMap localUses; + SemanticUses selectionsForLocalVariableUnderCursor; + SemanticUses selectionsForLocalUnusedVariables; + QList<int> references; +}; + +class CppUseSelectionsUpdater : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(CppUseSelectionsUpdater) + +public: + explicit CppUseSelectionsUpdater(TextEditor::BaseTextEditorWidget *editorWidget); + +public slots: + void scheduleUpdate(); + void abortSchedule(); + void update(); + +signals: + void finished(CppTools::SemanticInfo::LocalUseMap localUses); + void selectionsForVariableUnderCursorUpdated(const QList<QTextEdit::ExtraSelection> &); + +private slots: + void onFindUsesFinished(); + +private: + CppUseSelectionsUpdater(); + + bool handleMacroCase(const QTextCursor &textCursor, + const CPlusPlus::Document::Ptr document); + void handleSymbolCase(const QTextCursor &textCursor, + const CPlusPlus::Document::Ptr document, + const CPlusPlus::Snapshot &snapshot); + + ExtraSelections toExtraSelections(const SemanticUses &uses, TextEditor::TextStyle style) const; + ExtraSelections toExtraSelections(const QList<int> &references, + TextEditor::TextStyle style) const; + + // Convenience + ExtraSelections currentUseSelections() const; + void updateUseSelections(const ExtraSelections &selections); + void updateUnusedSelections(const ExtraSelections &selections); + QTextCharFormat textCharFormat(TextEditor::TextStyle category) const; + QTextDocument *textDocument() const; + +private: + TextEditor::BaseTextEditorWidget *m_editorWidget; + + QTimer m_timer; + + CPlusPlus::Document::Ptr m_document; + CPlusPlus::Snapshot m_snapshot; + + QScopedPointer<QFutureWatcher<UseSelectionsResult>> m_findUsesWatcher; + int m_findUsesRevision; + int m_findUsesCursorPosition; +}; + +} // namespace Internal +} // namespace CppEditor + +#endif // CPPUSESELECTIONSUPDATER_H diff --git a/src/plugins/cpptools/baseeditordocumentparser.cpp b/src/plugins/cpptools/baseeditordocumentparser.cpp index 058fae5b99..bcf7407415 100644 --- a/src/plugins/cpptools/baseeditordocumentparser.cpp +++ b/src/plugins/cpptools/baseeditordocumentparser.cpp @@ -29,6 +29,8 @@ #include "baseeditordocumentparser.h" +#include "editordocumenthandle.h" + namespace CppTools { /*! @@ -101,6 +103,16 @@ void BaseEditorDocumentParser::setEditorDefines(const QByteArray &editorDefines) } } +BaseEditorDocumentParser *BaseEditorDocumentParser::get(const QString &filePath) +{ + CppModelManagerInterface *cmmi = CppModelManagerInterface::instance(); + if (EditorDocumentHandle *editorDocument = cmmi->editorDocument(filePath)) { + if (BaseEditorDocumentProcessor *processor = editorDocument->processor()) + return processor->parser(); + } + return 0; +} + void BaseEditorDocumentParser::updateProjectPart() { if (m_manuallySetProjectPart) { diff --git a/src/plugins/cpptools/baseeditordocumentparser.h b/src/plugins/cpptools/baseeditordocumentparser.h index e62bbae4c6..d33b88a8ab 100644 --- a/src/plugins/cpptools/baseeditordocumentparser.h +++ b/src/plugins/cpptools/baseeditordocumentparser.h @@ -33,10 +33,13 @@ #include "cppmodelmanagerinterface.h" #include "cpptools_global.h" +#include <QObject> + namespace CppTools { -class CPPTOOLS_EXPORT BaseEditorDocumentParser +class CPPTOOLS_EXPORT BaseEditorDocumentParser : public QObject { + Q_OBJECT Q_DISABLE_COPY(BaseEditorDocumentParser) BaseEditorDocumentParser(); @@ -57,6 +60,9 @@ public: QByteArray editorDefines() const; void setEditorDefines(const QByteArray &editorDefines); +public: + static BaseEditorDocumentParser *get(const QString &filePath); + protected: void updateProjectPart(); diff --git a/src/plugins/cpptools/baseeditordocumentprocessor.cpp b/src/plugins/cpptools/baseeditordocumentprocessor.cpp new file mode 100644 index 0000000000..e8992da58e --- /dev/null +++ b/src/plugins/cpptools/baseeditordocumentprocessor.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +** GNU Lesser General Public License Usage +** 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 +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "baseeditordocumentprocessor.h" +#include "cppworkingcopy.h" + +#include "editordocumenthandle.h" + +#include <utils/qtcassert.h> + +#include <QTextBlock> + +namespace CppTools { + +/*! + \class CppTools::BaseEditorDocumentProcessor + + \brief The BaseEditorDocumentProcessor class controls and executes all + document relevant actions (reparsing, semantic highlighting, additional + semantic calculations) after a text document has changed. +*/ + +BaseEditorDocumentProcessor::BaseEditorDocumentProcessor( + TextEditor::BaseTextDocument *document) + : m_baseTextDocument(document) +{ + QTC_CHECK(document); +} + +BaseEditorDocumentProcessor::~BaseEditorDocumentProcessor() +{ +} + +TextEditor::BaseTextDocument *BaseEditorDocumentProcessor::baseTextDocument() const +{ + return m_baseTextDocument; +} + +BaseEditorDocumentProcessor *BaseEditorDocumentProcessor::get(const QString &filePath) +{ + CppModelManagerInterface *cmmi = CppModelManagerInterface::instance(); + if (EditorDocumentHandle *editorDocument = cmmi->editorDocument(filePath)) + return editorDocument->processor(); + return 0; +} + +QList<QTextEdit::ExtraSelection> BaseEditorDocumentProcessor::toTextEditorSelections( + const QList<CPlusPlus::Document::DiagnosticMessage> &diagnostics, + QTextDocument *textDocument) +{ + // Format for errors + QTextCharFormat errorFormat; + errorFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline); + errorFormat.setUnderlineColor(Qt::red); + + // Format for warnings + QTextCharFormat warningFormat; + warningFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline); + warningFormat.setUnderlineColor(Qt::darkYellow); + + QList<QTextEdit::ExtraSelection> result; + foreach (const CPlusPlus::Document::DiagnosticMessage &m, diagnostics) { + QTextEdit::ExtraSelection sel; + if (m.isWarning()) + sel.format = warningFormat; + else + sel.format = errorFormat; + + QTextCursor c(textDocument->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) { + if (!text.at(i).isSpace()) { + c.setPosition(c.position() + i); + break; + } + } + c.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); + } + sel.cursor = c; + sel.format.setToolTip(m.text()); + result.append(sel); + } + + return result; +} + +void BaseEditorDocumentProcessor::runParser(QFutureInterface<void> &future, + BaseEditorDocumentParser *parser, + WorkingCopy workingCopy) +{ + future.setProgressRange(0, 1); + if (future.isCanceled()) { + future.setProgressValue(1); + return; + } + + parser->update(workingCopy); + CppModelManagerInterface::instance() + ->finishedRefreshingSourceFiles(QStringList(parser->filePath())); + + future.setProgressValue(1); +} + +} // namespace CppTools diff --git a/src/plugins/cpptools/baseeditordocumentprocessor.h b/src/plugins/cpptools/baseeditordocumentprocessor.h new file mode 100644 index 0000000000..a6ac2e8a31 --- /dev/null +++ b/src/plugins/cpptools/baseeditordocumentprocessor.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +** GNU Lesser General Public License Usage +** 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 +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef BASEEDITORDOCUMENTPROCESSOR_H +#define BASEEDITORDOCUMENTPROCESSOR_H + +#include "baseeditordocumentparser.h" +#include "cppsemanticinfo.h" +#include "cpptools_global.h" + +#include <texteditor/basetexteditor.h> + +#include <cplusplus/CppDocument.h> + +#include <QTextEdit> + +namespace CppTools { + +class CPPTOOLS_EXPORT BaseEditorDocumentProcessor : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(BaseEditorDocumentProcessor) + BaseEditorDocumentProcessor(); + +public: + BaseEditorDocumentProcessor(TextEditor::BaseTextDocument *document); + virtual ~BaseEditorDocumentProcessor(); + + TextEditor::BaseTextDocument *baseTextDocument() const; + + // Function interface to implement + virtual void run() = 0; + virtual void semanticRehighlight(bool force) = 0; + virtual CppTools::SemanticInfo recalculateSemanticInfo() = 0; + virtual BaseEditorDocumentParser *parser() = 0; + virtual bool isParserRunning() const = 0; + +public: + static BaseEditorDocumentProcessor *get(const QString &filePath); + +signals: + // Signal interface to implement + void codeWarningsUpdated(unsigned revision, + const QList<QTextEdit::ExtraSelection> selections); + + void ifdefedOutBlocksUpdated(unsigned revision, + const QList<TextEditor::BlockRange> ifdefedOutBlocks); + + void cppDocumentUpdated(const CPlusPlus::Document::Ptr document); // TODO: Remove me + void semanticInfoUpdated(const CppTools::SemanticInfo semanticInfo); // TODO: Remove me + +protected: + static QList<QTextEdit::ExtraSelection> toTextEditorSelections( + const QList<CPlusPlus::Document::DiagnosticMessage> &diagnostics, + QTextDocument *textDocument); + + static void runParser(QFutureInterface<void> &future, + CppTools::BaseEditorDocumentParser *parser, + CppTools::WorkingCopy workingCopy); + + // Convenience + QString filePath() const { return m_baseTextDocument->filePath(); } + unsigned revision() const { return static_cast<unsigned>(textDocument()->revision()); } + QTextDocument *textDocument() const { return m_baseTextDocument->document(); } + +private: + TextEditor::BaseTextDocument *m_baseTextDocument; +}; + +} // namespace CppTools + +#endif // BASEEDITORDOCUMENTPROCESSOR_H + diff --git a/src/plugins/cpptools/builtineditordocumentparser.cpp b/src/plugins/cpptools/builtineditordocumentparser.cpp index a52659d4c6..526664dc1e 100644 --- a/src/plugins/cpptools/builtineditordocumentparser.cpp +++ b/src/plugins/cpptools/builtineditordocumentparser.cpp @@ -29,6 +29,7 @@ #include "builtineditordocumentparser.h" #include "cppsourceprocessor.h" +#include "editordocumenthandle.h" #include <utils/qtcassert.h> @@ -221,8 +222,15 @@ void BuiltinEditorDocumentParser::setReleaseSourceAndAST(bool onoff) m_releaseSourceAndAST = onoff; } +BuiltinEditorDocumentParser *BuiltinEditorDocumentParser::get(const QString &filePath) +{ + if (BaseEditorDocumentParser *b = BaseEditorDocumentParser::get(filePath)) + return qobject_cast<BuiltinEditorDocumentParser *>(b); + return 0; +} + void BuiltinEditorDocumentParser::addFileAndDependencies(QSet<QString> *toRemove, - const QString &fileName) const + const QString &fileName) const { toRemove->insert(fileName); if (fileName != filePath()) { @@ -230,4 +238,3 @@ void BuiltinEditorDocumentParser::addFileAndDependencies(QSet<QString> *toRemove toRemove->unite(QSet<QString>::fromList(deps)); } } - diff --git a/src/plugins/cpptools/builtineditordocumentparser.h b/src/plugins/cpptools/builtineditordocumentparser.h index b52e6596db..c7993c6a6b 100644 --- a/src/plugins/cpptools/builtineditordocumentparser.h +++ b/src/plugins/cpptools/builtineditordocumentparser.h @@ -45,8 +45,7 @@ namespace CppTools { class CPPTOOLS_EXPORT BuiltinEditorDocumentParser : public BaseEditorDocumentParser { -public: - typedef QSharedPointer<BuiltinEditorDocumentParser> Ptr; + Q_OBJECT public: BuiltinEditorDocumentParser(const QString &filePath); @@ -60,6 +59,9 @@ public: void setReleaseSourceAndAST(bool onoff); +public: + static BuiltinEditorDocumentParser *get(const QString &filePath); + private: void addFileAndDependencies(QSet<QString> *toRemove, const QString &fileName) const; diff --git a/src/plugins/cpptools/builtineditordocumentprocessor.cpp b/src/plugins/cpptools/builtineditordocumentprocessor.cpp new file mode 100644 index 0000000000..cd50c86609 --- /dev/null +++ b/src/plugins/cpptools/builtineditordocumentprocessor.cpp @@ -0,0 +1,253 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +** GNU Lesser General Public License Usage +** 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 +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "builtineditordocumentprocessor.h" + +#include "cppchecksymbols.h" +#include "cppcodemodelsettings.h" +#include "cppmodelmanager.h" +#include "cpptoolsplugin.h" +#include "cpptoolsreuse.h" +#include "cppworkingcopy.h" + +#include <texteditor/basetexteditor.h> +#include <texteditor/convenience.h> + +#include <cplusplus/CppDocument.h> +#include <cplusplus/SimpleLexer.h> + +#include <utils/QtConcurrentTools> +#include <utils/qtcassert.h> + +enum { debug = 0 }; + +namespace { + +CppTools::Internal::CppModelManager *cmm() +{ + return CppTools::Internal::CppModelManager::instance(); +} + +QFuture<TextEditor::HighlightingResult> runHighlighter(const CPlusPlus::Document::Ptr &doc, + const CPlusPlus::Snapshot &snapshot, + QTextDocument *textDocument) +{ + QFuture<TextEditor::HighlightingResult> failed; + QTC_ASSERT(doc, return failed); + QTC_ASSERT(doc->translationUnit(), return failed); + QTC_ASSERT(doc->translationUnit()->ast(), return failed); + QTC_ASSERT(textDocument, return failed); + + using namespace CPlusPlus; + using namespace CppTools; + typedef TextEditor::HighlightingResult Result; + QList<Result> macroUses; + + using TextEditor::Convenience::convertPosition; + + // Get macro definitions + foreach (const CPlusPlus::Macro& macro, doc->definedMacros()) { + int line, column; + convertPosition(textDocument, macro.utf16CharOffset(), &line, &column); + + ++column; //Highlighting starts at (column-1) --> compensate here + Result use(line, column, macro.nameToQString().size(), SemanticHighlighter::MacroUse); + macroUses.append(use); + } + + // Get macro uses + foreach (const Document::MacroUse ¯o, doc->macroUses()) { + const QString name = macro.macro().nameToQString(); + + //Filter out QtKeywords + if (isQtKeyword(QStringRef(&name))) + continue; + + // Filter out C++ keywords + // FIXME: Check default values or get from document. + LanguageFeatures features; + features.cxx11Enabled = true; + features.c99Enabled = true; + + SimpleLexer tokenize; + tokenize.setLanguageFeatures(features); + + const QList<Token> tokens = tokenize(name); + if (tokens.length() && (tokens.at(0).isKeyword() || tokens.at(0).isObjCAtKeyword())) + continue; + + int line, column; + convertPosition(textDocument, macro.utf16charsBegin(), &line, &column); + ++column; //Highlighting starts at (column-1) --> compensate here + Result use(line, column, name.size(), SemanticHighlighter::MacroUse); + macroUses.append(use); + } + + LookupContext context(doc, snapshot); + return CheckSymbols::go(doc, context, macroUses); +} + +QList<TextEditor::BlockRange> toTextEditorBlocks( + const QList<CPlusPlus::Document::Block> &skippedBlocks) +{ + QList<TextEditor::BlockRange> result; + result.reserve(skippedBlocks.size()); + foreach (const CPlusPlus::Document::Block &block, skippedBlocks) + result.append(TextEditor::BlockRange(block.utf16charsBegin(), block.utf16charsEnd())); + return result; +} + +} // anonymous namespace + +namespace CppTools { + +BuiltinEditorDocumentProcessor::BuiltinEditorDocumentProcessor( + TextEditor::BaseTextDocument *document, + bool enableSemanticHighlighter) + : BaseEditorDocumentProcessor(document) + , m_parser(new BuiltinEditorDocumentParser(document->filePath())) + , m_semanticInfoUpdater(m_parser.data()) + , m_semanticHighlighter(enableSemanticHighlighter + ? new CppTools::SemanticHighlighter(document) + : 0) +{ + QSharedPointer<Internal::CppCodeModelSettings> cms + = Internal::CppToolsPlugin::instance()->codeModelSettings(); + m_parser->setUsePrecompiledHeaders( + cms->pchUsage() != Internal::CppCodeModelSettings::PchUse_None); + + if (m_semanticHighlighter) { + m_semanticHighlighter->setHighlightingRunner( + [this]() -> QFuture<TextEditor::HighlightingResult> { + const SemanticInfo semanticInfo = m_semanticInfoUpdater.semanticInfo(); + return runHighlighter(semanticInfo.doc, semanticInfo.snapshot, + baseTextDocument()->document()); + }); + } + + connect(cmm(), &Internal::CppModelManager::documentUpdated, + this, &BuiltinEditorDocumentProcessor::onDocumentUpdated); + connect(&m_semanticInfoUpdater, &SemanticInfoUpdater::updated, + this, &BuiltinEditorDocumentProcessor::onSemanticInfoUpdated); +} + +BuiltinEditorDocumentProcessor::~BuiltinEditorDocumentProcessor() +{ + m_parserFuture.cancel(); + m_parserFuture.waitForFinished(); +} + +void BuiltinEditorDocumentProcessor::run() +{ + m_parserFuture = QtConcurrent::run(&runParser, parser(), cmm()->workingCopy()); +} + +BaseEditorDocumentParser *BuiltinEditorDocumentProcessor::parser() +{ + return m_parser.data(); +} + +void BuiltinEditorDocumentProcessor::semanticRehighlight(bool force) +{ + const auto source = createSemanticInfoSource(force); + m_semanticInfoUpdater.updateDetached(source); +} + +SemanticInfo BuiltinEditorDocumentProcessor::recalculateSemanticInfo() +{ + const auto source = createSemanticInfoSource(false); + return m_semanticInfoUpdater.update(source); +} + +bool BuiltinEditorDocumentProcessor::isParserRunning() const +{ + return m_parserFuture.isRunning(); +} + +BuiltinEditorDocumentProcessor *BuiltinEditorDocumentProcessor::get(const QString &filePath) +{ + if (BaseEditorDocumentProcessor *b = BaseEditorDocumentProcessor::get(filePath)) + return qobject_cast<BuiltinEditorDocumentProcessor *>(b); + return 0; +} + +void BuiltinEditorDocumentProcessor::onDocumentUpdated(CPlusPlus::Document::Ptr document) +{ + if (document.isNull()) + return; + + if (document->fileName() != filePath()) + return; // some other document got updated + + if (document->editorRevision() != revision()) + return; // outdated content, wait for a new document to be parsed + + if (debug) { + qDebug() << "BuiltinEditorDocumentProcessor: document parsed" << document->fileName() + << document->editorRevision(); + } + + // Emit ifdefed out blocks + const auto ifdefoutBlocks = toTextEditorBlocks(document->skippedBlocks()); + emit ifdefedOutBlocksUpdated(revision(), ifdefoutBlocks); + + // Emit code warnings + auto codeWarnings = toTextEditorSelections(document->diagnosticMessages(), textDocument()); + emit codeWarningsUpdated(revision(), codeWarnings); + + emit cppDocumentUpdated(document); + + const auto source = createSemanticInfoSource(false); + m_semanticInfoUpdater.updateDetached(source); +} + +void BuiltinEditorDocumentProcessor::onSemanticInfoUpdated(const SemanticInfo semanticInfo) +{ + if (debug) { + qDebug() << "BuiltinEditorDocumentProcessor: semantic info updated" + << semanticInfo.doc->fileName() << semanticInfo.revision << semanticInfo.complete; + } + + emit semanticInfoUpdated(semanticInfo); + + if (m_semanticHighlighter) + m_semanticHighlighter->run(); +} + +SemanticInfo::Source BuiltinEditorDocumentProcessor::createSemanticInfoSource(bool force) const +{ + const WorkingCopy workingCopy = cmm()->workingCopy(); + const QString path = filePath(); + return SemanticInfo::Source(path, + workingCopy.source(path), + workingCopy.revision(path), + force); +} + +} // namespace CppTools diff --git a/src/plugins/cpptools/builtineditordocumentprocessor.h b/src/plugins/cpptools/builtineditordocumentprocessor.h new file mode 100644 index 0000000000..402d5720ce --- /dev/null +++ b/src/plugins/cpptools/builtineditordocumentprocessor.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +** GNU Lesser General Public License Usage +** 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 +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef BUILTINEDITORDOCUMENTPROCESSOR_H +#define BUILTINEDITORDOCUMENTPROCESSOR_H + +#include "baseeditordocumentprocessor.h" +#include "builtineditordocumentparser.h" +#include "cppsemanticinfoupdater.h" +#include "cpptools_global.h" +#include "semantichighlighter.h" + +#include <utils/qtcoverride.h> + +namespace CppTools { + +class CPPTOOLS_EXPORT BuiltinEditorDocumentProcessor : public BaseEditorDocumentProcessor +{ + Q_OBJECT + BuiltinEditorDocumentProcessor(); + +public: + BuiltinEditorDocumentProcessor(TextEditor::BaseTextDocument *document, + bool enableSemanticHighlighter = true); + ~BuiltinEditorDocumentProcessor(); + + // BaseEditorDocumentProcessor interface + void run() QTC_OVERRIDE; + void semanticRehighlight(bool force) QTC_OVERRIDE; + CppTools::SemanticInfo recalculateSemanticInfo() QTC_OVERRIDE; + BaseEditorDocumentParser *parser() QTC_OVERRIDE; + bool isParserRunning() const QTC_OVERRIDE; + +public: + static BuiltinEditorDocumentProcessor *get(const QString &filePath); + +private slots: + void onDocumentUpdated(CPlusPlus::Document::Ptr document); + void onSemanticInfoUpdated(const CppTools::SemanticInfo semanticInfo); + +private: + SemanticInfo::Source createSemanticInfoSource(bool force) const; + +private: + QScopedPointer<BuiltinEditorDocumentParser> m_parser; + QFuture<void> m_parserFuture; + + SemanticInfoUpdater m_semanticInfoUpdater; + QScopedPointer<SemanticHighlighter> m_semanticHighlighter; +}; + +} // namespace CppTools + +#endif // BUILTINEDITORDOCUMENTPROCESSOR_H diff --git a/src/plugins/cpptools/cppchecksymbols.cpp b/src/plugins/cpptools/cppchecksymbols.cpp index 4f528d47d6..eb6974c470 100644 --- a/src/plugins/cpptools/cppchecksymbols.cpp +++ b/src/plugins/cpptools/cppchecksymbols.cpp @@ -298,6 +298,8 @@ static bool acceptName(NameAST *ast, unsigned *referenceToken) CheckSymbols::Future CheckSymbols::go(Document::Ptr doc, const LookupContext &context, const QList<CheckSymbols::Result> ¯oUses) { QTC_ASSERT(doc, return Future()); + QTC_ASSERT(doc->translationUnit(), return Future()); + QTC_ASSERT(doc->translationUnit()->ast(), return Future()); return (new CheckSymbols(doc, context, macroUses))->start(); } @@ -477,7 +479,7 @@ bool CheckSymbols::visit(NamespaceAST *ast) if (!tok.generated()) { unsigned line, column; getTokenStartPosition(ast->identifier_token, &line, &column); - Result use(line, column, tok.utf16chars(), CppHighlightingSupport::TypeUse); + Result use(line, column, tok.utf16chars(), SemanticHighlighter::TypeUse); addUse(use); } } @@ -492,13 +494,13 @@ bool CheckSymbols::visit(UsingDirectiveAST *) bool CheckSymbols::visit(EnumeratorAST *ast) { - addUse(ast->identifier_token, CppHighlightingSupport::EnumerationUse); + addUse(ast->identifier_token, SemanticHighlighter::EnumerationUse); return true; } bool CheckSymbols::visit(DotDesignatorAST *ast) { - addUse(ast->identifier_token, CppHighlightingSupport::FieldUse); + addUse(ast->identifier_token, SemanticHighlighter::FieldUse); return true; } @@ -513,7 +515,7 @@ bool CheckSymbols::visit(SimpleDeclarationAST *ast) if (funTy->isVirtual() || (nameAST->asDestructorName() && hasVirtualDestructor(_context.lookupType(funTy->enclosingScope())))) { - addUse(nameAST, CppHighlightingSupport::VirtualMethodUse); + addUse(nameAST, SemanticHighlighter::VirtualMethodUse); declrIdNameAST = nameAST; } else if (maybeAddFunction(_context.lookup(decl->name(), decl->enclosingScope()), @@ -521,7 +523,7 @@ bool CheckSymbols::visit(SimpleDeclarationAST *ast) declrIdNameAST = nameAST; // Add a diagnostic message if non-virtual function has override/final marker - if ((_usages.back().kind != CppHighlightingSupport::VirtualMethodUse)) { + if ((_usages.back().kind != SemanticHighlighter::VirtualMethodUse)) { if (funTy->isOverride()) warning(declrIdNameAST, QCoreApplication::translate( "CPlusplus::CheckSymbols", "Only virtual functions can be marked 'override'")); @@ -559,7 +561,7 @@ bool CheckSymbols::visit(ElaboratedTypeSpecifierAST *ast) { accept(ast->attribute_list); accept(ast->name); - addUse(ast->name, CppHighlightingSupport::TypeUse); + addUse(ast->name, SemanticHighlighter::TypeUse); return false; } @@ -796,14 +798,14 @@ void CheckSymbols::checkName(NameAST *ast, Scope *scope) if (klass) { if (hasVirtualDestructor(_context.lookupType(klass))) { - addUse(ast, CppHighlightingSupport::VirtualMethodUse); + addUse(ast, SemanticHighlighter::VirtualMethodUse); } else { bool added = false; if (highlightCtorDtorAsType && maybeType(ast->name)) added = maybeAddTypeOrStatic(_context.lookup(ast->name, klass), ast); if (!added) - addUse(ast, CppHighlightingSupport::FunctionUse); + addUse(ast, SemanticHighlighter::FunctionUse); } } } else if (maybeType(ast->name) || maybeStatic(ast->name)) { @@ -853,14 +855,14 @@ bool CheckSymbols::visit(QualifiedNameAST *ast) if (binding && ast->unqualified_name) { if (ast->unqualified_name->asDestructorName() != 0) { if (hasVirtualDestructor(binding)) { - addUse(ast->unqualified_name, CppHighlightingSupport::VirtualMethodUse); + addUse(ast->unqualified_name, SemanticHighlighter::VirtualMethodUse); } else { bool added = false; if (highlightCtorDtorAsType && maybeType(ast->name)) added = maybeAddTypeOrStatic(binding->find(ast->unqualified_name->name), ast->unqualified_name); if (!added) - addUse(ast->unqualified_name, CppHighlightingSupport::FunctionUse); + addUse(ast->unqualified_name, SemanticHighlighter::FunctionUse); } } else { QList<LookupItem> items = binding->find(ast->unqualified_name->name); @@ -904,7 +906,7 @@ ClassOrNamespace *CheckSymbols::checkNestedName(QualifiedNameAST *ast) if (NameAST *class_or_namespace_name = nested_name_specifier->class_or_namespace_name) { if (TemplateIdAST *template_id = class_or_namespace_name->asTemplateId()) { if (template_id->template_token) { - addUse(template_id, CppHighlightingSupport::TypeUse); + addUse(template_id, SemanticHighlighter::TypeUse); binding = 0; // there's no way we can find a binding. } @@ -928,7 +930,7 @@ ClassOrNamespace *CheckSymbols::checkNestedName(QualifiedNameAST *ast) bool CheckSymbols::visit(TypenameTypeParameterAST *ast) { - addUse(ast->name, CppHighlightingSupport::TypeUse); + addUse(ast->name, SemanticHighlighter::TypeUse); accept(ast->type_id); return false; } @@ -936,7 +938,7 @@ bool CheckSymbols::visit(TypenameTypeParameterAST *ast) bool CheckSymbols::visit(TemplateTypeParameterAST *ast) { accept(ast->template_parameter_list); - addUse(ast->name, CppHighlightingSupport::TypeUse); + addUse(ast->name, SemanticHighlighter::TypeUse); accept(ast->type_id); return false; } @@ -988,7 +990,7 @@ bool CheckSymbols::visit(MemInitializerAST *ast) bool CheckSymbols::visit(GotoStatementAST *ast) { if (ast->identifier_token) - addUse(ast->identifier_token, CppHighlightingSupport::LabelUse); + addUse(ast->identifier_token, SemanticHighlighter::LabelUse); return false; } @@ -996,7 +998,7 @@ bool CheckSymbols::visit(GotoStatementAST *ast) bool CheckSymbols::visit(LabeledStatementAST *ast) { if (ast->label_token && !tokenAt(ast->label_token).isKeyword()) - addUse(ast->label_token, CppHighlightingSupport::LabelUse); + addUse(ast->label_token, SemanticHighlighter::LabelUse); accept(ast->statement); return false; @@ -1017,7 +1019,7 @@ bool CheckSymbols::visit(SimpleSpecifierAST *ast) if (id.equalTo(_doc->control()->cpp11Override()) || id.equalTo(_doc->control()->cpp11Final())) { - addUse(ast->specifier_token, CppHighlightingSupport::PseudoKeywordUse); + addUse(ast->specifier_token, SemanticHighlighter::PseudoKeywordUse); } } } @@ -1028,7 +1030,7 @@ bool CheckSymbols::visit(SimpleSpecifierAST *ast) bool CheckSymbols::visit(ClassSpecifierAST *ast) { if (ast->final_token) - addUse(ast->final_token, CppHighlightingSupport::PseudoKeywordUse); + addUse(ast->final_token, SemanticHighlighter::PseudoKeywordUse); return true; } @@ -1053,7 +1055,7 @@ bool CheckSymbols::visit(FunctionDefinitionAST *ast) if (fun->isVirtual() || (declId->asDestructorName() && hasVirtualDestructor(_context.lookupType(fun->enclosingScope())))) { - addUse(declId, CppHighlightingSupport::VirtualMethodUse); + addUse(declId, SemanticHighlighter::VirtualMethodUse); } else if (!maybeAddFunction(_context.lookup(fun->name(), fun->enclosingScope()), declId, fun->argumentCount())) { @@ -1161,7 +1163,7 @@ void CheckSymbols::addType(ClassOrNamespace *b, NameAST *ast) unsigned line, column; getTokenStartPosition(startToken, &line, &column); const unsigned length = tok.utf16chars(); - const Result use(line, column, length, CppHighlightingSupport::TypeUse); + const Result use(line, column, length, SemanticHighlighter::TypeUse); addUse(use); } @@ -1203,12 +1205,12 @@ bool CheckSymbols::maybeAddTypeOrStatic(const QList<LookupItem> &candidates, Nam getTokenStartPosition(startToken, &line, &column); const unsigned length = tok.utf16chars(); - Kind kind = CppHighlightingSupport::TypeUse; + Kind kind = SemanticHighlighter::TypeUse; if (c->enclosingEnum() != 0) - kind = CppHighlightingSupport::EnumerationUse; + kind = SemanticHighlighter::EnumerationUse; else if (c->isStatic()) // treat static variable as a field(highlighting) - kind = CppHighlightingSupport::FieldUse; + kind = SemanticHighlighter::FieldUse; const Result use(line, column, length, kind); addUse(use); @@ -1245,7 +1247,7 @@ bool CheckSymbols::maybeAddField(const QList<LookupItem> &candidates, NameAST *a getTokenStartPosition(startToken, &line, &column); const unsigned length = tok.utf16chars(); - const Result use(line, column, length, CppHighlightingSupport::FieldUse); + const Result use(line, column, length, SemanticHighlighter::FieldUse); addUse(use); return true; @@ -1270,7 +1272,7 @@ bool CheckSymbols::maybeAddFunction(const QList<LookupItem> &candidates, NameAST return false; enum { Match_None, Match_TooManyArgs, Match_TooFewArgs, Match_Ok } matchType = Match_None; - Kind kind = CppHighlightingSupport::FunctionUse; + Kind kind = SemanticHighlighter::FunctionUse; foreach (const LookupItem &r, candidates) { Symbol *c = r.declaration(); @@ -1297,21 +1299,21 @@ bool CheckSymbols::maybeAddFunction(const QList<LookupItem> &candidates, NameAST if (argumentCount < funTy->minimumArgumentCount()) { if (matchType != Match_Ok) { - kind = funTy->isVirtual() ? CppHighlightingSupport::VirtualMethodUse : CppHighlightingSupport::FunctionUse; + kind = funTy->isVirtual() ? SemanticHighlighter::VirtualMethodUse : SemanticHighlighter::FunctionUse; matchType = Match_TooFewArgs; } } else if (argumentCount > funTy->argumentCount() && !funTy->isVariadic()) { if (matchType != Match_Ok) { matchType = Match_TooManyArgs; - kind = funTy->isVirtual() ? CppHighlightingSupport::VirtualMethodUse : CppHighlightingSupport::FunctionUse; + kind = funTy->isVirtual() ? SemanticHighlighter::VirtualMethodUse : SemanticHighlighter::FunctionUse; } } else if (!funTy->isVirtual()) { matchType = Match_Ok; - kind = CppHighlightingSupport::FunctionUse; + kind = SemanticHighlighter::FunctionUse; //continue, to check if there is a matching candidate which is virtual } else { matchType = Match_Ok; - kind = CppHighlightingSupport::VirtualMethodUse; + kind = SemanticHighlighter::VirtualMethodUse; break; } } @@ -1321,7 +1323,7 @@ bool CheckSymbols::maybeAddFunction(const QList<LookupItem> &candidates, NameAST if (highlightCtorDtorAsType && (isConstructor || isDestructor) && maybeType(ast->name) - && kind == CppHighlightingSupport::FunctionUse) { + && kind == SemanticHighlighter::FunctionUse) { return false; } diff --git a/src/plugins/cpptools/cppchecksymbols.h b/src/plugins/cpptools/cppchecksymbols.h index 5ccd2fe4cf..6c61275b6e 100644 --- a/src/plugins/cpptools/cppchecksymbols.h +++ b/src/plugins/cpptools/cppchecksymbols.h @@ -31,8 +31,8 @@ #define CPLUSPLUSCHECKSYMBOLS_H #include "cpptools_global.h" -#include "cpphighlightingsupport.h" #include "cppsemanticinfo.h" +#include "semantichighlighter.h" #include <cplusplus/TypeOfExpression.h> @@ -51,7 +51,7 @@ public: virtual ~CheckSymbols(); typedef TextEditor::HighlightingResult Result; - typedef CppHighlightingSupport::Kind Kind; + typedef SemanticHighlighter::Kind Kind; virtual void run(); diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp index 19d262ae69..679e141b75 100644 --- a/src/plugins/cpptools/cppcompletion_test.cpp +++ b/src/plugins/cpptools/cppcompletion_test.cpp @@ -102,8 +102,8 @@ public: { QStringList completions; CppCompletionAssistInterface *ai - = new CppCompletionAssistInterface(m_editorWidget->document(), m_position, - m_editorWidget->textDocument()->filePath(), + = new CppCompletionAssistInterface(m_editorWidget->textDocument()->filePath(), + m_editorWidget->document(), m_position, ExplicitlyInvoked, m_snapshot, ProjectPart::HeaderPaths()); CppCompletionAssistProcessor processor; diff --git a/src/plugins/cpptools/cppcompletionassist.cpp b/src/plugins/cpptools/cppcompletionassist.cpp index 90fce585f8..a4866da361 100644 --- a/src/plugins/cpptools/cppcompletionassist.cpp +++ b/src/plugins/cpptools/cppcompletionassist.cpp @@ -34,8 +34,8 @@ #include "cppmodelmanager.h" #include "cppmodelmanagerinterface.h" #include "cpptoolsconstants.h" -#include "cpptoolseditorsupport.h" #include "cpptoolsreuse.h" +#include "editordocumenthandle.h" #include <coreplugin/icore.h> #include <cppeditor/cppeditorconstants.h> @@ -421,15 +421,14 @@ IAssistProcessor *InternalCompletionAssistProvider::createProcessor() const } TextEditor::IAssistInterface *InternalCompletionAssistProvider::createAssistInterface( - ProjectExplorer::Project *project, BaseTextEditor *editor, QTextDocument *document, + ProjectExplorer::Project *project, const QString &filePath, QTextDocument *document, bool isObjCEnabled, int position, TextEditor::AssistReason reason) const { Q_UNUSED(project); - QTC_ASSERT(editor, return 0); QTC_ASSERT(document, return 0); CppModelManagerInterface *modelManager = CppModelManagerInterface::instance(); - return new CppTools::Internal::CppCompletionAssistInterface(editor, document, isObjCEnabled, + return new CppTools::Internal::CppCompletionAssistInterface(filePath, document, isObjCEnabled, position, reason, modelManager->workingCopy()); } @@ -1957,12 +1956,9 @@ void CppCompletionAssistInterface::getCppSpecifics() const return; m_gotCppSpecifics = true; - CppModelManagerInterface *modelManager = CppModelManagerInterface::instance(); - if (CppEditorSupport *supp = modelManager->cppEditorSupport(m_editor)) { - if (BuiltinEditorDocumentParser::Ptr parser = supp->documentParser()) { - parser->update(m_workingCopy); - m_snapshot = parser->snapshot(); - m_headerPaths = parser->headerPaths(); - } + if (BuiltinEditorDocumentParser *parser = BuiltinEditorDocumentParser::get(fileName())) { + parser->update(m_workingCopy); + m_snapshot = parser->snapshot(); + m_headerPaths = parser->headerPaths(); } } diff --git a/src/plugins/cpptools/cppcompletionassist.h b/src/plugins/cpptools/cppcompletionassist.h index a63ca76ad4..7fa602b4a5 100644 --- a/src/plugins/cpptools/cppcompletionassist.h +++ b/src/plugins/cpptools/cppcompletionassist.h @@ -96,7 +96,7 @@ public: TextEditor::IAssistProcessor *createProcessor() const QTC_OVERRIDE; TextEditor::IAssistInterface *createAssistInterface(ProjectExplorer::Project *project, - TextEditor::BaseTextEditor *editor, + const QString &filePath, QTextDocument *document, bool isObjCEnabled, int position, @@ -173,28 +173,25 @@ private: class CppCompletionAssistInterface : public TextEditor::DefaultAssistInterface { public: - CppCompletionAssistInterface(TextEditor::BaseTextEditor *editor, + CppCompletionAssistInterface(const QString &filePath, QTextDocument *textDocument, bool isObjCEnabled, int position, TextEditor::AssistReason reason, const WorkingCopy &workingCopy) - : TextEditor::DefaultAssistInterface(textDocument, position, editor->document()->filePath(), - reason) - , m_editor(editor) + : TextEditor::DefaultAssistInterface(textDocument, position, filePath, reason) , m_isObjCEnabled(isObjCEnabled) , m_gotCppSpecifics(false) , m_workingCopy(workingCopy) {} - CppCompletionAssistInterface(QTextDocument *textDocument, + CppCompletionAssistInterface(const QString &filePath, + QTextDocument *textDocument, int position, - const QString &fileName, TextEditor::AssistReason reason, const CPlusPlus::Snapshot &snapshot, const ProjectPart::HeaderPaths &headerPaths) - : TextEditor::DefaultAssistInterface(textDocument, position, fileName, reason) - , m_editor(0) + : TextEditor::DefaultAssistInterface(textDocument, position, filePath, reason) , m_isObjCEnabled(false) , m_gotCppSpecifics(true) , m_snapshot(snapshot) @@ -210,7 +207,6 @@ public: private: void getCppSpecifics() const; - TextEditor::BaseTextEditor *m_editor; mutable bool m_isObjCEnabled; mutable bool m_gotCppSpecifics; WorkingCopy m_workingCopy; diff --git a/src/plugins/cpptools/cppcompletionassistprovider.h b/src/plugins/cpptools/cppcompletionassistprovider.h index 8873fd3518..f60c5bb102 100644 --- a/src/plugins/cpptools/cppcompletionassistprovider.h +++ b/src/plugins/cpptools/cppcompletionassistprovider.h @@ -61,7 +61,7 @@ public: bool isContinuationChar(const QChar &c) const QTC_OVERRIDE; virtual TextEditor::IAssistInterface *createAssistInterface( - ProjectExplorer::Project *project, TextEditor::BaseTextEditor *editor, + ProjectExplorer::Project *project, const QString &filePath, QTextDocument *document, bool isObjCEnabled, int position, TextEditor::AssistReason reason) const = 0; diff --git a/src/plugins/cpptools/cpphighlightingsupportinternal.cpp b/src/plugins/cpptools/cpphighlightingsupportinternal.cpp deleted file mode 100644 index 852868cc77..0000000000 --- a/src/plugins/cpptools/cpphighlightingsupportinternal.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of Qt Creator. -** -** 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. -** -** GNU Lesser General Public License Usage -** 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 -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#include "cpphighlightingsupportinternal.h" - -#include "cppchecksymbols.h" -#include "cpptoolsreuse.h" - -#include <texteditor/basetextdocument.h> -#include <texteditor/convenience.h> - -#include <cplusplus/SimpleLexer.h> - -using namespace CPlusPlus; -using namespace CppTools; -using namespace CppTools::Internal; - -CppHighlightingSupportInternal::CppHighlightingSupportInternal( - TextEditor::BaseTextDocument *baseTextDocument) - : CppHighlightingSupport(baseTextDocument) -{ -} - -CppHighlightingSupportInternal::~CppHighlightingSupportInternal() -{ -} - -QFuture<TextEditor::HighlightingResult> CppHighlightingSupportInternal::highlightingFuture( - const Document::Ptr &doc, - const Snapshot &snapshot) const -{ - typedef TextEditor::HighlightingResult Result; - QList<Result> macroUses; - - QTextDocument *textDocument = baseTextDocument()->document(); - using TextEditor::Convenience::convertPosition; - - // Get macro definitions - foreach (const CPlusPlus::Macro& macro, doc->definedMacros()) { - int line, column; - convertPosition(textDocument, macro.utf16CharOffset(), &line, &column); - - ++column; //Highlighting starts at (column-1) --> compensate here - Result use(line, column, macro.nameToQString().size(), MacroUse); - macroUses.append(use); - } - - // Get macro uses - foreach (const Document::MacroUse ¯o, doc->macroUses()) { - const QString name = macro.macro().nameToQString(); - - //Filter out QtKeywords - if (isQtKeyword(QStringRef(&name))) - continue; - - // Filter out C++ keywords - // FIXME: Check default values or get from document. - LanguageFeatures features; - features.cxx11Enabled = true; - features.c99Enabled = true; - - SimpleLexer tokenize; - tokenize.setLanguageFeatures(features); - - const QList<Token> tokens = tokenize(name); - if (tokens.length() && (tokens.at(0).isKeyword() || tokens.at(0).isObjCAtKeyword())) - continue; - - int line, column; - convertPosition(textDocument, macro.utf16charsBegin(), &line, &column); - ++column; //Highlighting starts at (column-1) --> compensate here - Result use(line, column, name.size(), MacroUse); - macroUses.append(use); - } - - LookupContext context(doc, snapshot); - return CheckSymbols::go(doc, context, macroUses); -} diff --git a/src/plugins/cpptools/cpplocalsymbols.cpp b/src/plugins/cpptools/cpplocalsymbols.cpp index e491589fc6..f68fc9bdc7 100644 --- a/src/plugins/cpptools/cpplocalsymbols.cpp +++ b/src/plugins/cpptools/cpplocalsymbols.cpp @@ -27,8 +27,8 @@ ** ****************************************************************************/ -#include "cpphighlightingsupport.h" #include "cpplocalsymbols.h" +#include "semantichighlighter.h" #include "cppsemanticinfo.h" @@ -86,7 +86,7 @@ protected: getPosition(token.utf16charsBegin(), &line, &column); localUses[member].append( HighlightingResult(line, column, token.utf16chars(), - CppHighlightingSupport::LocalUse)); + SemanticHighlighter::LocalUse)); } } } @@ -110,7 +110,7 @@ protected: getTokenStartPosition(simpleName->identifier_token, &line, &column); localUses[member].append( HighlightingResult(line, column, token.utf16chars(), - CppHighlightingSupport::LocalUse)); + SemanticHighlighter::LocalUse)); return false; } } diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index 83c642b5b9..796a052b95 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -34,13 +34,12 @@ #include "cppcodemodelinspectordumper.h" #include "cppcodemodelsettings.h" #include "cppfindreferences.h" -#include "cpphighlightingsupport.h" #include "cppindexingsupport.h" #include "cppmodelmanagersupportinternal.h" #include "cppsourceprocessor.h" #include "cpptoolsconstants.h" -#include "cpptoolseditorsupport.h" #include "cpptoolsplugin.h" +#include "editordocumenthandle.h" #include <coreplugin/icore.h> #include <coreplugin/progressmanager/progressmanager.h> @@ -399,47 +398,42 @@ void CppModelManager::removeExtraEditorSupport(AbstractEditorSupport *editorSupp m_extraEditorSupports.remove(editorSupport); } -/// \brief Returns the \c CppEditorSupport for the given text editor. It will -/// create one when none exists yet. -CppEditorSupport *CppModelManager::cppEditorSupport(TextEditor::BaseTextEditor *textEditor) +EditorDocumentHandle *CppModelManager::editorDocument(const QString &filePath) { - Q_ASSERT(textEditor); + QTC_ASSERT(!filePath.isEmpty(), return 0); - QMutexLocker locker(&m_cppEditorSupportsMutex); - - CppEditorSupport *editorSupport = m_cppEditorSupports.value(textEditor, 0); - if (!editorSupport && isCppEditor(textEditor)) { - editorSupport = new CppEditorSupport(this, textEditor); - m_cppEditorSupports.insert(textEditor, editorSupport); - } - return editorSupport; + QMutexLocker locker(&m_cppEditorsMutex); + return m_cppEditors.value(filePath, 0); } -/// \brief Removes the CppEditorSupport for the closed editor. -void CppModelManager::deleteCppEditorSupport(TextEditor::BaseTextEditor *textEditor) +void CppModelManager::registerEditorDocument(EditorDocumentHandle *editorDocument) { - static short numberOfClosedEditors = 0; + QTC_ASSERT(editorDocument, return); + const QString filePath = editorDocument->filePath(); + QTC_ASSERT(!filePath.isEmpty(), return); - QTC_ASSERT(textEditor, return); + QMutexLocker locker(&m_cppEditorsMutex); + QTC_ASSERT(m_cppEditors.value(filePath, 0) == 0, return); + m_cppEditors.insert(filePath, editorDocument); +} - if (!isCppEditor(textEditor)) - return; +void CppModelManager::unregisterEditorDocument(const QString &filePath) +{ + QTC_ASSERT(!filePath.isEmpty(), return); - CppEditorSupport *editorSupport; - int numberOfOpenEditors = 0; + static short closedCppDocuments = 0; + int openCppDocuments = 0; - { // Only lock the operations on m_cppEditorSupport - QMutexLocker locker(&m_cppEditorSupportsMutex); - editorSupport = m_cppEditorSupports.value(textEditor, 0); - m_cppEditorSupports.remove(textEditor); - numberOfOpenEditors = m_cppEditorSupports.size(); + { + QMutexLocker locker(&m_cppEditorsMutex); + QTC_ASSERT(m_cppEditors.value(filePath, 0), return); + QTC_CHECK(m_cppEditors.remove(filePath) == 1); + openCppDocuments = m_cppEditors.size(); } - delete editorSupport; - - ++numberOfClosedEditors; - if (numberOfOpenEditors == 0 || numberOfClosedEditors == 5) { - numberOfClosedEditors = 0; + ++closedCppDocuments; + if (openCppDocuments == 0 || closedCppDocuments == 5) { + closedCppDocuments = 0; delayedGC(); } } @@ -483,10 +477,8 @@ WorkingCopy CppModelManager::buildWorkingCopyList() { WorkingCopy workingCopy; - foreach (const CppEditorSupport *editorSupport, cppEditorSupportList()) { - workingCopy.insert(editorSupport->fileName(), editorSupport->contents(), - editorSupport->editorRevision()); - } + foreach (const EditorDocumentHandle *cppEditor, cppEditors()) + workingCopy.insert(cppEditor->filePath(), cppEditor->contents(), cppEditor->revision()); QSetIterator<AbstractEditorSupport *> it(m_extraEditorSupports); while (it.hasNext()) { @@ -551,10 +543,10 @@ void CppModelManager::removeProjectInfoFilesAndIncludesFromSnapshot(const Projec } } -QList<CppEditorSupport *> CppModelManager::cppEditorSupportList() const +QList<EditorDocumentHandle *> CppModelManager::cppEditors() const { - QMutexLocker locker(&m_cppEditorSupportsMutex); - return m_cppEditorSupports.values(); + QMutexLocker locker(&m_cppEditorsMutex); + return m_cppEditors.values(); } /// \brief Remove all given files from the snapshot. @@ -832,8 +824,8 @@ void CppModelManager::GC() // Collect files of CppEditorSupport and AbstractEditorSupport. QStringList filesInEditorSupports; - foreach (const CppEditorSupport *cppEditorSupport, cppEditorSupportList()) - filesInEditorSupports << cppEditorSupport->fileName(); + foreach (const EditorDocumentHandle *cppEditor, cppEditors()) + filesInEditorSupports << cppEditor->filePath(); QSetIterator<AbstractEditorSupport *> jt(m_extraEditorSupports); while (jt.hasNext()) { @@ -909,13 +901,13 @@ CppCompletionAssistProvider *CppModelManager::completionAssistProvider(const QSt return cms->completionAssistProvider(); } -CppHighlightingSupport *CppModelManager::highlightingSupport( +BaseEditorDocumentProcessor *CppModelManager::editorDocumentProcessor( TextEditor::BaseTextDocument *baseTextDocument) const { QTC_ASSERT(baseTextDocument, return 0); ModelManagerSupport *cms = modelManagerSupportForMimeType(baseTextDocument->mimeType()); QTC_ASSERT(cms, return 0); - return cms->highlightingSupport(baseTextDocument); + return cms->editorDocumentProcessor(baseTextDocument); } void CppModelManager::setIndexingSupport(CppIndexingSupport *indexingSupport) @@ -934,27 +926,3 @@ void CppModelManager::enableGarbageCollector(bool enable) m_delayedGcTimer->stop(); m_enableGC = enable; } - -bool CppModelManager::setExtraDiagnostics(const QString &fileName, - const QString &kind, - const QList<Document::DiagnosticMessage> &diagnostics) -{ - foreach (CppEditorSupport *editorSupport, cppEditorSupportList()) { - if (editorSupport->fileName() == fileName) { - editorSupport->setExtraDiagnostics(kind, diagnostics); - return true; - } - } - return false; -} - -void CppModelManager::setIfdefedOutBlocks(const QString &fileName, - const QList<TextEditor::BlockRange> &ifdeffedOutBlocks) -{ - foreach (CppEditorSupport *editorSupport, cppEditorSupportList()) { - if (editorSupport->fileName() == fileName) { - editorSupport->setIfdefedOutBlocks(ifdeffedOutBlocks); - break; - } - } -} diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h index c029bcb67e..490c9f803b 100644 --- a/src/plugins/cpptools/cppmodelmanager.h +++ b/src/plugins/cpptools/cppmodelmanager.h @@ -44,8 +44,6 @@ namespace TextEditor { class BaseTextEditorWidget; } namespace CppTools { -class CppEditorSupport; - namespace Internal { class CppFindReferences; @@ -94,8 +92,10 @@ public: virtual void addExtraEditorSupport(AbstractEditorSupport *editorSupport); virtual void removeExtraEditorSupport(AbstractEditorSupport *editorSupport); - virtual CppEditorSupport *cppEditorSupport(TextEditor::BaseTextEditor *textEditor); - virtual void deleteCppEditorSupport(TextEditor::BaseTextEditor *textEditor); + + virtual EditorDocumentHandle *editorDocument(const QString &filePath); + virtual void registerEditorDocument(EditorDocumentHandle *editorDocument); + virtual void unregisterEditorDocument(const QString &filePath); virtual QList<int> references(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context); @@ -106,18 +106,13 @@ public: virtual void findMacroUsages(const CPlusPlus::Macro ¯o); virtual void renameMacroUsages(const CPlusPlus::Macro ¯o, const QString &replacement); - virtual bool setExtraDiagnostics(const QString &fileName, const QString &key, - const QList<Document::DiagnosticMessage> &diagnostics); - virtual void setIfdefedOutBlocks(const QString &fileName, - const QList<TextEditor::BlockRange> &ifdeffedOutBlocks); - - void finishedRefreshingSourceFiles(const QStringList &files); + virtual void finishedRefreshingSourceFiles(const QStringList &files); virtual void addModelManagerSupport(ModelManagerSupport *modelManagerSupport); virtual ModelManagerSupport *modelManagerSupportForMimeType(const QString &mimeType) const; virtual CppCompletionAssistProvider *completionAssistProvider(const QString &mimeType) const; - virtual CppHighlightingSupport *highlightingSupport( - TextEditor::BaseTextDocument *baseTextDocument) const; + virtual BaseEditorDocumentProcessor *editorDocumentProcessor( + TextEditor::BaseTextDocument *baseTextDocument) const; virtual void setIndexingSupport(CppIndexingSupport *indexingSupport); virtual CppIndexingSupport *indexingSupport(); @@ -176,7 +171,7 @@ private: void removeFilesFromSnapshot(const QSet<QString> &removedFiles); void removeProjectInfoFilesAndIncludesFromSnapshot(const ProjectInfo &projectInfo); - QList<CppEditorSupport *> cppEditorSupportList() const; + QList<EditorDocumentHandle *> cppEditors() const; WorkingCopy buildWorkingCopyList(); @@ -208,8 +203,8 @@ private: QByteArray m_definedMacros; // Editor integration - mutable QMutex m_cppEditorSupportsMutex; - QMap<TextEditor::BaseTextEditor *, CppEditorSupport *> m_cppEditorSupports; + mutable QMutex m_cppEditorsMutex; + QMap<QString, EditorDocumentHandle *> m_cppEditors; QSet<AbstractEditorSupport *> m_extraEditorSupports; // Completion & highlighting diff --git a/src/plugins/cpptools/cppmodelmanager_test.cpp b/src/plugins/cpptools/cppmodelmanager_test.cpp index b443f5ba5a..e4bce83d1d 100644 --- a/src/plugins/cpptools/cppmodelmanager_test.cpp +++ b/src/plugins/cpptools/cppmodelmanager_test.cpp @@ -27,10 +27,11 @@ ** ****************************************************************************/ +#include "builtineditordocumentparser.h" #include "cppsourceprocessor.h" -#include "cpptoolseditorsupport.h" #include "cpptoolsplugin.h" #include "cpptoolstestcase.h" +#include "editordocumenthandle.h" #include "modelmanagertesthelper.h" #include <coreplugin/editormanager/editormanager.h> @@ -865,10 +866,10 @@ void CppToolsPlugin::test_modelmanager_defines_per_project() QCOMPARE(Core::DocumentModel::openedDocuments().size(), 1); QVERIFY(mm->isCppEditor(editor)); - CppEditorSupport *sup = mm->cppEditorSupport( - qobject_cast<TextEditor::BaseTextEditor *>(editor)); - while (sup->lastSemanticInfoDocument().isNull()) - QCoreApplication::processEvents(); +// CppEditorSupport *sup = mm->cppEditorSupport( +// qobject_cast<TextEditor::BaseTextEditor *>(editor)); +// while (sup->lastSemanticInfoDocument().isNull()) +// QCoreApplication::processEvents(); Document::Ptr doc = mm->document(fileName); QCOMPARE(nameOfFirstDeclaration(doc), firstDeclarationName); @@ -942,20 +943,16 @@ void CppToolsPlugin::test_modelmanager_precompiled_headers() QCOMPARE(Core::DocumentModel::openedDocuments().size(), 1); QVERIFY(mm->isCppEditor(editor)); - CppEditorSupport *sup = mm->cppEditorSupport( - qobject_cast<TextEditor::BaseTextEditor *>(editor)); - while (sup->lastSemanticInfoDocument().isNull()) - QCoreApplication::processEvents(); - - sup->documentParser()->setUsePrecompiledHeaders(true); - sup->documentParser()->update(mm->workingCopy()); + BuiltinEditorDocumentParser *parser = BuiltinEditorDocumentParser::get(fileName); + parser->setUsePrecompiledHeaders(true); + parser->update(mm->workingCopy()); // Check if defines from pch are considered Document::Ptr document = mm->document(fileName); QCOMPARE(nameOfFirstDeclaration(document), firstDeclarationName); // Check if declarations from pch are considered - CPlusPlus::LookupContext context(document, sup->documentParser()->snapshot()); + CPlusPlus::LookupContext context(document, parser->snapshot()); const CPlusPlus::Identifier *identifier = document->control()->identifier(firstClassInPchFile.data()); const QList<CPlusPlus::LookupItem> results = context.lookup(identifier, @@ -1025,13 +1022,10 @@ void CppToolsPlugin::test_modelmanager_defines_per_editor() QCOMPARE(Core::DocumentModel::openedDocuments().size(), 1); QVERIFY(mm->isCppEditor(editor)); - CppEditorSupport *sup = mm->cppEditorSupport( - qobject_cast<TextEditor::BaseTextEditor *>(editor)); - while (sup->lastSemanticInfoDocument().isNull()) - QCoreApplication::processEvents(); - - sup->documentParser()->setEditorDefines(editorDefines.toUtf8()); - sup->documentParser()->update(mm->workingCopy()); + const QString filePath = editor->document()->filePath(); + BaseEditorDocumentParser *parser = BaseEditorDocumentParser::get(filePath); + parser->setEditorDefines(editorDefines.toUtf8()); + parser->update(mm->workingCopy()); Document::Ptr doc = mm->document(main1File); QCOMPARE(nameOfFirstDeclaration(doc), firstDeclarationName); diff --git a/src/plugins/cpptools/cppmodelmanagerinterface.h b/src/plugins/cpptools/cppmodelmanagerinterface.h index 53120715fd..f48950499f 100644 --- a/src/plugins/cpptools/cppmodelmanagerinterface.h +++ b/src/plugins/cpptools/cppmodelmanagerinterface.h @@ -52,9 +52,9 @@ namespace Utils { class FileName; } namespace CppTools { class AbstractEditorSupport; +class BaseEditorDocumentProcessor; class CppCompletionAssistProvider; -class CppEditorSupport; -class CppHighlightingSupport; +class EditorDocumentHandle; class CppIndexingSupport; class ModelManagerSupport; class WorkingCopy; @@ -95,8 +95,10 @@ public: virtual void addExtraEditorSupport(CppTools::AbstractEditorSupport *editorSupport) = 0; virtual void removeExtraEditorSupport(CppTools::AbstractEditorSupport *editorSupport) = 0; - virtual CppEditorSupport *cppEditorSupport(TextEditor::BaseTextEditor *textEditor) = 0; - virtual void deleteCppEditorSupport(TextEditor::BaseTextEditor *textEditor) = 0; + + virtual EditorDocumentHandle *editorDocument(const QString &filePath) = 0; + virtual void registerEditorDocument(EditorDocumentHandle *editorDocument) = 0; + virtual void unregisterEditorDocument(const QString &filePath) = 0; virtual QList<int> references(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context) = 0; @@ -108,14 +110,13 @@ public: virtual void renameMacroUsages(const CPlusPlus::Macro ¯o, const QString &replacement = QString()) = 0; virtual void findMacroUsages(const CPlusPlus::Macro ¯o) = 0; - virtual void setIfdefedOutBlocks(const QString &fileName, - const QList<TextEditor::BlockRange> &ifdeffedOutBlocks) = 0; + virtual void finishedRefreshingSourceFiles(const QStringList &files) = 0; virtual void addModelManagerSupport(ModelManagerSupport *modelManagerSupport) = 0; virtual ModelManagerSupport *modelManagerSupportForMimeType(const QString &mimeType) const = 0; virtual CppCompletionAssistProvider *completionAssistProvider(const QString &mimeType) const = 0; - virtual CppHighlightingSupport *highlightingSupport( - TextEditor::BaseTextDocument *baseTextDocument) const = 0; + virtual BaseEditorDocumentProcessor *editorDocumentProcessor( + TextEditor::BaseTextDocument *baseTextDocument) const = 0; virtual void setIndexingSupport(CppTools::CppIndexingSupport *indexingSupport) = 0; virtual CppIndexingSupport *indexingSupport() = 0; diff --git a/src/plugins/cpptools/cppmodelmanagersupport.h b/src/plugins/cpptools/cppmodelmanagersupport.h index 556f34cbf8..423b096415 100644 --- a/src/plugins/cpptools/cppmodelmanagersupport.h +++ b/src/plugins/cpptools/cppmodelmanagersupport.h @@ -38,8 +38,8 @@ namespace TextEditor { class BaseTextDocument; } namespace CppTools { +class BaseEditorDocumentProcessor; class CppCompletionAssistProvider; -class CppHighlightingSupport; class CPPTOOLS_EXPORT ModelManagerSupport { @@ -50,8 +50,8 @@ public: virtual QString displayName() const = 0; virtual CppCompletionAssistProvider *completionAssistProvider() = 0; - virtual CppHighlightingSupport *highlightingSupport( - TextEditor::BaseTextDocument *baseTextDocument) = 0; + virtual BaseEditorDocumentProcessor *editorDocumentProcessor( + TextEditor::BaseTextDocument *baseTextDocument) = 0; }; } // CppTools namespace diff --git a/src/plugins/cpptools/cppmodelmanagersupportinternal.cpp b/src/plugins/cpptools/cppmodelmanagersupportinternal.cpp index bf43cf7908..9074a499b2 100644 --- a/src/plugins/cpptools/cppmodelmanagersupportinternal.cpp +++ b/src/plugins/cpptools/cppmodelmanagersupportinternal.cpp @@ -28,8 +28,8 @@ ****************************************************************************/ #include "cppcompletionassist.h" -#include "cpphighlightingsupportinternal.h" #include "cppmodelmanagersupportinternal.h" +#include "builtineditordocumentprocessor.h" #include <QCoreApplication> @@ -56,13 +56,13 @@ QString ModelManagerSupportInternal::displayName() const "Qt Creator Built-in"); } -CppCompletionAssistProvider *ModelManagerSupportInternal::completionAssistProvider() +BaseEditorDocumentProcessor *ModelManagerSupportInternal::editorDocumentProcessor( + TextEditor::BaseTextDocument *baseTextDocument) { - return m_completionAssistProvider.data(); + return new BuiltinEditorDocumentProcessor(baseTextDocument); } -CppHighlightingSupport *ModelManagerSupportInternal::highlightingSupport( - TextEditor::BaseTextDocument *baseTextDocument) +CppCompletionAssistProvider *ModelManagerSupportInternal::completionAssistProvider() { - return new CppHighlightingSupportInternal(baseTextDocument); + return m_completionAssistProvider.data(); } diff --git a/src/plugins/cpptools/cppmodelmanagersupportinternal.h b/src/plugins/cpptools/cppmodelmanagersupportinternal.h index a55280af9d..2e9a335ba5 100644 --- a/src/plugins/cpptools/cppmodelmanagersupportinternal.h +++ b/src/plugins/cpptools/cppmodelmanagersupportinternal.h @@ -49,8 +49,8 @@ public: virtual QString displayName() const; virtual CppCompletionAssistProvider *completionAssistProvider(); - virtual CppHighlightingSupport *highlightingSupport( - TextEditor::BaseTextDocument *baseTextDocument); + virtual BaseEditorDocumentProcessor *editorDocumentProcessor( + TextEditor::BaseTextDocument *baseTextDocument); private: QScopedPointer<CppCompletionAssistProvider> m_completionAssistProvider; diff --git a/src/plugins/cpptools/cppsemanticinfo.cpp b/src/plugins/cpptools/cppsemanticinfo.cpp index 09407681c3..5ab57d0ca1 100644 --- a/src/plugins/cpptools/cppsemanticinfo.cpp +++ b/src/plugins/cpptools/cppsemanticinfo.cpp @@ -32,6 +32,6 @@ using namespace CppTools; SemanticInfo::SemanticInfo() - : revision(0), forced(false), complete(true) + : revision(0), complete(true), localUsesUpdated(false) { } diff --git a/src/plugins/cpptools/cppsemanticinfo.h b/src/plugins/cpptools/cppsemanticinfo.h index c0968edb3a..4066bfef40 100644 --- a/src/plugins/cpptools/cppsemanticinfo.h +++ b/src/plugins/cpptools/cppsemanticinfo.h @@ -45,28 +45,22 @@ class CPPTOOLS_EXPORT SemanticInfo public: struct Source { - const CPlusPlus::Snapshot snapshot; const QString fileName; const QByteArray code; - const int line; - const int column; const unsigned revision; const bool force; - Source() - : line(0), column(0), revision(0), force(false) - { } + Source() : revision(0), force(false) {} - Source(const CPlusPlus::Snapshot &snapshot, - const QString &fileName, + Source(const QString &fileName, const QByteArray &code, - int line, int column, unsigned revision, bool force) - : snapshot(snapshot), fileName(fileName), - code(code), line(line), column(column), - revision(revision), force(force) - { } + : fileName(fileName) + , code(code) + , revision(revision) + , force(force) + {} }; public: @@ -78,10 +72,12 @@ public: SemanticInfo(); unsigned revision; - bool forced; bool complete; CPlusPlus::Snapshot snapshot; CPlusPlus::Document::Ptr doc; + + // Widget specific (e.g. related to cursor position) + bool localUsesUpdated; LocalUseMap localUses; }; diff --git a/src/plugins/cpptools/cppsemanticinfoupdater.cpp b/src/plugins/cpptools/cppsemanticinfoupdater.cpp new file mode 100644 index 0000000000..71fbb16e46 --- /dev/null +++ b/src/plugins/cpptools/cppsemanticinfoupdater.cpp @@ -0,0 +1,226 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +** GNU Lesser General Public License Usage +** 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 +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "builtineditordocumentparser.h" +#include "cpplocalsymbols.h" +#include "cppsemanticinfoupdater.h" + +#include <utils/qtcassert.h> +#include <utils/qtcoverride.h> +#include <utils/runextensions.h> + +#include <cplusplus/Control.h> +#include <cplusplus/CppDocument.h> +#include <cplusplus/TranslationUnit.h> + +enum { debug = 0 }; + +using namespace CPlusPlus; +using namespace CppTools; + +namespace CppTools { + +class SemanticInfoUpdaterPrivate +{ +public: + class FuturizedTopLevelDeclarationProcessor: public CPlusPlus::TopLevelDeclarationProcessor + { + public: + FuturizedTopLevelDeclarationProcessor(QFutureInterface<void> &future): m_future(future) {} + bool processDeclaration(CPlusPlus::DeclarationAST *) { return !isCanceled(); } + bool isCanceled() { return m_future.isCanceled(); } + private: + QFutureInterface<void> m_future; + }; + +public: + SemanticInfoUpdaterPrivate(SemanticInfoUpdater *q, BuiltinEditorDocumentParser *m_parser); + ~SemanticInfoUpdaterPrivate(); + + SemanticInfo semanticInfo() const; + void setSemanticInfo(const SemanticInfo &semanticInfo, bool emitSignal); + + SemanticInfo update(const SemanticInfo::Source &source, + bool emitSignalWhenFinished, + FuturizedTopLevelDeclarationProcessor *processor); + + bool reuseCurrentSemanticInfo(const SemanticInfo::Source &source, bool emitSignalWhenFinished); + + void update_helper(QFutureInterface<void> &future, const SemanticInfo::Source source); + +public: + SemanticInfoUpdater *q; + mutable QMutex m_lock; + SemanticInfo m_semanticInfo; + QFuture<void> m_future; + BuiltinEditorDocumentParser *m_parser; +}; + +SemanticInfoUpdaterPrivate::SemanticInfoUpdaterPrivate(SemanticInfoUpdater *q, + BuiltinEditorDocumentParser *parser) + : q(q) + , m_parser(parser) +{ +} + +SemanticInfoUpdaterPrivate::~SemanticInfoUpdaterPrivate() +{ + m_future.cancel(); + m_future.waitForFinished(); +} + +SemanticInfo SemanticInfoUpdaterPrivate::semanticInfo() const +{ + QMutexLocker locker(&m_lock); + return m_semanticInfo; +} + +void SemanticInfoUpdaterPrivate::setSemanticInfo(const SemanticInfo &semanticInfo, bool emitSignal) +{ + { + QMutexLocker locker(&m_lock); + m_semanticInfo = semanticInfo; + } + if (emitSignal) { + if (debug) + qDebug() << "SemanticInfoUpdater: emiting new info"; + emit q->updated(semanticInfo); + } +} + +SemanticInfo SemanticInfoUpdaterPrivate::update(const SemanticInfo::Source &source, + bool emitSignalWhenFinished, + FuturizedTopLevelDeclarationProcessor *processor) +{ + if (debug) + qDebug() << "SemanticInfoUpdater: update() - source revision" << source.revision; + + SemanticInfo newSemanticInfo; + newSemanticInfo.revision = source.revision; + + QTC_ASSERT(m_parser, return newSemanticInfo); + newSemanticInfo.snapshot = m_parser->snapshot(); + QTC_ASSERT(newSemanticInfo.snapshot.contains(source.fileName), return newSemanticInfo); + + Document::Ptr doc = newSemanticInfo.snapshot.preprocessedDocument(source.code, source.fileName); + if (processor) + doc->control()->setTopLevelDeclarationProcessor(processor); + doc->check(); + if (processor && processor->isCanceled()) + newSemanticInfo.complete = false; + newSemanticInfo.doc = doc; + + if (debug) + qDebug() << "SemanticInfoUpdater: update() - re-calculated document. Canceled =" + << !newSemanticInfo.complete; + + setSemanticInfo(newSemanticInfo, emitSignalWhenFinished); + return newSemanticInfo; +} + +bool SemanticInfoUpdaterPrivate::reuseCurrentSemanticInfo(const SemanticInfo::Source &source, + bool emitSignalWhenFinished) +{ + const SemanticInfo currentSemanticInfo = semanticInfo(); + + if (!source.force + && currentSemanticInfo.complete + && currentSemanticInfo.revision == source.revision + && currentSemanticInfo.doc + && currentSemanticInfo.doc->translationUnit()->ast() + && currentSemanticInfo.doc->fileName() == source.fileName) { + SemanticInfo newSemanticInfo; + newSemanticInfo.revision = source.revision; + newSemanticInfo.doc = currentSemanticInfo.doc; + newSemanticInfo.snapshot = currentSemanticInfo.snapshot; // ### TODO: use the new snapshot. + setSemanticInfo(newSemanticInfo, emitSignalWhenFinished); + if (debug) + qDebug() << "SemanticInfoUpdater: re-using current semantic info - source.revision" + << source.revision; + return true; + } + + return false; +} + +void SemanticInfoUpdaterPrivate::update_helper(QFutureInterface<void> &future, + const SemanticInfo::Source source) +{ + FuturizedTopLevelDeclarationProcessor processor(future); + update(source, true, &processor); +} + +SemanticInfoUpdater::SemanticInfoUpdater(BuiltinEditorDocumentParser *parser) + : d(new SemanticInfoUpdaterPrivate(this, parser)) +{ +} + +SemanticInfoUpdater::~SemanticInfoUpdater() +{ + d->m_future.cancel(); + d->m_future.waitForFinished(); +} + +SemanticInfo SemanticInfoUpdater::update(const SemanticInfo::Source &source) +{ + if (debug) + qDebug() << "SemanticInfoUpdater: update() - synchronous"; + d->m_future.cancel(); + + const bool emitSignalWhenFinished = false; + if (d->reuseCurrentSemanticInfo(source, emitSignalWhenFinished)) { + d->m_future = QFuture<void>(); + return semanticInfo(); + } + + return d->update(source, emitSignalWhenFinished, 0); +} + +void SemanticInfoUpdater::updateDetached(const SemanticInfo::Source source) +{ + if (debug) + qDebug() << "SemanticInfoUpdater: updateDetached() - asynchronous"; + d->m_future.cancel(); + + const bool emitSignalWhenFinished = true; + if (d->reuseCurrentSemanticInfo(source, emitSignalWhenFinished)) { + d->m_future = QFuture<void>(); + return; + } + + d->m_future = QtConcurrent::run<SemanticInfoUpdaterPrivate, void, const SemanticInfo::Source> + (&SemanticInfoUpdaterPrivate::update_helper, d.data(), source); +} + +SemanticInfo SemanticInfoUpdater::semanticInfo() const +{ + return d->semanticInfo(); +} + +} // namespace CppTools diff --git a/src/plugins/cpptools/cpphighlightingsupportinternal.h b/src/plugins/cpptools/cppsemanticinfoupdater.h index 14fb8236ce..0436bf1846 100644 --- a/src/plugins/cpptools/cpphighlightingsupportinternal.h +++ b/src/plugins/cpptools/cppsemanticinfoupdater.h @@ -27,37 +27,40 @@ ** ****************************************************************************/ -#ifndef CPPTOOLS_CPPHIGHLIGHTINGSUPPORTINTERNAL_H -#define CPPTOOLS_CPPHIGHLIGHTINGSUPPORTINTERNAL_H +#ifndef CPPSEMANTICINFOUPDATER_H +#define CPPSEMANTICINFOUPDATER_H -#include "cpphighlightingsupport.h" +#include "cppsemanticinfo.h" -#include <QFuture> +#include <QObject> +#include <QScopedPointer> namespace CppTools { -namespace Internal { -class CppHighlightingSupportInternal: public CppHighlightingSupport +class BuiltinEditorDocumentParser; +class SemanticInfoUpdaterPrivate; + +class SemanticInfoUpdater : public QObject { + Q_OBJECT + Q_DISABLE_COPY(SemanticInfoUpdater) + public: - CppHighlightingSupportInternal(TextEditor::BaseTextDocument *baseTextDocument); - virtual ~CppHighlightingSupportInternal(); + explicit SemanticInfoUpdater(BuiltinEditorDocumentParser *parser); + ~SemanticInfoUpdater(); - virtual bool requiresSemanticInfo() const - { return true; } + SemanticInfo semanticInfo() const; - virtual bool hightlighterHandlesDiagnostics() const - { return false; } + SemanticInfo update(const SemanticInfo::Source &source); + void updateDetached(const SemanticInfo::Source source); - virtual bool hightlighterHandlesIfdefedOutBlocks() const - { return false; } +signals: + void updated(CppTools::SemanticInfo semanticInfo); - virtual QFuture<TextEditor::HighlightingResult> highlightingFuture( - const CPlusPlus::Document::Ptr &doc, - const CPlusPlus::Snapshot &snapshot) const; +private: + QScopedPointer<SemanticInfoUpdaterPrivate> d; }; -} // namespace Internal } // namespace CppTools -#endif // CPPTOOLS_CPPHIGHLIGHTINGSUPPORTINTERNAL_H +#endif // CPPSEMANTICINFOUPDATER_H diff --git a/src/plugins/cpptools/cppsourceprocessor_test.cpp b/src/plugins/cpptools/cppsourceprocessor_test.cpp index af59cd8334..9b14594954 100644 --- a/src/plugins/cpptools/cppsourceprocessor_test.cpp +++ b/src/plugins/cpptools/cppsourceprocessor_test.cpp @@ -33,8 +33,8 @@ #include "cppmodelmanager.h" #include "cppsourceprocessertesthelper.h" #include "cppsourceprocessor.h" -#include "cpptoolseditorsupport.h" #include "cpptoolstestcase.h" +#include "editordocumenthandle.h" #include <texteditor/basetexteditor.h> @@ -140,13 +140,11 @@ void CppToolsPlugin::test_cppsourceprocessor_includes_cyclic() QVERIFY(testCase.openBaseTextEditor(fileName1, &editor)); testCase.closeEditorAtEndOfTestCase(editor); - // Get editor snapshot - CppEditorSupport *cppEditorSupport = CppModelManagerInterface::instance() - ->cppEditorSupport(editor); - QVERIFY(cppEditorSupport); - BuiltinEditorDocumentParser::Ptr documentParser = cppEditorSupport->documentParser(); - QVERIFY(documentParser); - Snapshot snapshot = documentParser->snapshot(); + // Check editor snapshot + const QString filePath = editor->document()->filePath(); + BuiltinEditorDocumentParser *parser = BuiltinEditorDocumentParser::get(filePath); + QVERIFY(parser); + Snapshot snapshot = parser->snapshot(); QCOMPARE(snapshot.size(), 3); // Configuration file included // Check includes diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro index a0e45d6000..941784703b 100644 --- a/src/plugins/cpptools/cpptools.pro +++ b/src/plugins/cpptools/cpptools.pro @@ -5,7 +5,9 @@ include(../../qtcreatorplugin.pri) HEADERS += \ abstracteditorsupport.h \ baseeditordocumentparser.h \ + baseeditordocumentprocessor.h \ builtineditordocumentparser.h \ + builtineditordocumentprocessor.h \ builtinindexingsupport.h \ commentssettings.h \ completionsettingspage.h \ @@ -26,8 +28,6 @@ HEADERS += \ cppfilesettingspage.h \ cppfindreferences.h \ cppfunctionsfilter.h \ - cpphighlightingsupport.h \ - cpphighlightingsupportinternal.h \ cppindexingsupport.h \ cpplocalsymbols.h \ cpplocatordata.h \ @@ -42,20 +42,22 @@ HEADERS += \ cppqtstyleindenter.h \ cpprefactoringchanges.h \ cppsemanticinfo.h \ + cppsemanticinfoupdater.h \ cppsourceprocessor.h \ cpptools_global.h \ cpptoolsconstants.h \ - cpptoolseditorsupport.h \ cpptoolsplugin.h \ cpptoolsreuse.h \ cpptoolssettings.h \ cppworkingcopy.h \ doxygengenerator.h \ + editordocumenthandle.h \ functionutils.h \ includeutils.h \ indexitem.h \ insertionpointlocator.h \ searchsymbols.h \ + semantichighlighter.h \ stringtable.h \ symbolfinder.h \ symbolsfindfilter.h \ @@ -64,7 +66,9 @@ HEADERS += \ SOURCES += \ abstracteditorsupport.cpp \ baseeditordocumentparser.cpp \ + baseeditordocumentprocessor.cpp \ builtineditordocumentparser.cpp \ + builtineditordocumentprocessor.cpp \ builtinindexingsupport.cpp \ commentssettings.cpp \ completionsettingspage.cpp \ @@ -85,8 +89,6 @@ SOURCES += \ cppfilesettingspage.cpp \ cppfindreferences.cpp \ cppfunctionsfilter.cpp \ - cpphighlightingsupport.cpp \ - cpphighlightingsupportinternal.cpp \ cppindexingsupport.cpp \ cpplocalsymbols.cpp \ cpplocatordata.cpp \ @@ -101,18 +103,20 @@ SOURCES += \ cppqtstyleindenter.cpp \ cpprefactoringchanges.cpp \ cppsemanticinfo.cpp \ + cppsemanticinfoupdater.cpp \ cppsourceprocessor.cpp \ - cpptoolseditorsupport.cpp \ cpptoolsplugin.cpp \ cpptoolsreuse.cpp \ cpptoolssettings.cpp \ cppworkingcopy.cpp \ doxygengenerator.cpp \ + editordocumenthandle.cpp \ functionutils.cpp \ includeutils.cpp \ indexitem.cpp \ insertionpointlocator.cpp \ searchsymbols.cpp \ + semantichighlighter.cpp \ stringtable.cpp \ symbolfinder.cpp \ symbolsfindfilter.cpp \ diff --git a/src/plugins/cpptools/cpptools.qbs b/src/plugins/cpptools/cpptools.qbs index 1c47b7ab60..d3f8681b9d 100644 --- a/src/plugins/cpptools/cpptools.qbs +++ b/src/plugins/cpptools/cpptools.qbs @@ -25,7 +25,9 @@ QtcPlugin { files: [ "abstracteditorsupport.cpp", "abstracteditorsupport.h", "baseeditordocumentparser.cpp", "baseeditordocumentparser.h", + "baseeditordocumentprocessor.cpp", "baseeditordocumentprocessor.h", "builtineditordocumentparser.cpp", "builtineditordocumentparser.h", + "builtineditordocumentprocessor.cpp", "builtineditordocumentprocessor.h", "builtinindexingsupport.cpp", "builtinindexingsupport.h", "commentssettings.cpp", "commentssettings.h", "completionsettingspage.cpp", "completionsettingspage.h", "completionsettingspage.ui", @@ -46,8 +48,6 @@ QtcPlugin { "cppfilesettingspage.cpp", "cppfilesettingspage.h", "cppfilesettingspage.ui", "cppfindreferences.cpp", "cppfindreferences.h", "cppfunctionsfilter.cpp", "cppfunctionsfilter.h", - "cpphighlightingsupport.cpp", "cpphighlightingsupport.h", - "cpphighlightingsupportinternal.cpp", "cpphighlightingsupportinternal.h", "cppindexingsupport.cpp", "cppindexingsupport.h", "cpplocalsymbols.cpp", "cpplocalsymbols.h", "cpplocatordata.cpp", "cpplocatordata.h", @@ -62,21 +62,23 @@ QtcPlugin { "cppqtstyleindenter.cpp", "cppqtstyleindenter.h", "cpprefactoringchanges.cpp", "cpprefactoringchanges.h", "cppsemanticinfo.cpp", "cppsemanticinfo.h", + "cppsemanticinfoupdater.cpp", "cppsemanticinfoupdater.h", "cppsourceprocessor.cpp", "cppsourceprocessor.h", "cpptools.qrc", "cpptools_global.h", "cpptoolsconstants.h", - "cpptoolseditorsupport.cpp", "cpptoolseditorsupport.h", "cpptoolsplugin.cpp", "cpptoolsplugin.h", "cpptoolsreuse.cpp", "cpptoolsreuse.h", "cpptoolssettings.cpp", "cpptoolssettings.h", "cppworkingcopy.cpp", "cppworkingcopy.h", "doxygengenerator.cpp", "doxygengenerator.h", + "editordocumenthandle.cpp", "editordocumenthandle.h", "functionutils.cpp", "functionutils.h", "includeutils.cpp", "includeutils.h", "indexitem.cpp", "indexitem.h", "insertionpointlocator.cpp", "insertionpointlocator.h", "searchsymbols.cpp", "searchsymbols.h", + "semantichighlighter.cpp", "semantichighlighter.h", "stringtable.cpp", "stringtable.h", "symbolfinder.cpp", "symbolfinder.h", "symbolsfindfilter.cpp", "symbolsfindfilter.h", diff --git a/src/plugins/cpptools/cppworkingcopy.h b/src/plugins/cpptools/cppworkingcopy.h index 3775838885..df20c57bb2 100644 --- a/src/plugins/cpptools/cppworkingcopy.h +++ b/src/plugins/cpptools/cppworkingcopy.h @@ -52,6 +52,9 @@ public: QByteArray source(const QString &fileName) const { return _elements.value(fileName).first; } + unsigned revision(const QString &fileName) const + { return _elements.value(fileName).second; } + QPair<QByteArray, unsigned> get(const QString &fileName) const { return _elements.value(fileName); } diff --git a/src/plugins/cpptools/cpphighlightingsupport.cpp b/src/plugins/cpptools/editordocumenthandle.cpp index 9c3bcd3dd5..d30e1c773d 100644 --- a/src/plugins/cpptools/cpphighlightingsupport.cpp +++ b/src/plugins/cpptools/editordocumenthandle.cpp @@ -27,16 +27,23 @@ ** ****************************************************************************/ -#include "cpphighlightingsupport.h" +#include "editordocumenthandle.h" -using namespace CppTools; +namespace CppTools { -CppHighlightingSupport::CppHighlightingSupport(TextEditor::BaseTextDocument *baseTextDocument) - : m_baseTextDocument(baseTextDocument) +/*! + \class CppTools::EditorDocumentHandle + + \brief The EditorDocumentHandle class provides an interface to an opened + C++ editor document. +*/ + +EditorDocumentHandle::EditorDocumentHandle() { - Q_ASSERT(baseTextDocument); } -CppHighlightingSupport::~CppHighlightingSupport() +EditorDocumentHandle::~EditorDocumentHandle() { } + +} // namespace CppTools diff --git a/src/plugins/cpptools/editordocumenthandle.h b/src/plugins/cpptools/editordocumenthandle.h new file mode 100644 index 0000000000..81ba868922 --- /dev/null +++ b/src/plugins/cpptools/editordocumenthandle.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +** GNU Lesser General Public License Usage +** 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 +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef EDITORDOCUMENTHANDLE_H +#define EDITORDOCUMENTHANDLE_H + +#include "baseeditordocumentprocessor.h" +#include "cpptools_global.h" + +namespace CppTools { + +class CPPTOOLS_EXPORT EditorDocumentHandle +{ +public: + EditorDocumentHandle(); + virtual ~EditorDocumentHandle(); + + // For the Working Copy + virtual QString filePath() const = 0; + virtual QByteArray contents() const = 0; + virtual unsigned revision() const = 0; + + // For updating if new project info is set + virtual BaseEditorDocumentProcessor *processor() = 0; +}; + +} // namespace CppTools + +#endif // EDITORDOCUMENTHANDLE_H diff --git a/src/plugins/cpptools/semantichighlighter.cpp b/src/plugins/cpptools/semantichighlighter.cpp new file mode 100644 index 0000000000..33a77261a6 --- /dev/null +++ b/src/plugins/cpptools/semantichighlighter.cpp @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +** GNU Lesser General Public License Usage +** 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 +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "semantichighlighter.h" + +#include <texteditor/fontsettings.h> +#include <texteditor/syntaxhighlighter.h> + +#include <utils/qtcassert.h> + +enum { debug = 0 }; + +using namespace CPlusPlus; +using TextEditor::SemanticHighlighter::incrementalApplyExtraAdditionalFormats; +using TextEditor::SemanticHighlighter::clearExtraAdditionalFormatsUntilEnd; + +namespace CppTools { + +SemanticHighlighter::SemanticHighlighter(TextEditor::BaseTextDocument *baseTextDocument) + : QObject(baseTextDocument) + , m_baseTextDocument(baseTextDocument) + , m_revision(0) +{ + QTC_CHECK(m_baseTextDocument); + + connect(baseTextDocument, &TextEditor::BaseTextDocument::fontSettingsChanged, + this, &SemanticHighlighter::onDocumentFontSettingsChanged); + + updateFormatMapFromFontSettings(); +} + +SemanticHighlighter::~SemanticHighlighter() +{ + if (m_watcher) { + disconnectWatcher(); + m_watcher->cancel(); + m_watcher->waitForFinished(); + } +} + +void SemanticHighlighter::setHighlightingRunner(HighlightingRunner highlightingRunner) +{ + m_highlightingRunner = highlightingRunner; +} + +void SemanticHighlighter::run() +{ + QTC_ASSERT(m_highlightingRunner, return); + + if (debug) + qDebug() << "SemanticHighlighter: run()"; + + if (m_watcher) { + disconnectWatcher(); + m_watcher->cancel(); + } + m_watcher.reset(new QFutureWatcher<TextEditor::HighlightingResult>); + connectWatcher(); + + m_revision = documentRevision(); + m_watcher->setFuture(m_highlightingRunner()); +} + +void SemanticHighlighter::onDocumentFontSettingsChanged() +{ + updateFormatMapFromFontSettings(); + run(); +} + +void SemanticHighlighter::onHighlighterResultAvailable(int from, int to) +{ + if (documentRevision() != m_revision) + return; // outdated + else if (!m_watcher || m_watcher->isCanceled()) + return; // aborted + + if (debug) + qDebug() << "SemanticHighlighter: onHighlighterResultAvailable()" << from << to; + + TextEditor::SyntaxHighlighter *highlighter = m_baseTextDocument->syntaxHighlighter(); + QTC_ASSERT(highlighter, return); + incrementalApplyExtraAdditionalFormats(highlighter, m_watcher->future(), from, to, m_formatMap); +} + +void SemanticHighlighter::onHighlighterFinished() +{ + QTC_ASSERT(m_watcher, return); + if (!m_watcher->isCanceled() && documentRevision() == m_revision) { + TextEditor::SyntaxHighlighter *highlighter = m_baseTextDocument->syntaxHighlighter(); + QTC_CHECK(highlighter); + if (highlighter) { + if (debug) + qDebug() << "SemanticHighlighter: onHighlighterFinished() - clearing formats"; + clearExtraAdditionalFormatsUntilEnd(highlighter, m_watcher->future()); + } + } + m_watcher.reset(); +} + +void SemanticHighlighter::connectWatcher() +{ + typedef QFutureWatcher<TextEditor::HighlightingResult> Watcher; + connect(m_watcher.data(), &Watcher::resultsReadyAt, + this, &SemanticHighlighter::onHighlighterResultAvailable); + connect(m_watcher.data(), &Watcher::finished, + this, &SemanticHighlighter::onHighlighterFinished); +} + +void SemanticHighlighter::disconnectWatcher() +{ + typedef QFutureWatcher<TextEditor::HighlightingResult> Watcher; + disconnect(m_watcher.data(), &Watcher::resultsReadyAt, + this, &SemanticHighlighter::onHighlighterResultAvailable); + disconnect(m_watcher.data(), &Watcher::finished, + this, &SemanticHighlighter::onHighlighterFinished); +} + +unsigned SemanticHighlighter::documentRevision() const +{ + return m_baseTextDocument->document()->revision(); +} + +void SemanticHighlighter::updateFormatMapFromFontSettings() +{ + const TextEditor::FontSettings &fs = m_baseTextDocument->fontSettings(); + + m_formatMap[TypeUse] = fs.toTextCharFormat(TextEditor::C_TYPE); + m_formatMap[LocalUse] = fs.toTextCharFormat(TextEditor::C_LOCAL); + m_formatMap[FieldUse] = fs.toTextCharFormat(TextEditor::C_FIELD); + m_formatMap[EnumerationUse] = fs.toTextCharFormat(TextEditor::C_ENUMERATION); + m_formatMap[VirtualMethodUse] = fs.toTextCharFormat(TextEditor::C_VIRTUAL_METHOD); + m_formatMap[LabelUse] = fs.toTextCharFormat(TextEditor::C_LABEL); + m_formatMap[MacroUse] = fs.toTextCharFormat(TextEditor::C_PREPROCESSOR); + m_formatMap[FunctionUse] = fs.toTextCharFormat(TextEditor::C_FUNCTION); + m_formatMap[PseudoKeywordUse] = fs.toTextCharFormat(TextEditor::C_KEYWORD); + m_formatMap[StringUse] = fs.toTextCharFormat(TextEditor::C_STRING); +} + +} // namespace CppTools diff --git a/src/plugins/cpptools/cpphighlightingsupport.h b/src/plugins/cpptools/semantichighlighter.h index d4be6b1416..fb12bf34e6 100644 --- a/src/plugins/cpptools/cpphighlightingsupport.h +++ b/src/plugins/cpptools/semantichighlighter.h @@ -27,23 +27,28 @@ ** ****************************************************************************/ -#ifndef CPPTOOLS_CPPHIGHLIGHTINGSUPPORT_H -#define CPPTOOLS_CPPHIGHLIGHTINGSUPPORT_H +#ifndef SEMANTICHIGHLIGHTER_H +#define SEMANTICHIGHLIGHTER_H +#include "cppsemanticinfo.h" #include "cpptools_global.h" +#include <texteditor/basetextdocument.h> #include <texteditor/semantichighlighter.h> -#include <cplusplus/CppDocument.h> +#include <QFutureWatcher> +#include <QScopedPointer> +#include <QTextEdit> -#include <QFuture> - -namespace TextEditor { class BaseTextDocument; } +#include <functional> namespace CppTools { -class CPPTOOLS_EXPORT CppHighlightingSupport +class CPPTOOLS_EXPORT SemanticHighlighter : public QObject { + Q_OBJECT + Q_DISABLE_COPY(SemanticHighlighter) + public: enum Kind { Unknown = 0, @@ -59,27 +64,39 @@ public: StringUse }; + typedef std::function<QFuture<TextEditor::HighlightingResult> ()> HighlightingRunner; + public: - CppHighlightingSupport(TextEditor::BaseTextDocument *baseTextDocument); - virtual ~CppHighlightingSupport() = 0; + explicit SemanticHighlighter(TextEditor::BaseTextDocument *baseTextDocument); + ~SemanticHighlighter(); + + void setHighlightingRunner(HighlightingRunner highlightingRunner); - virtual bool requiresSemanticInfo() const = 0; + void run(); - virtual bool hightlighterHandlesDiagnostics() const = 0; - virtual bool hightlighterHandlesIfdefedOutBlocks() const = 0; +private slots: + void onDocumentFontSettingsChanged(); - virtual QFuture<TextEditor::HighlightingResult> highlightingFuture( - const CPlusPlus::Document::Ptr &doc, - const CPlusPlus::Snapshot &snapshot) const = 0; + void onHighlighterResultAvailable(int from, int to); + void onHighlighterFinished(); -protected: - TextEditor::BaseTextDocument *baseTextDocument() const - { return m_baseTextDocument; } +private: + void connectWatcher(); + void disconnectWatcher(); + + unsigned documentRevision() const; + void updateFormatMapFromFontSettings(); private: TextEditor::BaseTextDocument *m_baseTextDocument; + + unsigned m_revision; + QScopedPointer<QFutureWatcher<TextEditor::HighlightingResult>> m_watcher; + QHash<int, QTextCharFormat> m_formatMap; + + HighlightingRunner m_highlightingRunner; }; } // namespace CppTools -#endif // CPPTOOLS_CPPHIGHLIGHTINGSUPPORT_H +#endif // SEMANTICHIGHLIGHTER_H diff --git a/src/plugins/designer/gotoslot_test.cpp b/src/plugins/designer/gotoslot_test.cpp index def152e985..7814af028d 100644 --- a/src/plugins/designer/gotoslot_test.cpp +++ b/src/plugins/designer/gotoslot_test.cpp @@ -33,9 +33,10 @@ #include <coreplugin/editormanager/editormanager.h> #include <coreplugin/testdatadir.h> +#include <cpptools/builtineditordocumentprocessor.h> #include <cpptools/cppmodelmanager.h> -#include <cpptools/cpptoolseditorsupport.h> #include <cpptools/cpptoolstestcase.h> +#include <cpptools/editordocumenthandle.h> #include <cplusplus/CppDocument.h> #include <cplusplus/Overview.h> @@ -163,8 +164,6 @@ public: closeEditorAtEndOfTestCase(editor); editors << e; } - TextEditor::BaseTextEditor *cppFileEditor = editors.at(0); - TextEditor::BaseTextEditor *hFileEditor = editors.at(1); const QString cppFile = files.at(0); const QString hFile = files.at(1); @@ -184,18 +183,22 @@ public: // Wait for updated documents foreach (TextEditor::BaseTextEditor *editor, editors) { - if (CppEditorSupport *editorSupport = m_modelManager->cppEditorSupport(editor)) { - while (editorSupport->isUpdatingDocument()) + const QString filePath = editor->document()->filePath(); + if (auto parser = BuiltinEditorDocumentParser::get(filePath)) { + forever { + if (Document::Ptr document = parser->document()) { + if (document->editorRevision() == 2) + break; + } QApplication::processEvents(); + } } } // Compare - const Document::Ptr cppDocument - = m_modelManager->cppEditorSupport(cppFileEditor)->documentParser()->document(); + const Document::Ptr cppDocument = BuiltinEditorDocumentParser::get(cppFile)->document(); QVERIFY(checkDiagsnosticMessages(cppDocument)); - const Document::Ptr hDocument - = m_modelManager->cppEditorSupport(hFileEditor)->documentParser()->document(); + const Document::Ptr hDocument = BuiltinEditorDocumentParser::get(hFile)->document(); QVERIFY(checkDiagsnosticMessages(hDocument)); QVERIFY(documentContainsFunctionDefinition(cppDocument, |