Commit c105ae47 authored by Christian Kamm's avatar Christian Kamm

QmlJS: Add semantic highlighting.

Change-Id: If9293244075cff1a52801b50cdbb77248ecd21ea
Reviewed-on: http://codereview.qt.nokia.com/3310Reviewed-by: default avatarFawzi Mohamed <fawzi.mohamed@nokia.com>
parent 1b9af316
......@@ -56,6 +56,20 @@ QList<const QmlComponentChain *> QmlComponentChain::instantiatingComponents() co
return m_instantiatingComponents;
}
const ObjectValue *QmlComponentChain::idScope() const
{
if (!m_document)
return 0;
return m_document->bind()->idEnvironment();
}
const ObjectValue *QmlComponentChain::rootObjectScope() const
{
if (!m_document)
return 0;
return m_document->bind()->rootObjectValue();
}
void QmlComponentChain::addInstantiatingComponent(const QmlComponentChain *component)
{
m_instantiatingComponents.append(component);
......@@ -188,9 +202,9 @@ static void collectScopes(const QmlComponentChain *chain, QList<const ObjectValu
if (!chain->document())
return;
if (ObjectValue *root = chain->document()->bind()->rootObjectValue())
if (const ObjectValue *root = chain->rootObjectScope())
target->append(root);
if (ObjectValue *ids = chain->document()->bind()->idEnvironment())
if (const ObjectValue *ids = chain->idScope())
target->append(ids);
}
......@@ -294,4 +308,3 @@ void ScopeChain::makeComponentChain(
}
}
}
......@@ -58,6 +58,9 @@ public:
Document::Ptr document() const;
QList<const QmlComponentChain *> instantiatingComponents() const;
const ObjectValue *idScope() const;
const ObjectValue *rootObjectScope() const;
// takes ownership
void addInstantiatingComponent(const QmlComponentChain *component);
......
......@@ -442,7 +442,7 @@ bool CheckSymbols::visit(NamespaceAST *ast)
if (! tok.generated()) {
unsigned line, column;
getTokenStartPosition(ast->identifier_token, &line, &column);
Use use(line, column, tok.length());
Use use(line, column, tok.length(), SemanticInfo::TypeUse);
addUse(use);
}
}
......@@ -457,7 +457,7 @@ bool CheckSymbols::visit(UsingDirectiveAST *)
bool CheckSymbols::visit(EnumeratorAST *ast)
{
addUse(ast->identifier_token, Use::Static);
addUse(ast->identifier_token, SemanticInfo::StaticUse);
return true;
}
......@@ -469,7 +469,7 @@ bool CheckSymbols::visit(SimpleDeclarationAST *ast)
if (NameAST *declId = declaratorId(ast->declarator_list->value)) {
if (Function *funTy = decl->type()->asFunctionType()) {
if (funTy->isVirtual()) {
addUse(declId, Use::VirtualMethod);
addUse(declId, SemanticInfo::VirtualMethodUse);
} else if (maybeVirtualMethod(decl->name())) {
addVirtualMethod(_context.lookup(decl->name(), decl->enclosingScope()), declId, funTy->argumentCount());
}
......@@ -490,7 +490,7 @@ bool CheckSymbols::visit(ElaboratedTypeSpecifierAST *ast)
{
accept(ast->attribute_list);
accept(ast->name);
addUse(ast->name, Use::Type);
addUse(ast->name, SemanticInfo::TypeUse);
return false;
}
......@@ -643,7 +643,7 @@ void CheckSymbols::checkName(NameAST *ast, Scope *scope)
if (ast->asDestructorName() != 0) {
Class *klass = scope->asClass();
if (hasVirtualDestructor(_context.lookupType(klass)))
addUse(ast, Use::VirtualMethod);
addUse(ast, SemanticInfo::VirtualMethodUse);
} else if (maybeType(ast->name) || maybeStatic(ast->name)) {
const QList<LookupItem> candidates = _context.lookup(ast->name, scope);
addTypeOrStatic(candidates, ast);
......@@ -693,7 +693,7 @@ bool CheckSymbols::visit(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, Use::Type);
addUse(template_id, SemanticInfo::TypeUse);
binding = 0; // there's no way we can find a binding.
}
......@@ -714,7 +714,7 @@ bool CheckSymbols::visit(QualifiedNameAST *ast)
if (binding && ast->unqualified_name) {
if (ast->unqualified_name->asDestructorName() != 0) {
if (hasVirtualDestructor(binding))
addUse(ast->unqualified_name, Use::VirtualMethod);
addUse(ast->unqualified_name, SemanticInfo::VirtualMethodUse);
} else {
addTypeOrStatic(binding->find(ast->unqualified_name->name), ast->unqualified_name);
}
......@@ -729,7 +729,7 @@ bool CheckSymbols::visit(QualifiedNameAST *ast)
bool CheckSymbols::visit(TypenameTypeParameterAST *ast)
{
addUse(ast->name, Use::Type);
addUse(ast->name, SemanticInfo::TypeUse);
accept(ast->type_id);
return false;
}
......@@ -737,7 +737,7 @@ bool CheckSymbols::visit(TypenameTypeParameterAST *ast)
bool CheckSymbols::visit(TemplateTypeParameterAST *ast)
{
accept(ast->template_parameter_list);
addUse(ast->name, Use::Type);
addUse(ast->name, SemanticInfo::TypeUse);
accept(ast->type_id);
return false;
}
......@@ -775,7 +775,7 @@ bool CheckSymbols::visit(FunctionDefinitionAST *ast)
declId = q->unqualified_name;
if (fun->isVirtual()) {
addUse(declId, Use::VirtualMethod);
addUse(declId, SemanticInfo::VirtualMethodUse);
} else if (maybeVirtualMethod(fun->name())) {
addVirtualMethod(_context.lookup(fun->name(), fun->enclosingScope()), declId, fun->argumentCount());
}
......@@ -798,7 +798,7 @@ bool CheckSymbols::visit(FunctionDefinitionAST *ast)
return false;
}
void CheckSymbols::addUse(NameAST *ast, Use::Kind kind)
void CheckSymbols::addUse(NameAST *ast, UseKind kind)
{
if (! ast)
return;
......@@ -822,7 +822,7 @@ void CheckSymbols::addUse(NameAST *ast, Use::Kind kind)
addUse(startToken, kind);
}
void CheckSymbols::addUse(unsigned tokenIndex, Use::Kind kind)
void CheckSymbols::addUse(unsigned tokenIndex, UseKind kind)
{
if (! tokenIndex)
return;
......@@ -871,7 +871,7 @@ void CheckSymbols::addType(ClassOrNamespace *b, NameAST *ast)
unsigned line, column;
getTokenStartPosition(startToken, &line, &column);
const unsigned length = tok.length();
const Use use(line, column, length, Use::Type);
const Use use(line, column, length, SemanticInfo::TypeUse);
addUse(use);
//qDebug() << "added use" << oo(ast->name) << line << column << length;
}
......@@ -913,10 +913,10 @@ void CheckSymbols::addTypeOrStatic(const QList<LookupItem> &candidates, NameAST
getTokenStartPosition(startToken, &line, &column);
const unsigned length = tok.length();
Use::Kind kind = Use::Type;
UseKind kind = SemanticInfo::TypeUse;
if (c->enclosingEnum() != 0)
kind = Use::Static;
kind = SemanticInfo::StaticUse;
const Use use(line, column, length, kind);
addUse(use);
......@@ -951,7 +951,7 @@ void CheckSymbols::addClassMember(const QList<LookupItem> &candidates, NameAST *
getTokenStartPosition(startToken, &line, &column);
const unsigned length = tok.length();
const Use use(line, column, length, Use::Field);
const Use use(line, column, length, SemanticInfo::FieldUse);
addUse(use);
break;
}
......@@ -976,7 +976,7 @@ void CheckSymbols::addStatic(const QList<LookupItem> &candidates, NameAST *ast)
getTokenStartPosition(startToken, &line, &column);
const unsigned length = tok.length();
const Use use(line, column, length, Use::Static);
const Use use(line, column, length, SemanticInfo::StaticUse);
addUse(use);
//qDebug() << "added use" << oo(ast->name) << line << column << length;
break;
......@@ -1015,7 +1015,7 @@ void CheckSymbols::addVirtualMethod(const QList<LookupItem> &candidates, NameAST
getTokenStartPosition(startToken, &line, &column);
const unsigned length = tok.length();
const Use use(line, column, length, Use::VirtualMethod);
const Use use(line, column, length, SemanticInfo::VirtualMethodUse);
addUse(use);
break;
}
......
......@@ -55,6 +55,7 @@ public:
virtual ~CheckSymbols();
typedef CppEditor::Internal::SemanticInfo::Use Use;
typedef CppEditor::Internal::SemanticInfo::UseKind UseKind;
virtual void run();
......@@ -110,8 +111,8 @@ protected:
void checkNamespace(NameAST *name);
void addUse(const Use &use);
void addUse(unsigned tokenIndex, Use::Kind kind);
void addUse(NameAST *name, Use::Kind kind);
void addUse(unsigned tokenIndex, UseKind kind);
void addUse(NameAST *name, UseKind kind);
void addType(ClassOrNamespace *b, NameAST *ast);
......
......@@ -87,6 +87,7 @@
#include <texteditor/tabsettings.h>
#include <texteditor/texteditorconstants.h>
#include <texteditor/refactoroverlay.h>
#include <texteditor/semantichighlighter.h>
#include <texteditor/codeassist/basicproposalitemlistmodel.h>
#include <texteditor/codeassist/basicproposalitem.h>
#include <texteditor/codeassist/genericproposal.h>
......@@ -461,7 +462,6 @@ CPPEditorWidget::CPPEditorWidget(QWidget *parent)
}
m_highlightRevision = 0;
m_nextHighlightBlockNumber = 0;
connect(&m_highlightWatcher, SIGNAL(resultsReadyAt(int,int)), SLOT(highlightSymbolUsages(int,int)));
connect(&m_highlightWatcher, SIGNAL(finished()), SLOT(finishHighlightSymbolUsages()));
......@@ -1010,68 +1010,11 @@ void CPPEditorWidget::highlightSymbolUsages(int from, int to)
else if (m_highlighter.isCanceled())
return; // aborted
CppHighlighter *highlighter = qobject_cast<CppHighlighter*>(baseTextDocument()->syntaxHighlighter());
Q_ASSERT(highlighter);
QTextDocument *doc = document();
if (m_nextHighlightBlockNumber >= doc->blockCount())
return;
QMap<int, QVector<SemanticInfo::Use> > chunks = CheckSymbols::chunks(m_highlighter, from, to);
if (chunks.isEmpty())
return;
QTextBlock b = doc->findBlockByNumber(m_nextHighlightBlockNumber);
QMapIterator<int, QVector<SemanticInfo::Use> > it(chunks);
while (b.isValid() && it.hasNext()) {
it.next();
const int blockNumber = it.key();
Q_ASSERT(blockNumber < doc->blockCount());
while (m_nextHighlightBlockNumber < blockNumber) {
highlighter->setExtraAdditionalFormats(b, QList<QTextLayout::FormatRange>());
b = b.next();
++m_nextHighlightBlockNumber;
}
QList<QTextLayout::FormatRange> formats;
foreach (const SemanticInfo::Use &use, it.value()) {
QTextLayout::FormatRange formatRange;
TextEditor::SyntaxHighlighter *highlighter = baseTextDocument()->syntaxHighlighter();
QTC_ASSERT(highlighter, return);
switch (use.kind) {
case SemanticInfo::Use::Type:
formatRange.format = m_typeFormat;
break;
case SemanticInfo::Use::Field:
formatRange.format = m_fieldFormat;
break;
case SemanticInfo::Use::Local:
formatRange.format = m_localFormat;
break;
case SemanticInfo::Use::Static:
formatRange.format = m_staticFormat;
break;
case SemanticInfo::Use::VirtualMethod:
formatRange.format = m_virtualMethodFormat;
break;
default:
continue;
}
formatRange.start = use.column - 1;
formatRange.length = use.length;
formats.append(formatRange);
}
highlighter->setExtraAdditionalFormats(b, formats);
b = b.next();
++m_nextHighlightBlockNumber;
}
TextEditor::SemanticHighlighter::incrementalApplyExtraAdditionalFormats(
highlighter, m_highlighter, from, to, m_semanticHighlightFormatMap);
}
void CPPEditorWidget::finishHighlightSymbolUsages()
......@@ -1082,20 +1025,11 @@ void CPPEditorWidget::finishHighlightSymbolUsages()
else if (m_highlighter.isCanceled())
return; // aborted
CppHighlighter *highlighter = qobject_cast<CppHighlighter*>(baseTextDocument()->syntaxHighlighter());
Q_ASSERT(highlighter);
QTextDocument *doc = document();
if (m_nextHighlightBlockNumber >= doc->blockCount())
return;
QTextBlock b = doc->findBlockByNumber(m_nextHighlightBlockNumber);
TextEditor::SyntaxHighlighter *highlighter = baseTextDocument()->syntaxHighlighter();
QTC_ASSERT(highlighter, return);
while (b.isValid()) {
highlighter->setExtraAdditionalFormats(b, QList<QTextLayout::FormatRange>());
b = b.next();
++m_nextHighlightBlockNumber;
}
TextEditor::SemanticHighlighter::clearExtraAdditionalFormatsUntilEnd(
highlighter, m_highlighter);
}
......@@ -1777,11 +1711,16 @@ void CPPEditorWidget::setFontSettings(const TextEditor::FontSettings &fs)
m_occurrencesUnusedFormat.clearForeground();
m_occurrencesUnusedFormat.setToolTip(tr("Unused variable"));
m_occurrenceRenameFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_OCCURRENCES_RENAME));
m_typeFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_TYPE));
m_localFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_LOCAL));
m_fieldFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_FIELD));
m_staticFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_STATIC));
m_virtualMethodFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_VIRTUAL_METHOD));
m_semanticHighlightFormatMap[SemanticInfo::TypeUse] =
fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_TYPE));
m_semanticHighlightFormatMap[SemanticInfo::LocalUse] =
fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_LOCAL));
m_semanticHighlightFormatMap[SemanticInfo::FieldUse] =
fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_FIELD));
m_semanticHighlightFormatMap[SemanticInfo::StaticUse] =
fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_STATIC));
m_semanticHighlightFormatMap[SemanticInfo::VirtualMethodUse] =
fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_VIRTUAL_METHOD));
m_keywordFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_KEYWORD));
// only set the background, we do not want to modify foreground properties set by the syntax highlighter or the link
......@@ -1921,7 +1860,6 @@ void CPPEditorWidget::updateSemanticInfo(const SemanticInfo &semanticInfo)
CheckSymbols::Future f = CheckSymbols::go(semanticInfo.doc, context);
m_highlighter = f;
m_highlightRevision = semanticInfo.revision;
m_nextHighlightBlockNumber = 0;
m_highlightWatcher.setFuture(m_highlighter);
}
}
......
......@@ -297,12 +297,8 @@ private:
QTextCharFormat m_occurrencesFormat;
QTextCharFormat m_occurrencesUnusedFormat;
QTextCharFormat m_occurrenceRenameFormat;
QTextCharFormat m_typeFormat;
QTextCharFormat m_localFormat;
QTextCharFormat m_fieldFormat;
QTextCharFormat m_staticFormat;
QHash<int, QTextCharFormat> m_semanticHighlightFormatMap;
QTextCharFormat m_keywordFormat;
QTextCharFormat m_virtualMethodFormat;
QList<QTextEdit::ExtraSelection> m_renameSelections;
int m_currentRenameSelection;
......@@ -320,7 +316,6 @@ private:
QFuture<SemanticInfo::Use> m_highlighter;
QFutureWatcher<SemanticInfo::Use> m_highlightWatcher;
unsigned m_highlightRevision; // the editor revision that requested the highlight
int m_nextHighlightBlockNumber;
QFuture<QList<int> > m_references;
QFutureWatcher<QList<int> > m_referencesWatcher;
......
......@@ -99,7 +99,7 @@ protected:
const Identifier *id = member->identifier();
unsigned line, column;
getTokenStartPosition(member->sourceLocation(), &line, &column);
localUses[member].append(SemanticInfo::Use(line, column, id->size(), SemanticInfo::Use::Local));
localUses[member].append(SemanticInfo::Use(line, column, id->size(), SemanticInfo::LocalUse));
}
}
}
......@@ -117,7 +117,7 @@ protected:
else if (!member->isGenerated() && (member->sourceLocation() < ast->firstToken() || member->enclosingScope()->isFunction())) {
unsigned line, column;
getTokenStartPosition(simpleName->identifier_token, &line, &column);
localUses[member].append(SemanticInfo::Use(line, column, id->size(), SemanticInfo::Use::Local));
localUses[member].append(SemanticInfo::Use(line, column, id->size(), SemanticInfo::LocalUse));
return false;
}
}
......
......@@ -35,6 +35,7 @@
#include <cplusplus/CppDocument.h>
#include <cplusplus/LookupContext.h>
#include <texteditor/semantichighlighter.h>
#include <QtCore/QHash>
namespace CppEditor {
......@@ -45,22 +46,13 @@ class CPPEditorWidget;
class SemanticInfo
{
public:
struct Use {
unsigned line;
unsigned column;
unsigned length;
unsigned kind;
enum Kind {
Type = 0,
Local,
Field,
Static,
VirtualMethod
};
Use(unsigned line = 0, unsigned column = 0, unsigned length = 0, unsigned kind = Type)
: line(line), column(column), length(length), kind(kind) {}
typedef TextEditor::SemanticHighlighter::Result Use;
enum UseKind {
TypeUse = 0,
LocalUse,
FieldUse,
StaticUse,
VirtualMethodUse
};
typedef QHash<CPlusPlus::Symbol *, QList<Use> > LocalUseMap;
......
......@@ -41,6 +41,7 @@
#include "qmljsautocompleter.h"
#include "qmljscompletionassist.h"
#include "qmljsquickfixassist.h"
#include "qmljssemantichighlighter.h"
#include <qmljs/qmljsbind.h>
#include <qmljs/qmljsevaluate.h>
......@@ -658,7 +659,8 @@ QmlJSTextEditorWidget::QmlJSTextEditorWidget(QWidget *parent) :
m_modelManager(0),
m_contextPane(0),
m_updateSelectedElements(false),
m_findReferences(new FindReferences(this))
m_findReferences(new FindReferences(this)),
m_semanticHighlighter(new SemanticHighlighter(this))
{
qRegisterMetaType<QmlJSEditor::SemanticInfo>("QmlJSEditor::SemanticInfo");
......@@ -1218,6 +1220,8 @@ void QmlJSTextEditorWidget::setFontSettings(const TextEditor::FontSettings &fs)
// only set the background, we do not want to modify foreground properties set by the syntax highlighter or the link
m_occurrencesFormat.clearForeground();
m_occurrenceRenameFormat.clearForeground();
m_semanticHighlighter->updateFontSettings(fs);
}
......@@ -1544,9 +1548,6 @@ void QmlJSTextEditorWidget::updateSemanticInfo(const SemanticInfo &semanticInfo)
FindIdDeclarations updateIds;
m_semanticInfo.idLocations = updateIds(doc);
FindDeclarations findDeclarations;
m_semanticInfo.declarations = findDeclarations(doc->ast());
if (m_contextPane) {
Node *newNode = m_semanticInfo.declaringMemberNoProperties(position());
if (newNode) {
......@@ -1563,6 +1564,10 @@ void QmlJSTextEditorWidget::updateSemanticInfo(const SemanticInfo &semanticInfo)
appendExtraSelectionsForMessages(&selections, doc->diagnosticMessages(), document());
appendExtraSelectionsForMessages(&selections, m_semanticInfo.semanticMessages, document());
setExtraSelections(CodeWarningsSelection, selections);
Core::EditorManager *editorManager = Core::EditorManager::instance();
if (editorManager->currentEditor() == editor())
m_semanticHighlighter->rerun(m_semanticInfo.scopeChain());
}
void QmlJSTextEditorWidget::onRefactorMarkerClicked(const TextEditor::RefactorMarker &marker)
......
......@@ -70,6 +70,7 @@ namespace Internal {
class QmlOutlineModel;
class SemanticInfoUpdater;
struct SemanticInfoUpdaterSource;
class SemanticHighlighter;
} // namespace Internal
struct QMLJSEDITOR_EXPORT Declaration
......@@ -132,7 +133,6 @@ public: // attributes
QmlJS::ContextPtr context;
QList<Range> ranges;
QHash<QString, QList<QmlJS::AST::SourceLocation> > idLocations;
QList<Declaration> declarations;
// these are in addition to the parser messages in the document
QList<QmlJS::DiagnosticMessage> semanticMessages;
......@@ -251,6 +251,9 @@ private:
bool m_updateSelectedElements;
FindReferences *m_findReferences;
Internal::SemanticHighlighter *m_semanticHighlighter;
friend class Internal::SemanticHighlighter;
};
} // namespace QmlJSEditor
......
......@@ -36,7 +36,8 @@ HEADERS += \
qmljsquickfixassist.h \
qmljscompletionassist.h \
qmljsquickfix.h \
qmljssemanticinfoupdater.h
qmljssemanticinfoupdater.h \
qmljssemantichighlighter.h
SOURCES += \
qmljseditor.cpp \
......@@ -66,7 +67,8 @@ SOURCES += \
qmljsquickfixassist.cpp \
qmljscompletionassist.cpp \
qmljsquickfix.cpp \
qmljssemanticinfoupdater.cpp
qmljssemanticinfoupdater.cpp \
qmljssemantichighlighter.cpp
RESOURCES += qmljseditor.qrc
OTHER_FILES += QmlJSEditor.mimetypes.xml
......@@ -74,7 +76,3 @@ OTHER_FILES += QmlJSEditor.mimetypes.xml
FORMS += \
quicktoolbarsettingspage.ui \
qmljscomponentnamedialog.ui
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** 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, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/
#include "qmljssemantichighlighter.h"
#include "qmljseditor.h"
#include <qmljs/qmljsdocument.h>
#include <qmljs/qmljsscopechain.h>
#include <qmljs/qmljsscopebuilder.h>
#include <qmljs/qmljsevaluate.h>
#include <qmljs/qmljscontext.h>
#include <qmljs/qmljsbind.h>
#include <qmljs/parser/qmljsast_p.h>
#include <qmljs/parser/qmljsastvisitor_p.h>
#include <texteditor/syntaxhighlighter.h>
#include <texteditor/basetextdocument.h>
#include <texteditor/texteditorconstants.h>
#include <texteditor/fontsettings.h>
#include <utils/qtcassert.h>
#include <QtCore/QThreadPool>
#include <QtCore/QFutureInterface>
#include <QtCore/QRunnable>
using namespace QmlJSEditor;
using namespace QmlJSEditor::Internal;
using namespace QmlJS;
using namespace QmlJS::AST;
namespace {
template <typename T>
class PriorityTask :
public QFutureInterface<T>,
public QRunnable
{
public:
typedef QFuture<T> Future;
Future start(QThread::Priority priority)
{
this->setRunnable(this);
this->reportStarted();
Future future = this->future();
QThreadPool::globalInstance()->start(this, priority);
return future;
}
};
static bool isIdScope(const ObjectValue *scope, const QList<const QmlComponentChain *> &chain)
{
foreach (const QmlComponentChain *c, chain) {
if (c->idScope() == scope)
return true;
if (isIdScope(scope, c->instantiatingComponents()))
return true;
}
return false;
}
class CollectStateNames : protected Visitor
{
QStringList m_stateNames;
bool m_inStateType;
ScopeChain m_scopeChain;
const QmlObjectValue *m_statePrototype;
public:
CollectStateNames(const ScopeChain &scopeChain)
: m_scopeChain(scopeChain)
{
m_statePrototype = scopeChain.context()->valueOwner()->cppQmlTypes().typeByCppName(QLatin1String("QDeclarativeState"));
}
QStringList operator()(Node *ast)
{
m_stateNames.clear();
if (!m_statePrototype)
return m_stateNames;
m_inStateType = false;
accept(ast);
return m_stateNames;
}
protected:
void accept(Node *ast)
{
if (ast)
ast->accept(this);
}
bool preVisit(Node *ast)
{
return ast->uiObjectMemberCast()
|| cast<UiProgram *>(ast)