forked from qt-creator/qt-creator
Improved the navigation and code completion in the QML editor.
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
#include <QDebug>
|
||||||
|
|
||||||
#include "idcollector.h"
|
#include "idcollector.h"
|
||||||
#include "qmljsast_p.h"
|
#include "qmljsast_p.h"
|
||||||
#include "qmljsengine_p.h"
|
#include "qmljsengine_p.h"
|
||||||
@@ -7,36 +9,39 @@ using namespace QmlJS::AST;
|
|||||||
using namespace QmlEditor;
|
using namespace QmlEditor;
|
||||||
using namespace QmlEditor::Internal;
|
using namespace QmlEditor::Internal;
|
||||||
|
|
||||||
QMap<QString, QmlIdSymbol*> IdCollector::operator()(const QString &fileName, QmlJS::AST::UiProgram *ast)
|
QMap<QString, QmlIdSymbol*> IdCollector::operator()(QmlDocument *doc)
|
||||||
{
|
{
|
||||||
_fileName = fileName;
|
_doc = doc;
|
||||||
_ids.clear();
|
_ids.clear();
|
||||||
|
_currentSymbol = 0;
|
||||||
|
|
||||||
Node::accept(ast, this);
|
Node::accept(doc->program(), this);
|
||||||
|
|
||||||
return _ids;
|
return _ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IdCollector::visit(UiArrayBinding *ast)
|
||||||
|
{
|
||||||
|
QmlSymbolFromFile *oldSymbol = switchSymbol(ast);
|
||||||
|
Node::accept(ast->members, this);
|
||||||
|
_currentSymbol = oldSymbol;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool IdCollector::visit(QmlJS::AST::UiObjectBinding *ast)
|
bool IdCollector::visit(QmlJS::AST::UiObjectBinding *ast)
|
||||||
{
|
{
|
||||||
_scopes.push(ast);
|
QmlSymbolFromFile *oldSymbol = switchSymbol(ast);
|
||||||
return true;
|
Node::accept(ast->initializer, this);
|
||||||
|
_currentSymbol = oldSymbol;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IdCollector::visit(QmlJS::AST::UiObjectDefinition *ast)
|
bool IdCollector::visit(QmlJS::AST::UiObjectDefinition *ast)
|
||||||
{
|
{
|
||||||
_scopes.push(ast);
|
QmlSymbolFromFile *oldSymbol = switchSymbol(ast);
|
||||||
return true;
|
Node::accept(ast->initializer, this);
|
||||||
}
|
_currentSymbol = oldSymbol;
|
||||||
|
return false;
|
||||||
void IdCollector::endVisit(QmlJS::AST::UiObjectBinding *)
|
|
||||||
{
|
|
||||||
_scopes.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IdCollector::endVisit(QmlJS::AST::UiObjectDefinition *)
|
|
||||||
{
|
|
||||||
_scopes.pop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IdCollector::visit(QmlJS::AST::UiScriptBinding *ast)
|
bool IdCollector::visit(QmlJS::AST::UiScriptBinding *ast)
|
||||||
@@ -44,21 +49,40 @@ bool IdCollector::visit(QmlJS::AST::UiScriptBinding *ast)
|
|||||||
if (!(ast->qualifiedId->next) && ast->qualifiedId->name->asString() == "id")
|
if (!(ast->qualifiedId->next) && ast->qualifiedId->name->asString() == "id")
|
||||||
if (ExpressionStatement *e = cast<ExpressionStatement*>(ast->statement))
|
if (ExpressionStatement *e = cast<ExpressionStatement*>(ast->statement))
|
||||||
if (IdentifierExpression *i = cast<IdentifierExpression*>(e->expression))
|
if (IdentifierExpression *i = cast<IdentifierExpression*>(e->expression))
|
||||||
addId(i->name->asString(), ast);
|
if (i->name)
|
||||||
|
addId(i->name->asString(), ast);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QmlSymbolFromFile *IdCollector::switchSymbol(QmlJS::AST::UiObjectMember *node)
|
||||||
|
{
|
||||||
|
QmlSymbolFromFile *newSymbol = 0;
|
||||||
|
|
||||||
|
if (_currentSymbol == 0) {
|
||||||
|
newSymbol = _doc->findSymbol(node);
|
||||||
|
} else {
|
||||||
|
newSymbol = _currentSymbol->findMember(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
QmlSymbolFromFile *oldSymbol = _currentSymbol;
|
||||||
|
|
||||||
|
if (newSymbol) {
|
||||||
|
_currentSymbol = newSymbol;
|
||||||
|
} else {
|
||||||
|
QString filename = _doc->fileName();
|
||||||
|
qWarning() << "Scope without symbol @"<<filename<<":"<<node->firstSourceLocation().startLine<<":"<<node->firstSourceLocation().startColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
return oldSymbol;
|
||||||
|
}
|
||||||
|
|
||||||
void IdCollector::addId(const QString &id, QmlJS::AST::UiScriptBinding *ast)
|
void IdCollector::addId(const QString &id, QmlJS::AST::UiScriptBinding *ast)
|
||||||
{
|
{
|
||||||
if (!_ids.contains(id)) {
|
if (!_ids.contains(id) && _currentSymbol) {
|
||||||
Node *parent = _scopes.top();
|
QmlSymbolFromFile *symbol = _currentSymbol->findMember(ast);
|
||||||
|
|
||||||
if (UiObjectBinding *binding = cast<UiObjectBinding*>(parent))
|
if (QmlIdSymbol *idSymbol = symbol->asIdSymbol())
|
||||||
_ids[id] = new QmlIdSymbol(_fileName, ast, QmlSymbolFromFile(_fileName, binding));
|
_ids[id] = idSymbol;
|
||||||
else if (UiObjectDefinition *definition = cast<UiObjectDefinition*>(parent))
|
|
||||||
_ids[id] = new QmlIdSymbol(_fileName, ast, QmlSymbolFromFile(_fileName, definition));
|
|
||||||
else
|
|
||||||
Q_ASSERT(!"Unknown parent for id");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <QStack>
|
#include <QStack>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
|
#include "qmldocument.h"
|
||||||
#include "qmljsastvisitor_p.h"
|
#include "qmljsastvisitor_p.h"
|
||||||
#include "qmlsymbol.h"
|
#include "qmlsymbol.h"
|
||||||
|
|
||||||
@@ -15,23 +16,22 @@ namespace Internal {
|
|||||||
class IdCollector: protected QmlJS::AST::Visitor
|
class IdCollector: protected QmlJS::AST::Visitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QMap<QString, QmlIdSymbol*> operator()(const QString &fileName, QmlJS::AST::UiProgram *ast);
|
QMap<QString, QmlIdSymbol*> operator()(QmlDocument *doc);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual bool visit(QmlJS::AST::UiArrayBinding *ast);
|
||||||
virtual bool visit(QmlJS::AST::UiObjectBinding *ast);
|
virtual bool visit(QmlJS::AST::UiObjectBinding *ast);
|
||||||
virtual bool visit(QmlJS::AST::UiObjectDefinition *ast);
|
virtual bool visit(QmlJS::AST::UiObjectDefinition *ast);
|
||||||
virtual bool visit(QmlJS::AST::UiScriptBinding *ast);
|
virtual bool visit(QmlJS::AST::UiScriptBinding *ast);
|
||||||
|
|
||||||
virtual void endVisit(QmlJS::AST::UiObjectBinding *);
|
|
||||||
virtual void endVisit(QmlJS::AST::UiObjectDefinition *);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QmlSymbolFromFile *switchSymbol(QmlJS::AST::UiObjectMember *node);
|
||||||
void addId(const QString &id, QmlJS::AST::UiScriptBinding *ast);
|
void addId(const QString &id, QmlJS::AST::UiScriptBinding *ast);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString _fileName;
|
QmlDocument *_doc;
|
||||||
QMap<QString, QmlIdSymbol*> _ids;
|
QMap<QString, QmlIdSymbol*> _ids;
|
||||||
QStack<QmlJS::AST::Node *> _scopes;
|
QmlSymbolFromFile *_currentSymbol;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
@@ -1,17 +1,25 @@
|
|||||||
#include "qmlcompletionvisitor.h"
|
|
||||||
#include "qmlcodecompletion.h"
|
#include "qmlcodecompletion.h"
|
||||||
#include "qmleditor.h"
|
#include "qmleditor.h"
|
||||||
|
#include "qmlmodelmanagerinterface.h"
|
||||||
|
#include "qmlexpressionundercursor.h"
|
||||||
|
#include "qmllookupcontext.h"
|
||||||
|
#include "qmlresolveexpression.h"
|
||||||
|
#include "qmlsymbol.h"
|
||||||
|
|
||||||
#include <texteditor/basetexteditor.h>
|
#include <texteditor/basetexteditor.h>
|
||||||
#include <QtDebug>
|
#include <QtDebug>
|
||||||
|
|
||||||
using namespace QmlEditor::Internal;
|
using namespace QmlEditor::Internal;
|
||||||
|
|
||||||
QmlCodeCompletion::QmlCodeCompletion(QObject *parent)
|
QmlCodeCompletion::QmlCodeCompletion(QmlModelManagerInterface *modelManager,QObject *parent)
|
||||||
: TextEditor::ICompletionCollector(parent),
|
: TextEditor::ICompletionCollector(parent),
|
||||||
|
m_modelManager(modelManager),
|
||||||
m_editor(0),
|
m_editor(0),
|
||||||
m_startPosition(0),
|
m_startPosition(0),
|
||||||
m_caseSensitivity(Qt::CaseSensitive)
|
m_caseSensitivity(Qt::CaseSensitive)
|
||||||
{ }
|
{
|
||||||
|
Q_ASSERT(modelManager);
|
||||||
|
}
|
||||||
|
|
||||||
QmlCodeCompletion::~QmlCodeCompletion()
|
QmlCodeCompletion::~QmlCodeCompletion()
|
||||||
{ }
|
{ }
|
||||||
@@ -49,26 +57,52 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
|
|||||||
m_startPosition = pos;
|
m_startPosition = pos;
|
||||||
m_completions.clear();
|
m_completions.clear();
|
||||||
|
|
||||||
foreach (const QString &word, edit->keywords()) {
|
// foreach (const QString &word, edit->keywords()) {
|
||||||
TextEditor::CompletionItem item(this);
|
// TextEditor::CompletionItem item(this);
|
||||||
item.m_text = word;
|
// item.m_text = word;
|
||||||
m_completions.append(item);
|
// m_completions.append(item);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
foreach (const QString &word, edit->words()) {
|
// foreach (const QString &word, edit->words()) {
|
||||||
TextEditor::CompletionItem item(this);
|
// TextEditor::CompletionItem item(this);
|
||||||
item.m_text = word;
|
// item.m_text = word;
|
||||||
m_completions.append(item);
|
// m_completions.append(item);
|
||||||
}
|
// }
|
||||||
|
|
||||||
QmlDocument::Ptr qmlDocument = edit->qmlDocument();
|
QmlDocument::Ptr qmlDocument = edit->qmlDocument();
|
||||||
if (!qmlDocument.isNull()) {
|
qDebug() << "*** document:" << qmlDocument;
|
||||||
QmlJS::AST::UiProgram *program = qmlDocument->program();
|
if (qmlDocument.isNull())
|
||||||
|
return pos;
|
||||||
|
|
||||||
if (program) {
|
if (!qmlDocument->program())
|
||||||
QmlCompletionVisitor visitor;
|
qmlDocument = m_modelManager->snapshot().value(qmlDocument->fileName());
|
||||||
|
|
||||||
foreach (const QString &word, visitor(program, m_startPosition)) {
|
if (qmlDocument->program()) {
|
||||||
|
QmlJS::AST::UiProgram *program = qmlDocument->program();
|
||||||
|
qDebug() << "*** program:" << program;
|
||||||
|
|
||||||
|
if (program) {
|
||||||
|
QmlExpressionUnderCursor expressionUnderCursor;
|
||||||
|
QTextCursor cursor(edit->document());
|
||||||
|
cursor.setPosition(pos);
|
||||||
|
expressionUnderCursor(cursor, qmlDocument);
|
||||||
|
|
||||||
|
QmlLookupContext context(expressionUnderCursor.expressionScopes(), qmlDocument, m_modelManager->snapshot());
|
||||||
|
QmlResolveExpression resolver(context);
|
||||||
|
QList<QmlSymbol*> symbols = resolver.visibleSymbols(expressionUnderCursor.expressionNode());
|
||||||
|
|
||||||
|
foreach (QmlSymbol *symbol, symbols) {
|
||||||
|
QString word;
|
||||||
|
|
||||||
|
if (symbol->isIdSymbol()) {
|
||||||
|
word = symbol->asIdSymbol()->id();
|
||||||
|
} else {
|
||||||
|
word = symbol->name();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (word.isEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
TextEditor::CompletionItem item(this);
|
TextEditor::CompletionItem item(this);
|
||||||
item.m_text = word;
|
item.m_text = word;
|
||||||
m_completions.append(item);
|
m_completions.append(item);
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ class ITextEditable;
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace QmlEditor {
|
namespace QmlEditor {
|
||||||
|
|
||||||
|
class QmlModelManagerInterface;
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class QmlCodeCompletion: public TextEditor::ICompletionCollector
|
class QmlCodeCompletion: public TextEditor::ICompletionCollector
|
||||||
@@ -15,7 +18,7 @@ class QmlCodeCompletion: public TextEditor::ICompletionCollector
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QmlCodeCompletion(QObject *parent = 0);
|
QmlCodeCompletion(QmlModelManagerInterface *modelManager, QObject *parent = 0);
|
||||||
virtual ~QmlCodeCompletion();
|
virtual ~QmlCodeCompletion();
|
||||||
|
|
||||||
Qt::CaseSensitivity caseSensitivity() const;
|
Qt::CaseSensitivity caseSensitivity() const;
|
||||||
@@ -30,6 +33,7 @@ public:
|
|||||||
virtual void cleanup();
|
virtual void cleanup();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QmlModelManagerInterface *m_modelManager;
|
||||||
TextEditor::ITextEditable *m_editor;
|
TextEditor::ITextEditable *m_editor;
|
||||||
int m_startPosition;
|
int m_startPosition;
|
||||||
QList<TextEditor::CompletionItem> m_completions;
|
QList<TextEditor::CompletionItem> m_completions;
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ QmlDocument::~QmlDocument()
|
|||||||
if (_pool)
|
if (_pool)
|
||||||
delete _pool;
|
delete _pool;
|
||||||
|
|
||||||
qDeleteAll(_ids.values());
|
qDeleteAll(_symbols);
|
||||||
}
|
}
|
||||||
|
|
||||||
QmlDocument::Ptr QmlDocument::create(const QString &fileName)
|
QmlDocument::Ptr QmlDocument::create(const QString &fileName)
|
||||||
@@ -109,14 +109,28 @@ bool QmlDocument::parse()
|
|||||||
_program = parser.ast();
|
_program = parser.ast();
|
||||||
_diagnosticMessages = parser.diagnosticMessages();
|
_diagnosticMessages = parser.diagnosticMessages();
|
||||||
|
|
||||||
if (_parsedCorrectly && _program) {
|
if (_program) {
|
||||||
Internal::IdCollector collect;
|
for (QmlJS::AST::UiObjectMemberList *iter = _program->members; iter; iter = iter->next)
|
||||||
_ids = collect(_fileName, _program);
|
if (iter->member)
|
||||||
|
_symbols.append(new QmlSymbolFromFile(_fileName, iter->member));
|
||||||
|
|
||||||
|
Internal::IdCollector collect;
|
||||||
|
_ids = collect(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _parsedCorrectly;
|
return _parsedCorrectly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QmlSymbolFromFile *QmlDocument::findSymbol(QmlJS::AST::Node *node) const
|
||||||
|
{
|
||||||
|
foreach (QmlSymbol *symbol, _symbols)
|
||||||
|
if (symbol->isSymbolFromFile())
|
||||||
|
if (symbol->asSymbolFromFile()->node() == node)
|
||||||
|
return symbol->asSymbolFromFile();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Snapshot::Snapshot()
|
Snapshot::Snapshot()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -127,6 +141,9 @@ Snapshot::~Snapshot()
|
|||||||
|
|
||||||
void Snapshot::insert(const QmlDocument::Ptr &document)
|
void Snapshot::insert(const QmlDocument::Ptr &document)
|
||||||
{
|
{
|
||||||
|
if (!document || !document->program())
|
||||||
|
return;
|
||||||
|
|
||||||
QMap<QString, QmlDocument::Ptr>::insert(document->fileName(), document);
|
QMap<QString, QmlDocument::Ptr>::insert(document->fileName(), document);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,10 @@ public:
|
|||||||
QString path() const { return _path; }
|
QString path() const { return _path; }
|
||||||
QString componentName() const { return _componentName; }
|
QString componentName() const { return _componentName; }
|
||||||
|
|
||||||
|
QmlSymbolFromFile *findSymbol(QmlJS::AST::Node *node) const;
|
||||||
|
QmlSymbol::List symbols() const
|
||||||
|
{ return _symbols; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QmlJS::Engine *_engine;
|
QmlJS::Engine *_engine;
|
||||||
QmlJS::NodePool *_pool;
|
QmlJS::NodePool *_pool;
|
||||||
@@ -85,6 +89,7 @@ private:
|
|||||||
QString _source;
|
QString _source;
|
||||||
bool _parsedCorrectly;
|
bool _parsedCorrectly;
|
||||||
IdTable _ids;
|
IdTable _ids;
|
||||||
|
QmlSymbol::List _symbols;
|
||||||
};
|
};
|
||||||
|
|
||||||
class QMLEDITOR_EXPORT Snapshot: public QMap<QString, QmlDocument::Ptr>
|
class QMLEDITOR_EXPORT Snapshot: public QMap<QString, QmlDocument::Ptr>
|
||||||
|
|||||||
@@ -719,12 +719,28 @@ TextEditor::BaseTextEditor::Link ScriptEditor::findLinkAt(const QTextCursor &cur
|
|||||||
if (!doc)
|
if (!doc)
|
||||||
return link;
|
return link;
|
||||||
|
|
||||||
|
QTextCursor expressionCursor(cursor);
|
||||||
|
{
|
||||||
|
// correct the position by moving to the end of an identifier (if we're hovering over one):
|
||||||
|
const QString txt = cursor.block().text();
|
||||||
|
int pos = cursor.position();
|
||||||
|
forever {
|
||||||
|
const QChar ch = characterAt(pos);
|
||||||
|
|
||||||
|
if (ch.isLetterOrNumber() || ch == QLatin1Char('_'))
|
||||||
|
++pos;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
expressionCursor.setPosition(pos);
|
||||||
|
}
|
||||||
|
|
||||||
QmlExpressionUnderCursor expressionUnderCursor;
|
QmlExpressionUnderCursor expressionUnderCursor;
|
||||||
expressionUnderCursor(cursor, doc->program());
|
expressionUnderCursor(expressionCursor, doc);
|
||||||
|
|
||||||
QmlLookupContext context(expressionUnderCursor.expressionScopes(), doc, snapshot);
|
QmlLookupContext context(expressionUnderCursor.expressionScopes(), doc, snapshot);
|
||||||
QmlResolveExpression resolve(context);
|
QmlResolveExpression resolver(context);
|
||||||
QmlSymbol *symbol = resolve(expressionUnderCursor.expressionNode());
|
QmlSymbol *symbol = resolver.typeOf(expressionUnderCursor.expressionNode());
|
||||||
|
|
||||||
if (!symbol)
|
if (!symbol)
|
||||||
return link;
|
return link;
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ HEADERS += qmleditor.h \
|
|||||||
qmleditorconstants.h \
|
qmleditorconstants.h \
|
||||||
qmlhoverhandler.h \
|
qmlhoverhandler.h \
|
||||||
qmldocument.h \
|
qmldocument.h \
|
||||||
qmlcompletionvisitor.h \
|
|
||||||
qmlmodelmanagerinterface.h \
|
qmlmodelmanagerinterface.h \
|
||||||
qmleditor_global.h \
|
qmleditor_global.h \
|
||||||
qmlmodelmanager.h \
|
qmlmodelmanager.h \
|
||||||
@@ -27,7 +26,8 @@ HEADERS += qmleditor.h \
|
|||||||
qmllookupcontext.h \
|
qmllookupcontext.h \
|
||||||
qmlresolveexpression.h \
|
qmlresolveexpression.h \
|
||||||
qmlsymbol.h \
|
qmlsymbol.h \
|
||||||
qmlfilewizard.h
|
qmlfilewizard.h \
|
||||||
|
qmlscope.h
|
||||||
SOURCES += qmleditor.cpp \
|
SOURCES += qmleditor.cpp \
|
||||||
qmleditorfactory.cpp \
|
qmleditorfactory.cpp \
|
||||||
qmleditorplugin.cpp \
|
qmleditorplugin.cpp \
|
||||||
@@ -36,7 +36,6 @@ SOURCES += qmleditor.cpp \
|
|||||||
qmlcodecompletion.cpp \
|
qmlcodecompletion.cpp \
|
||||||
qmlhoverhandler.cpp \
|
qmlhoverhandler.cpp \
|
||||||
qmldocument.cpp \
|
qmldocument.cpp \
|
||||||
qmlcompletionvisitor.cpp \
|
|
||||||
qmlmodelmanagerinterface.cpp \
|
qmlmodelmanagerinterface.cpp \
|
||||||
qmlmodelmanager.cpp \
|
qmlmodelmanager.cpp \
|
||||||
qmlcodeformatter.cpp \
|
qmlcodeformatter.cpp \
|
||||||
@@ -45,5 +44,6 @@ SOURCES += qmleditor.cpp \
|
|||||||
qmllookupcontext.cpp \
|
qmllookupcontext.cpp \
|
||||||
qmlresolveexpression.cpp \
|
qmlresolveexpression.cpp \
|
||||||
qmlsymbol.cpp \
|
qmlsymbol.cpp \
|
||||||
qmlfilewizard.cpp
|
qmlfilewizard.cpp \
|
||||||
|
qmlscope.cpp
|
||||||
RESOURCES += qmleditor.qrc
|
RESOURCES += qmleditor.qrc
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ bool QmlEditorPlugin::initialize(const QStringList & /*arguments*/, QString *err
|
|||||||
| TextEditor::TextEditorActionHandler::UnCollapseAll);
|
| TextEditor::TextEditorActionHandler::UnCollapseAll);
|
||||||
m_actionHandler->initializeActions();
|
m_actionHandler->initializeActions();
|
||||||
|
|
||||||
m_completion = new QmlCodeCompletion();
|
m_completion = new QmlCodeCompletion(m_modelManager);
|
||||||
addAutoReleasedObject(m_completion);
|
addAutoReleasedObject(m_completion);
|
||||||
|
|
||||||
addAutoReleasedObject(new QmlHoverHandler());
|
addAutoReleasedObject(new QmlHoverHandler());
|
||||||
|
|||||||
@@ -1,124 +1,294 @@
|
|||||||
#include "qmljsast_p.h"
|
#include <QDebug>
|
||||||
#include "qmljsengine_p.h"
|
|
||||||
|
|
||||||
|
#include "qmljsast_p.h"
|
||||||
|
#include "qmljsastvisitor_p.h"
|
||||||
|
#include "qmljsengine_p.h"
|
||||||
|
#include "qmljslexer_p.h"
|
||||||
|
#include "qmljsnodepool_p.h"
|
||||||
|
#include "qmljsparser_p.h"
|
||||||
#include "qmlexpressionundercursor.h"
|
#include "qmlexpressionundercursor.h"
|
||||||
|
|
||||||
using namespace QmlEditor;
|
|
||||||
using namespace QmlEditor::Internal;
|
|
||||||
using namespace QmlJS;
|
using namespace QmlJS;
|
||||||
using namespace QmlJS::AST;
|
using namespace QmlJS::AST;
|
||||||
|
|
||||||
|
namespace QmlEditor {
|
||||||
|
namespace Internal {
|
||||||
|
class PositionCalculator: protected Visitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Node *operator()(Node *ast, int pos)
|
||||||
|
{
|
||||||
|
_pos = pos;
|
||||||
|
_expression = 0;
|
||||||
|
_offset = -1;
|
||||||
|
_length = -1;
|
||||||
|
|
||||||
|
Node::accept(ast, this);
|
||||||
|
|
||||||
|
return _expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
int offset() const
|
||||||
|
{ return _offset; }
|
||||||
|
|
||||||
|
int length() const
|
||||||
|
{ return _length; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool visit(FieldMemberExpression *ast)
|
||||||
|
{
|
||||||
|
if (ast->identifierToken.offset <= _pos && _pos <= ast->identifierToken.end()) {
|
||||||
|
_expression = ast;
|
||||||
|
_offset = ast->identifierToken.offset;
|
||||||
|
_length = ast->identifierToken.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool visit(IdentifierExpression *ast)
|
||||||
|
{
|
||||||
|
if (ast->firstSourceLocation().offset <= _pos && _pos <= ast->lastSourceLocation().end()) {
|
||||||
|
_expression = ast;
|
||||||
|
_offset = ast->firstSourceLocation().offset;
|
||||||
|
_length = ast->lastSourceLocation().end() - _offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool visit(UiImport * /*ast*/)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool visit(UiQualifiedId *ast)
|
||||||
|
{
|
||||||
|
if (ast->identifierToken.offset <= _pos) {
|
||||||
|
for (UiQualifiedId *iter = ast; iter; iter = iter->next) {
|
||||||
|
if (_pos <= iter->identifierToken.end()) {
|
||||||
|
// found it
|
||||||
|
_expression = ast;
|
||||||
|
_offset = ast->identifierToken.offset;
|
||||||
|
|
||||||
|
for (UiQualifiedId *iter2 = ast; iter2; iter2 = iter2->next) {
|
||||||
|
_length = iter2->identifierToken.end() - _offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
quint32 _pos;
|
||||||
|
Node *_expression;
|
||||||
|
int _offset;
|
||||||
|
int _length;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ScopeCalculator: protected Visitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QStack<QmlSymbol*> operator()(const QmlDocument::Ptr &doc, int pos)
|
||||||
|
{
|
||||||
|
_doc = doc;
|
||||||
|
_pos = pos;
|
||||||
|
_scopes.clear();
|
||||||
|
_currentSymbol = 0;
|
||||||
|
Node::accept(doc->program(), this);
|
||||||
|
return _scopes;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool visit(Block *ast)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
// if (_pos > ast->lbraceToken.end() && _pos < ast->rbraceToken.offset) {
|
||||||
|
// push(ast);
|
||||||
|
// Node::accept(ast->statements, this);
|
||||||
|
// }
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool visit(UiObjectBinding *ast)
|
||||||
|
{
|
||||||
|
if (ast->initializer && ast->initializer->rbraceToken.offset < _pos && _pos <= ast->initializer->lbraceToken.end()) {
|
||||||
|
push(ast);
|
||||||
|
Node::accept(ast->initializer, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool visit(UiObjectDefinition *ast)
|
||||||
|
{
|
||||||
|
if (ast->initializer && ast->initializer->rbraceToken.offset < _pos && _pos <= ast->initializer->lbraceToken.end()) {
|
||||||
|
push(ast);
|
||||||
|
Node::accept(ast->initializer, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool visit(UiArrayBinding *ast)
|
||||||
|
{
|
||||||
|
if (ast->lbracketToken.offset < _pos && _pos <= ast->rbracketToken.end()) {
|
||||||
|
push(ast);
|
||||||
|
Node::accept(ast->members, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void push(Node *node)
|
||||||
|
{
|
||||||
|
QmlSymbolFromFile* symbol;
|
||||||
|
|
||||||
|
if (_currentSymbol) {
|
||||||
|
symbol = _currentSymbol->findMember(node);
|
||||||
|
} else {
|
||||||
|
symbol = _doc->findSymbol(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symbol) {
|
||||||
|
_currentSymbol = symbol;
|
||||||
|
|
||||||
|
if (!cast<UiArrayBinding*>(node))
|
||||||
|
_scopes.push(symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QmlDocument::Ptr _doc;
|
||||||
|
quint32 _pos;
|
||||||
|
QStack<QmlSymbol*> _scopes;
|
||||||
|
QmlSymbolFromFile* _currentSymbol;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace QmlEditor;
|
||||||
|
using namespace QmlEditor::Internal;
|
||||||
|
|
||||||
QmlExpressionUnderCursor::QmlExpressionUnderCursor()
|
QmlExpressionUnderCursor::QmlExpressionUnderCursor()
|
||||||
: _expressionNode(0),
|
: _expressionNode(0),
|
||||||
_pos(0)
|
_pos(0), _engine(0), _nodePool(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlExpressionUnderCursor::operator()(const QTextCursor &cursor,
|
QmlExpressionUnderCursor::~QmlExpressionUnderCursor()
|
||||||
QmlJS::AST::UiProgram *program)
|
|
||||||
{
|
{
|
||||||
|
if (_engine) { delete _engine; _engine = 0; }
|
||||||
|
if (_nodePool) { delete _nodePool; _nodePool = 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void QmlExpressionUnderCursor::operator()(const QTextCursor &cursor,
|
||||||
|
const QmlDocument::Ptr &doc)
|
||||||
|
{
|
||||||
|
if (_engine) { delete _engine; _engine = 0; }
|
||||||
|
if (_nodePool) { delete _nodePool; _nodePool = 0; }
|
||||||
|
|
||||||
_pos = cursor.position();
|
_pos = cursor.position();
|
||||||
_expressionNode = 0;
|
_expressionNode = 0;
|
||||||
_expressionOffset = -1;
|
_expressionOffset = -1;
|
||||||
_expressionLength = -1;
|
_expressionLength = -1;
|
||||||
_scopes.clear();
|
_expressionScopes.clear();
|
||||||
|
|
||||||
if (program)
|
const QTextBlock block = cursor.block();
|
||||||
program->accept(this);
|
parseExpression(block);
|
||||||
|
|
||||||
|
if (_expressionOffset != -1) {
|
||||||
|
ScopeCalculator calculator;
|
||||||
|
_expressionScopes = calculator(doc, _expressionOffset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QmlExpressionUnderCursor::visit(QmlJS::AST::Block *ast)
|
void QmlExpressionUnderCursor::parseExpression(const QTextBlock &block)
|
||||||
{
|
{
|
||||||
_scopes.push(ast);
|
int textPosition = _pos - block.position();
|
||||||
|
const QString blockText = block.text();
|
||||||
return true;
|
if (textPosition > 0) {
|
||||||
}
|
if (blockText.at(textPosition - 1) == QLatin1Char('.'))
|
||||||
|
--textPosition;
|
||||||
void QmlExpressionUnderCursor::endVisit(QmlJS::AST::Block *)
|
} else {
|
||||||
{
|
textPosition = 0;
|
||||||
_scopes.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QmlExpressionUnderCursor::visit(QmlJS::AST::FieldMemberExpression *ast)
|
|
||||||
{
|
|
||||||
if (ast->identifierToken.offset <= _pos && _pos <= ast->identifierToken.end()) {
|
|
||||||
_expressionNode = ast;
|
|
||||||
_expressionOffset = ast->identifierToken.offset;
|
|
||||||
_expressionLength = ast->identifierToken.length;
|
|
||||||
_expressionScopes = _scopes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
const QString text = blockText.left(textPosition);
|
||||||
}
|
|
||||||
|
|
||||||
bool QmlExpressionUnderCursor::visit(QmlJS::AST::IdentifierExpression *ast)
|
Node *node = 0;
|
||||||
{
|
|
||||||
if (ast->firstSourceLocation().offset <= _pos && _pos <= ast->lastSourceLocation().end()) {
|
if (UiObjectMember *binding = tryBinding(text)) {
|
||||||
_expressionNode = ast;
|
qDebug() << "**** binding";
|
||||||
_expressionOffset = ast->firstSourceLocation().offset;
|
node = binding;
|
||||||
_expressionLength = ast->lastSourceLocation().end() - _expressionOffset;
|
} else if (Statement *stmt = tryStatement(text)) {
|
||||||
_expressionScopes = _scopes;
|
qDebug() << "**** statement";
|
||||||
|
node = stmt;
|
||||||
|
} else if (ExpressionNode *expr = tryExpression(text)) {
|
||||||
|
qDebug() << "**** expression";
|
||||||
|
node = expr;
|
||||||
|
} else {
|
||||||
|
qDebug() << "**** none";
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
if (node) {
|
||||||
}
|
PositionCalculator calculator;
|
||||||
|
_expressionNode = calculator(node, textPosition);
|
||||||
bool QmlExpressionUnderCursor::visit(QmlJS::AST::UiObjectBinding *ast)
|
_expressionOffset = calculator.offset() + block.position();
|
||||||
{
|
_expressionLength = calculator.length();
|
||||||
Node::accept(ast->qualifiedId, this);
|
|
||||||
Node::accept(ast->qualifiedTypeNameId, this);
|
|
||||||
|
|
||||||
_scopes.push(ast);
|
|
||||||
|
|
||||||
Node::accept(ast->initializer, this);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QmlExpressionUnderCursor::endVisit(QmlJS::AST::UiObjectBinding *)
|
|
||||||
{
|
|
||||||
_scopes.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QmlExpressionUnderCursor::visit(QmlJS::AST::UiObjectDefinition *ast)
|
|
||||||
{
|
|
||||||
Node::accept(ast->qualifiedTypeNameId, this);
|
|
||||||
|
|
||||||
_scopes.push(ast);
|
|
||||||
|
|
||||||
Node::accept(ast->initializer, this);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QmlExpressionUnderCursor::endVisit(QmlJS::AST::UiObjectDefinition *)
|
|
||||||
{
|
|
||||||
_scopes.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QmlExpressionUnderCursor::visit(QmlJS::AST::UiQualifiedId *ast)
|
|
||||||
{
|
|
||||||
if (ast->identifierToken.offset <= _pos) {
|
|
||||||
for (UiQualifiedId *iter = ast; iter; iter = iter->next) {
|
|
||||||
if (_pos <= iter->identifierToken.end()) {
|
|
||||||
// found it
|
|
||||||
_expressionNode = ast;
|
|
||||||
_expressionOffset = ast->identifierToken.offset;
|
|
||||||
|
|
||||||
for (UiQualifiedId *iter2 = ast; iter2; iter2 = iter2->next) {
|
|
||||||
_expressionLength = iter2->identifierToken.end() - _expressionOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
_expressionScopes = _scopes;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QmlExpressionUnderCursor::visit(QmlJS::AST::UiImport * /*ast*/)
|
ExpressionNode *QmlExpressionUnderCursor::tryExpression(const QString &text)
|
||||||
{
|
{
|
||||||
return false;
|
_engine = new Engine();
|
||||||
|
_nodePool = new NodePool("", _engine);
|
||||||
|
Lexer lexer(_engine);
|
||||||
|
Parser parser(_engine);
|
||||||
|
lexer.setCode(text, /*line = */ 1);
|
||||||
|
|
||||||
|
if (parser.parseExpression())
|
||||||
|
return parser.expression();
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Statement *QmlExpressionUnderCursor::tryStatement(const QString &text)
|
||||||
|
{
|
||||||
|
_engine = new Engine();
|
||||||
|
_nodePool = new NodePool("", _engine);
|
||||||
|
Lexer lexer(_engine);
|
||||||
|
Parser parser(_engine);
|
||||||
|
lexer.setCode(text, /*line = */ 1);
|
||||||
|
|
||||||
|
if (parser.parseStatement())
|
||||||
|
return parser.statement();
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
UiObjectMember *QmlExpressionUnderCursor::tryBinding(const QString &text)
|
||||||
|
{
|
||||||
|
_engine = new Engine();
|
||||||
|
_nodePool = new NodePool("", _engine);
|
||||||
|
Lexer lexer(_engine);
|
||||||
|
Parser parser(_engine);
|
||||||
|
lexer.setCode(text, /*line = */ 1);
|
||||||
|
|
||||||
|
if (parser.parseUiObjectMember()) {
|
||||||
|
UiObjectMember *member = parser.uiObjectMember();
|
||||||
|
|
||||||
|
if (cast<UiObjectBinding*>(member) || cast<UiArrayBinding*>(member) || cast<UiScriptBinding*>(member))
|
||||||
|
return member;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,21 +2,30 @@
|
|||||||
#define QMLEXPRESSIONUNDERCURSOR_H
|
#define QMLEXPRESSIONUNDERCURSOR_H
|
||||||
|
|
||||||
#include <QStack>
|
#include <QStack>
|
||||||
|
#include <QTextBlock>
|
||||||
#include <QTextCursor>
|
#include <QTextCursor>
|
||||||
|
|
||||||
#include "qmljsastvisitor_p.h"
|
#include "qmldocument.h"
|
||||||
|
#include "qmljsastfwd_p.h"
|
||||||
|
#include "qmlsymbol.h"
|
||||||
|
|
||||||
|
namespace QmlJS {
|
||||||
|
class Engine;
|
||||||
|
class NodePool;
|
||||||
|
}
|
||||||
|
|
||||||
namespace QmlEditor {
|
namespace QmlEditor {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class QmlExpressionUnderCursor: protected QmlJS::AST::Visitor
|
class QmlExpressionUnderCursor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QmlExpressionUnderCursor();
|
QmlExpressionUnderCursor();
|
||||||
|
virtual ~QmlExpressionUnderCursor();
|
||||||
|
|
||||||
void operator()(const QTextCursor &cursor, QmlJS::AST::UiProgram *program);
|
void operator()(const QTextCursor &cursor, const QmlDocument::Ptr &doc);
|
||||||
|
|
||||||
QStack<QmlJS::AST::Node *> expressionScopes() const
|
QStack<QmlSymbol *> expressionScopes() const
|
||||||
{ return _expressionScopes; }
|
{ return _expressionScopes; }
|
||||||
|
|
||||||
QmlJS::AST::Node *expressionNode() const
|
QmlJS::AST::Node *expressionNode() const
|
||||||
@@ -28,26 +37,21 @@ public:
|
|||||||
int expressionLength() const
|
int expressionLength() const
|
||||||
{ return _expressionLength; }
|
{ return _expressionLength; }
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
virtual bool visit(QmlJS::AST::Block *ast);
|
void parseExpression(const QTextBlock &block);
|
||||||
virtual bool visit(QmlJS::AST::FieldMemberExpression *ast);
|
|
||||||
virtual bool visit(QmlJS::AST::IdentifierExpression *ast);
|
|
||||||
virtual bool visit(QmlJS::AST::UiImport *ast);
|
|
||||||
virtual bool visit(QmlJS::AST::UiObjectBinding *ast);
|
|
||||||
virtual bool visit(QmlJS::AST::UiObjectDefinition *ast);
|
|
||||||
virtual bool visit(QmlJS::AST::UiQualifiedId *ast);
|
|
||||||
|
|
||||||
virtual void endVisit(QmlJS::AST::Block *);
|
QmlJS::AST::ExpressionNode *tryExpression(const QString &text);
|
||||||
virtual void endVisit(QmlJS::AST::UiObjectBinding *);
|
QmlJS::AST::Statement *tryStatement(const QString &text);
|
||||||
virtual void endVisit(QmlJS::AST::UiObjectDefinition *);
|
QmlJS::AST::UiObjectMember *tryBinding(const QString &text);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QStack<QmlJS::AST::Node *> _scopes;
|
QStack<QmlSymbol *> _expressionScopes;
|
||||||
QStack<QmlJS::AST::Node *> _expressionScopes;
|
|
||||||
QmlJS::AST::Node *_expressionNode;
|
QmlJS::AST::Node *_expressionNode;
|
||||||
int _expressionOffset;
|
int _expressionOffset;
|
||||||
int _expressionLength;
|
int _expressionLength;
|
||||||
quint32 _pos;
|
quint32 _pos;
|
||||||
|
QmlJS::Engine *_engine;
|
||||||
|
QmlJS::NodePool *_nodePool;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ using namespace QmlEditor::Internal;
|
|||||||
using namespace QmlJS;
|
using namespace QmlJS;
|
||||||
using namespace QmlJS::AST;
|
using namespace QmlJS::AST;
|
||||||
|
|
||||||
QmlLookupContext::QmlLookupContext(const QStack<QmlJS::AST::Node *> &scopes,
|
QmlLookupContext::QmlLookupContext(const QStack<QmlSymbol *> &scopes,
|
||||||
const QmlDocument::Ptr &doc,
|
const QmlDocument::Ptr &doc,
|
||||||
const Snapshot &snapshot):
|
const Snapshot &snapshot):
|
||||||
_scopes(scopes),
|
_scopes(scopes),
|
||||||
@@ -19,28 +19,49 @@ QmlLookupContext::QmlLookupContext(const QStack<QmlJS::AST::Node *> &scopes,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QmlLookupContext::~QmlLookupContext()
|
static inline int findFirstQmlObjectScope(const QStack<QmlSymbol*> &scopes, int startIdx)
|
||||||
{
|
{
|
||||||
qDeleteAll(_temporarySymbols);
|
if (startIdx < 0 || startIdx >= scopes.size())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (int i = startIdx; i >= 0; --i) {
|
||||||
|
QmlSymbol *current = scopes.at(i);
|
||||||
|
|
||||||
|
if (current->isSymbolFromFile()) {
|
||||||
|
Node *node = current->asSymbolFromFile()->node();
|
||||||
|
|
||||||
|
if (cast<UiObjectBinding*>(node) || cast<UiObjectDefinition*>(node)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QmlSymbol *resolveParent(const QStack<QmlSymbol*> &scopes)
|
||||||
|
{
|
||||||
|
int idx = findFirstQmlObjectScope(scopes, scopes.size() - 1);
|
||||||
|
if (idx < 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
idx = findFirstQmlObjectScope(scopes, idx - 1);
|
||||||
|
|
||||||
|
if (idx < 0)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return scopes.at(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
QmlSymbol *QmlLookupContext::resolve(const QString &name)
|
QmlSymbol *QmlLookupContext::resolve(const QString &name)
|
||||||
{
|
{
|
||||||
// look at property definitions
|
// look at property definitions
|
||||||
if (QmlSymbol *propertySymbol = resolveProperty(name, _scopes.top(), _doc->fileName()))
|
if (!_scopes.isEmpty())
|
||||||
return propertySymbol;
|
if (QmlSymbol *propertySymbol = resolveProperty(name, _scopes.top(), _doc->fileName()))
|
||||||
|
return propertySymbol;
|
||||||
|
|
||||||
if (name == "parent") {
|
if (name == "parent") {
|
||||||
for (int i = _scopes.size() - 2; i >= 0; --i) {
|
return resolveParent(_scopes);
|
||||||
Node *scope = _scopes.at(i);
|
|
||||||
|
|
||||||
if (UiObjectDefinition *definition = cast<UiObjectDefinition*>(scope))
|
|
||||||
return createSymbol(_doc->fileName(), definition);
|
|
||||||
else if (UiObjectBinding *binding = cast<UiObjectBinding*>(scope))
|
|
||||||
return createSymbol(_doc->fileName(), binding);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// look at the ids.
|
// look at the ids.
|
||||||
@@ -52,13 +73,6 @@ QmlSymbol *QmlLookupContext::resolve(const QString &name)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QmlSymbol *QmlLookupContext::createSymbol(const QString &fileName, QmlJS::AST::UiObjectMember *node)
|
|
||||||
{
|
|
||||||
QmlSymbol *symbol = new QmlSymbolFromFile(fileName, node);
|
|
||||||
_temporarySymbols.append(symbol);
|
|
||||||
return symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
QmlSymbol *QmlLookupContext::resolveType(const QString &name, const QString &fileName)
|
QmlSymbol *QmlLookupContext::resolveType(const QString &name, const QString &fileName)
|
||||||
{
|
{
|
||||||
// TODO: handle import-as.
|
// TODO: handle import-as.
|
||||||
@@ -88,66 +102,41 @@ QmlSymbol *QmlLookupContext::resolveType(const QString &name, const QString &fil
|
|||||||
if (importedTypes.contains(name)) {
|
if (importedTypes.contains(name)) {
|
||||||
QmlDocument::Ptr importedDoc = importedTypes.value(name);
|
QmlDocument::Ptr importedDoc = importedTypes.value(name);
|
||||||
|
|
||||||
UiProgram *importedProgram = importedDoc->program();
|
return importedDoc->symbols().at(0);
|
||||||
if (importedProgram && importedProgram->members && importedProgram->members->member)
|
|
||||||
return createSymbol(importedDoc->fileName(), importedProgram->members->member);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QmlSymbol *QmlLookupContext::resolveProperty(const QString &name, Node *scope, const QString &fileName)
|
QmlSymbol *QmlLookupContext::resolveProperty(const QString &name, QmlSymbol *scope, const QString &fileName)
|
||||||
{
|
{
|
||||||
|
foreach (QmlSymbol *symbol, scope->members())
|
||||||
|
if (symbol->name() == name)
|
||||||
|
return symbol;
|
||||||
|
|
||||||
UiQualifiedId *typeName = 0;
|
UiQualifiedId *typeName = 0;
|
||||||
|
|
||||||
if (UiObjectBinding *binding = cast<UiObjectBinding*>(scope)) {
|
if (scope->isSymbolFromFile()) {
|
||||||
if (QmlSymbol *symbol = resolveProperty(name, binding->initializer, fileName))
|
Node *ast = scope->asSymbolFromFile()->node();
|
||||||
return symbol;
|
|
||||||
else
|
if (UiObjectBinding *binding = cast<UiObjectBinding*>(ast)) {
|
||||||
typeName = binding->qualifiedTypeNameId;
|
typeName = binding->qualifiedTypeNameId;
|
||||||
} else if (UiObjectDefinition *definition = cast<UiObjectDefinition*>(scope)) {
|
} else if (UiObjectDefinition *definition = cast<UiObjectDefinition*>(ast)) {
|
||||||
if (QmlSymbol *symbol = resolveProperty(name, definition->initializer, fileName))
|
|
||||||
return symbol;
|
|
||||||
else
|
|
||||||
typeName = definition->qualifiedTypeNameId;
|
typeName = definition->qualifiedTypeNameId;
|
||||||
} // TODO: extend this to handle (JavaScript) block scopes.
|
} // TODO: extend this to handle (JavaScript) block scopes.
|
||||||
|
}
|
||||||
|
|
||||||
if (typeName == 0)
|
if (typeName == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
QmlSymbol *typeSymbol = resolveType(toString(typeName), fileName);
|
QmlSymbol *typeSymbol = resolveType(toString(typeName), fileName);
|
||||||
if (typeSymbol && typeSymbol->isSymbolFromFile()) {
|
if (!typeSymbol)
|
||||||
return resolveProperty(name, typeSymbol->asSymbolFromFile()->node(), typeSymbol->asSymbolFromFile()->fileName());
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
QmlSymbol *QmlLookupContext::resolveProperty(const QString &name, QmlJS::AST::UiObjectInitializer *initializer, const QString &fileName)
|
|
||||||
{
|
|
||||||
if (!initializer)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (UiObjectMemberList *iter = initializer->members; iter; iter = iter->next) {
|
if (typeSymbol->isSymbolFromFile()) {
|
||||||
UiObjectMember *member = iter->member;
|
return resolveProperty(name, typeSymbol->asSymbolFromFile(), typeSymbol->asSymbolFromFile()->fileName());
|
||||||
if (!member)
|
} // TODO: internal types
|
||||||
continue;
|
|
||||||
|
|
||||||
if (UiPublicMember *publicMember = cast<UiPublicMember*>(member)) {
|
|
||||||
if (name == publicMember->name->asString())
|
|
||||||
return createSymbol(fileName, publicMember);
|
|
||||||
} else if (UiObjectBinding *objectBinding = cast<UiObjectBinding*>(member)) {
|
|
||||||
if (name == toString(objectBinding->qualifiedId))
|
|
||||||
return createSymbol(fileName, objectBinding);
|
|
||||||
} else if (UiArrayBinding *arrayBinding = cast<UiArrayBinding*>(member)) {
|
|
||||||
if (name == toString(arrayBinding->qualifiedId))
|
|
||||||
return createSymbol(fileName, arrayBinding);
|
|
||||||
} else if (UiScriptBinding *scriptBinding = cast<UiScriptBinding*>(member)) {
|
|
||||||
if (name == toString(scriptBinding->qualifiedId))
|
|
||||||
return createSymbol(fileName, scriptBinding);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -169,10 +158,17 @@ QString QmlLookupContext::toString(UiQualifiedId *id)
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QmlSymbol*> QmlLookupContext::visibleSymbols(QmlJS::AST::Node * /* scope */)
|
QList<QmlSymbol*> QmlLookupContext::visibleSymbolsInScope()
|
||||||
{
|
{
|
||||||
// FIXME
|
QList<QmlSymbol*> result;
|
||||||
return QList<QmlSymbol*>();
|
|
||||||
|
if (!_scopes.isEmpty()) {
|
||||||
|
QmlSymbol *scope = _scopes.top();
|
||||||
|
|
||||||
|
result.append(scope->members());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QmlSymbol*> QmlLookupContext::visibleTypes()
|
QList<QmlSymbol*> QmlLookupContext::visibleTypes()
|
||||||
@@ -196,11 +192,7 @@ QList<QmlSymbol*> QmlLookupContext::visibleTypes()
|
|||||||
|
|
||||||
const QMap<QString, QmlDocument::Ptr> types = _snapshot.componentsDefinedByImportedDocuments(_doc, path);
|
const QMap<QString, QmlDocument::Ptr> types = _snapshot.componentsDefinedByImportedDocuments(_doc, path);
|
||||||
foreach (const QmlDocument::Ptr typeDoc, types) {
|
foreach (const QmlDocument::Ptr typeDoc, types) {
|
||||||
UiProgram *typeProgram = typeDoc->program();
|
result.append(typeDoc->symbols().at(0));
|
||||||
|
|
||||||
if (typeProgram && typeProgram->members && typeProgram->members->member) {
|
|
||||||
result.append(createSymbol(typeDoc->fileName(), typeProgram->members->member));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,9 @@ namespace Internal {
|
|||||||
class QmlLookupContext
|
class QmlLookupContext
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QmlLookupContext(const QStack<QmlJS::AST::Node *> &scopes,
|
QmlLookupContext(const QStack<QmlSymbol *> &scopes,
|
||||||
const QmlDocument::Ptr &doc,
|
const QmlDocument::Ptr &doc,
|
||||||
const Snapshot &snapshot);
|
const Snapshot &snapshot);
|
||||||
~QmlLookupContext();
|
|
||||||
|
|
||||||
QmlSymbol *resolve(const QString &name);
|
QmlSymbol *resolve(const QString &name);
|
||||||
QmlSymbol *resolveType(const QString &name)
|
QmlSymbol *resolveType(const QString &name)
|
||||||
@@ -27,23 +26,19 @@ public:
|
|||||||
QmlDocument::Ptr document() const
|
QmlDocument::Ptr document() const
|
||||||
{ return _doc; }
|
{ return _doc; }
|
||||||
|
|
||||||
QList<QmlSymbol*> visibleSymbols(QmlJS::AST::Node *scope);
|
QList<QmlSymbol*> visibleSymbolsInScope();
|
||||||
QList<QmlSymbol*> visibleTypes();
|
QList<QmlSymbol*> visibleTypes();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QmlSymbol *createSymbol(const QString &fileName, QmlJS::AST::UiObjectMember *node);
|
|
||||||
|
|
||||||
QmlSymbol *resolveType(const QString &name, const QString &fileName);
|
QmlSymbol *resolveType(const QString &name, const QString &fileName);
|
||||||
QmlSymbol *resolveProperty(const QString &name, QmlJS::AST::Node *scope, const QString &fileName);
|
QmlSymbol *resolveProperty(const QString &name, QmlSymbol *scope, const QString &fileName);
|
||||||
QmlSymbol *resolveProperty(const QString &name, QmlJS::AST::UiObjectInitializer *initializer, const QString &fileName);
|
|
||||||
|
|
||||||
static QString toString(QmlJS::AST::UiQualifiedId *id);
|
static QString toString(QmlJS::AST::UiQualifiedId *id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QStack<QmlJS::AST::Node *> _scopes;
|
QStack<QmlSymbol *> _scopes;
|
||||||
QmlDocument::Ptr _doc;
|
QmlDocument::Ptr _doc;
|
||||||
Snapshot _snapshot;
|
Snapshot _snapshot;
|
||||||
QList<QmlSymbol*> _temporarySymbols;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
@@ -12,11 +12,6 @@ QmlResolveExpression::QmlResolveExpression(const QmlLookupContext &context)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QmlResolveExpression::~QmlResolveExpression()
|
|
||||||
{
|
|
||||||
qDeleteAll(_temporarySymbols);
|
|
||||||
}
|
|
||||||
|
|
||||||
QmlSymbol *QmlResolveExpression::typeOf(Node *node)
|
QmlSymbol *QmlResolveExpression::typeOf(Node *node)
|
||||||
{
|
{
|
||||||
QmlSymbol *previousValue = switchValue(0);
|
QmlSymbol *previousValue = switchValue(0);
|
||||||
@@ -25,6 +20,30 @@ QmlSymbol *QmlResolveExpression::typeOf(Node *node)
|
|||||||
return switchValue(previousValue);
|
return switchValue(previousValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<QmlSymbol*> QmlResolveExpression::visibleSymbols(Node *node)
|
||||||
|
{
|
||||||
|
QList<QmlSymbol*> result;
|
||||||
|
|
||||||
|
QmlSymbol *symbol = typeOf(node);
|
||||||
|
if (symbol) {
|
||||||
|
if (symbol->isIdSymbol())
|
||||||
|
symbol = symbol->asIdSymbol()->parentNode();
|
||||||
|
result.append(symbol->members());
|
||||||
|
|
||||||
|
// TODO: also add symbols from super-types
|
||||||
|
} else {
|
||||||
|
result.append(_context.visibleTypes());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node) {
|
||||||
|
foreach (QmlIdSymbol *idSymbol, _context.document()->ids().values())
|
||||||
|
result.append(idSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.append(_context.visibleSymbolsInScope());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
QmlSymbol *QmlResolveExpression::switchValue(QmlSymbol *value)
|
QmlSymbol *QmlResolveExpression::switchValue(QmlSymbol *value)
|
||||||
{
|
{
|
||||||
@@ -58,52 +77,19 @@ bool QmlResolveExpression::visit(FieldMemberExpression *ast)
|
|||||||
{
|
{
|
||||||
const QString memberName = ast->name->asString();
|
const QString memberName = ast->name->asString();
|
||||||
|
|
||||||
const QmlSymbol *base = typeOf(ast->base);
|
QmlSymbol *base = typeOf(ast->base);
|
||||||
if (!base)
|
if (!base)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (base->isIdSymbol())
|
if (base->isIdSymbol())
|
||||||
base = base->asIdSymbol()->parentNode();
|
base = base->asIdSymbol()->parentNode();
|
||||||
|
|
||||||
UiObjectMemberList *members = 0;
|
if (!base)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (const QmlSymbolFromFile *symbol = base->asSymbolFromFile()) {
|
foreach (QmlSymbol *memberSymbol, base->members())
|
||||||
Node *node = symbol->node();
|
if (memberSymbol->name() == memberName)
|
||||||
|
_value = memberSymbol;
|
||||||
if (UiObjectBinding *binding = cast<UiObjectBinding*>(node)) {
|
|
||||||
if (binding->initializer)
|
|
||||||
members = binding->initializer->members;
|
|
||||||
} else if (UiObjectDefinition *definition = cast<UiObjectDefinition*>(node)) {
|
|
||||||
if (definition->initializer)
|
|
||||||
members = definition->initializer->members;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (UiObjectMemberList *it = members; it; it = it->next) {
|
|
||||||
UiObjectMember *member = it->member;
|
|
||||||
|
|
||||||
if (UiPublicMember *publicMember = cast<UiPublicMember *>(member)) {
|
|
||||||
if (publicMember->name && publicMember->name->asString() == memberName) {
|
|
||||||
_value = createPropertyDefinitionSymbol(publicMember);
|
|
||||||
break; // we're done.
|
|
||||||
}
|
|
||||||
} else if (UiObjectBinding *objectBinding = cast<UiObjectBinding*>(member)) {
|
|
||||||
if (matches(objectBinding->qualifiedId, memberName)) {
|
|
||||||
_value = createSymbolFromFile(objectBinding);
|
|
||||||
break; // we're done
|
|
||||||
}
|
|
||||||
} else if (UiScriptBinding *scriptBinding = cast<UiScriptBinding*>(member)) {
|
|
||||||
if (matches(scriptBinding->qualifiedId, memberName)) {
|
|
||||||
_value = createSymbolFromFile(scriptBinding);
|
|
||||||
break; // we're done
|
|
||||||
}
|
|
||||||
} else if (UiArrayBinding *arrayBinding = cast<UiArrayBinding*>(member)) {
|
|
||||||
if (matches(arrayBinding->qualifiedId, memberName)) {
|
|
||||||
_value = createSymbolFromFile(arrayBinding);
|
|
||||||
break; // we're done
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -114,17 +100,3 @@ bool QmlResolveExpression::visit(QmlJS::AST::UiQualifiedId *ast)
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QmlPropertyDefinitionSymbol *QmlResolveExpression::createPropertyDefinitionSymbol(QmlJS::AST::UiPublicMember *ast)
|
|
||||||
{
|
|
||||||
QmlPropertyDefinitionSymbol *symbol = new QmlPropertyDefinitionSymbol(_context.document()->fileName(), ast);
|
|
||||||
_temporarySymbols.append(symbol);
|
|
||||||
return symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
QmlSymbolFromFile *QmlResolveExpression::createSymbolFromFile(QmlJS::AST::UiObjectMember *ast)
|
|
||||||
{
|
|
||||||
QmlSymbolFromFile *symbol = new QmlSymbolFromFile(_context.document()->fileName(), ast);
|
|
||||||
_temporarySymbols.append(symbol);
|
|
||||||
return symbol;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -12,28 +12,21 @@ class QmlResolveExpression: protected QmlJS::AST::Visitor
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QmlResolveExpression(const QmlLookupContext &context);
|
QmlResolveExpression(const QmlLookupContext &context);
|
||||||
~QmlResolveExpression();
|
|
||||||
|
|
||||||
QmlSymbol *operator()(QmlJS::AST::Node *node)
|
QmlSymbol *typeOf(QmlJS::AST::Node *node);
|
||||||
{ return typeOf(node); }
|
QList<QmlSymbol*> visibleSymbols(QmlJS::AST::Node *node);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using QmlJS::AST::Visitor::visit;
|
using QmlJS::AST::Visitor::visit;
|
||||||
|
|
||||||
QmlSymbol *typeOf(QmlJS::AST::Node *node);
|
|
||||||
QmlSymbol *switchValue(QmlSymbol *symbol);
|
QmlSymbol *switchValue(QmlSymbol *symbol);
|
||||||
|
|
||||||
virtual bool visit(QmlJS::AST::FieldMemberExpression *ast);
|
virtual bool visit(QmlJS::AST::FieldMemberExpression *ast);
|
||||||
virtual bool visit(QmlJS::AST::IdentifierExpression *ast);
|
virtual bool visit(QmlJS::AST::IdentifierExpression *ast);
|
||||||
virtual bool visit(QmlJS::AST::UiQualifiedId *ast);
|
virtual bool visit(QmlJS::AST::UiQualifiedId *ast);
|
||||||
|
|
||||||
private:
|
|
||||||
QmlPropertyDefinitionSymbol *createPropertyDefinitionSymbol(QmlJS::AST::UiPublicMember *ast);
|
|
||||||
QmlSymbolFromFile *createSymbolFromFile(QmlJS::AST::UiObjectMember *ast);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QmlLookupContext _context;
|
QmlLookupContext _context;
|
||||||
QList<QmlSymbol*> _temporarySymbols;
|
|
||||||
QmlSymbol *_value;
|
QmlSymbol *_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
35
src/plugins/qmleditor/qmlscope.cpp
Normal file
35
src/plugins/qmleditor/qmlscope.cpp
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#include "qmlscope.h"
|
||||||
|
|
||||||
|
using namespace QmlEditor;
|
||||||
|
using namespace QmlEditor::Internal;
|
||||||
|
|
||||||
|
Scope::Scope(Scope *parentScope):
|
||||||
|
_parentScope(parentScope)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Scope::~Scope()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Scope::isJSScope()
|
||||||
|
{ return asJSScope() != 0; }
|
||||||
|
|
||||||
|
bool Scope::isQmlScope()
|
||||||
|
{ return asQmlScope() != 0; }
|
||||||
|
|
||||||
|
JSScope *Scope::asJSScope()
|
||||||
|
{ return 0; }
|
||||||
|
|
||||||
|
QmlScope *Scope::asQmlScope()
|
||||||
|
{ return 0; }
|
||||||
|
|
||||||
|
QmlScope::QmlScope(QmlScope *parentScope):
|
||||||
|
Scope(parentScope)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
JSScope::JSScope(Scope *parentScope):
|
||||||
|
Scope(parentScope)
|
||||||
|
{
|
||||||
|
}
|
||||||
40
src/plugins/qmleditor/qmlscope.h
Normal file
40
src/plugins/qmleditor/qmlscope.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#ifndef QMLSCOPE_H
|
||||||
|
#define QMLSCOPE_H
|
||||||
|
|
||||||
|
namespace QmlEditor {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class QmlScope;
|
||||||
|
class JSScope;
|
||||||
|
|
||||||
|
class Scope
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Scope(Scope *parentScope);
|
||||||
|
virtual ~Scope();
|
||||||
|
|
||||||
|
bool isQmlScope();
|
||||||
|
bool isJSScope();
|
||||||
|
|
||||||
|
virtual QmlScope *asQmlScope();
|
||||||
|
virtual JSScope *asJSScope();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Scope *_parentScope;
|
||||||
|
};
|
||||||
|
|
||||||
|
class QmlScope: public Scope
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QmlScope(QmlScope *parentScope);
|
||||||
|
};
|
||||||
|
|
||||||
|
class JSScope: public Scope
|
||||||
|
{
|
||||||
|
JSScope(Scope *parentScope);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace QmlEditor
|
||||||
|
|
||||||
|
#endif // QMLSCOPE_H
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "qmljsast_p.h"
|
#include "qmljsast_p.h"
|
||||||
|
#include "qmljsengine_p.h"
|
||||||
#include "qmlsymbol.h"
|
#include "qmlsymbol.h"
|
||||||
|
|
||||||
using namespace QmlEditor;
|
using namespace QmlEditor;
|
||||||
@@ -7,41 +8,67 @@ using namespace QmlJS::AST;
|
|||||||
|
|
||||||
QmlSymbol::~QmlSymbol()
|
QmlSymbol::~QmlSymbol()
|
||||||
{
|
{
|
||||||
|
qDeleteAll(_members);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QmlSymbol::isBuildInSymbol() const
|
bool QmlSymbol::isBuildInSymbol()
|
||||||
{ return asBuildInSymbol() != 0; }
|
{ return asBuildInSymbol() != 0; }
|
||||||
|
|
||||||
bool QmlSymbol::isSymbolFromFile() const
|
bool QmlSymbol::isSymbolFromFile()
|
||||||
{ return asSymbolFromFile() != 0; }
|
{ return asSymbolFromFile() != 0; }
|
||||||
|
|
||||||
bool QmlSymbol::isIdSymbol() const
|
bool QmlSymbol::isIdSymbol()
|
||||||
{ return asIdSymbol() != 0; }
|
{ return asIdSymbol() != 0; }
|
||||||
|
|
||||||
QmlBuildInSymbol const *QmlSymbol::asBuildInSymbol() const
|
bool QmlSymbol::isPropertyDefinitionSymbol()
|
||||||
|
{ return asPropertyDefinitionSymbol() != 0; }
|
||||||
|
|
||||||
|
QmlBuildInSymbol *QmlSymbol::asBuildInSymbol()
|
||||||
{ return 0; }
|
{ return 0; }
|
||||||
|
|
||||||
QmlSymbolFromFile const *QmlSymbol::asSymbolFromFile() const
|
QmlSymbolFromFile *QmlSymbol::asSymbolFromFile()
|
||||||
{ return 0; }
|
{ return 0; }
|
||||||
|
|
||||||
QmlIdSymbol const *QmlSymbol::asIdSymbol() const
|
QmlIdSymbol *QmlSymbol::asIdSymbol()
|
||||||
{ return 0; }
|
{ return 0; }
|
||||||
|
|
||||||
|
QmlPropertyDefinitionSymbol *QmlSymbol::asPropertyDefinitionSymbol()
|
||||||
|
{ return 0; }
|
||||||
|
|
||||||
|
const QmlSymbol::List QmlSymbol::members()
|
||||||
|
{ return _members; }
|
||||||
|
|
||||||
QmlBuildInSymbol::~QmlBuildInSymbol()
|
QmlBuildInSymbol::~QmlBuildInSymbol()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
QmlBuildInSymbol const* QmlBuildInSymbol::asBuildInSymbol() const
|
QmlBuildInSymbol *QmlBuildInSymbol::asBuildInSymbol()
|
||||||
{ return this; }
|
{ return this; }
|
||||||
|
|
||||||
QmlSymbolFromFile::QmlSymbolFromFile(const QString &fileName, QmlJS::AST::UiObjectMember *node):
|
QmlSymbolFromFile::QmlSymbolFromFile(const QString &fileName, QmlJS::AST::UiObjectMember *node):
|
||||||
_fileName(fileName),
|
_fileName(fileName),
|
||||||
_node(node)
|
_node(node)
|
||||||
{}
|
{
|
||||||
|
if (UiObjectBinding *objectBinding = cast<UiObjectBinding*>(_node)) {
|
||||||
|
if (objectBinding->initializer)
|
||||||
|
for (UiObjectMemberList *iter = objectBinding->initializer->members; iter; iter = iter->next)
|
||||||
|
if (iter->member)
|
||||||
|
todo.append(iter->member);
|
||||||
|
} else if (UiObjectDefinition *objectDefinition = cast<UiObjectDefinition*>(_node)) {
|
||||||
|
if (objectDefinition->initializer)
|
||||||
|
for (UiObjectMemberList *iter = objectDefinition->initializer->members; iter; iter = iter->next)
|
||||||
|
if (iter->member)
|
||||||
|
todo.append(iter->member);
|
||||||
|
} else if (UiArrayBinding *arrayBinding = cast<UiArrayBinding*>(_node)) {
|
||||||
|
for (UiArrayMemberList *iter = arrayBinding->members; iter; iter = iter->next)
|
||||||
|
if (iter->member)
|
||||||
|
todo.append(iter->member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QmlSymbolFromFile::~QmlSymbolFromFile()
|
QmlSymbolFromFile::~QmlSymbolFromFile()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
const QmlSymbolFromFile *QmlSymbolFromFile::asSymbolFromFile() const
|
QmlSymbolFromFile *QmlSymbolFromFile::asSymbolFromFile()
|
||||||
{ return this; }
|
{ return this; }
|
||||||
|
|
||||||
int QmlSymbolFromFile::line() const
|
int QmlSymbolFromFile::line() const
|
||||||
@@ -50,7 +77,76 @@ int QmlSymbolFromFile::line() const
|
|||||||
int QmlSymbolFromFile::column() const
|
int QmlSymbolFromFile::column() const
|
||||||
{ return _node->firstSourceLocation().startColumn; }
|
{ return _node->firstSourceLocation().startColumn; }
|
||||||
|
|
||||||
QmlIdSymbol::QmlIdSymbol(const QString &fileName, QmlJS::AST::UiScriptBinding *idNode, const QmlSymbolFromFile &parentNode):
|
static inline QString toString(UiQualifiedId *qId)
|
||||||
|
{
|
||||||
|
QString result;
|
||||||
|
|
||||||
|
for (UiQualifiedId *iter = qId; iter; iter = iter->next) {
|
||||||
|
if (!iter->name)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
result += iter->name->asString();
|
||||||
|
|
||||||
|
if (iter->next)
|
||||||
|
result += '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString QmlSymbolFromFile::name() const
|
||||||
|
{
|
||||||
|
if (UiObjectBinding *objectBinding = cast<UiObjectBinding*>(_node))
|
||||||
|
return toString(objectBinding->qualifiedId);
|
||||||
|
else if (UiScriptBinding *scriptBinding = cast<UiScriptBinding*>(_node))
|
||||||
|
return toString(scriptBinding->qualifiedId);
|
||||||
|
else if (UiArrayBinding *arrayBinding = cast<UiArrayBinding*>(_node))
|
||||||
|
return toString(arrayBinding->qualifiedId);
|
||||||
|
else if (UiObjectDefinition *objectDefinition = cast<UiObjectDefinition*>(_node))
|
||||||
|
return toString(objectDefinition->qualifiedTypeNameId);
|
||||||
|
else
|
||||||
|
return QString::null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QmlSymbol::List QmlSymbolFromFile::members()
|
||||||
|
{
|
||||||
|
if (!todo.isEmpty()) {
|
||||||
|
foreach (Node *node, todo) {
|
||||||
|
if (UiObjectBinding *objectBinding = cast<UiObjectBinding*>(node))
|
||||||
|
_members.append(new QmlSymbolFromFile(fileName(), objectBinding));
|
||||||
|
else if (UiObjectDefinition *objectDefinition = cast<UiObjectDefinition*>(node))
|
||||||
|
_members.append(new QmlSymbolFromFile(fileName(), objectDefinition));
|
||||||
|
else if (UiArrayBinding *arrayBinding = cast<UiArrayBinding*>(node))
|
||||||
|
_members.append(new QmlSymbolFromFile(fileName(), arrayBinding));
|
||||||
|
else if (UiPublicMember *publicMember = cast<UiPublicMember*>(node))
|
||||||
|
_members.append(new QmlPropertyDefinitionSymbol(fileName(), publicMember));
|
||||||
|
else if (UiScriptBinding *scriptBinding = cast<UiScriptBinding*>(node)) {
|
||||||
|
if (scriptBinding->qualifiedId && scriptBinding->qualifiedId->name && scriptBinding->qualifiedId->name->asString() == QLatin1String("id") && !scriptBinding->qualifiedId->next)
|
||||||
|
_members.append(new QmlIdSymbol(fileName(), scriptBinding, this));
|
||||||
|
else
|
||||||
|
_members.append(new QmlSymbolFromFile(fileName(), scriptBinding));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
todo.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _members;
|
||||||
|
}
|
||||||
|
|
||||||
|
QmlSymbolFromFile *QmlSymbolFromFile::findMember(QmlJS::AST::Node *memberNode)
|
||||||
|
{
|
||||||
|
List symbols = members();
|
||||||
|
|
||||||
|
foreach (QmlSymbol *symbol, symbols)
|
||||||
|
if (symbol->isSymbolFromFile())
|
||||||
|
if (memberNode == symbol->asSymbolFromFile()->node())
|
||||||
|
return symbol->asSymbolFromFile();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QmlIdSymbol::QmlIdSymbol(const QString &fileName, QmlJS::AST::UiScriptBinding *idNode, QmlSymbolFromFile *parentNode):
|
||||||
QmlSymbolFromFile(fileName, idNode),
|
QmlSymbolFromFile(fileName, idNode),
|
||||||
_parentNode(parentNode)
|
_parentNode(parentNode)
|
||||||
{}
|
{}
|
||||||
@@ -58,7 +154,7 @@ QmlIdSymbol::QmlIdSymbol(const QString &fileName, QmlJS::AST::UiScriptBinding *i
|
|||||||
QmlIdSymbol::~QmlIdSymbol()
|
QmlIdSymbol::~QmlIdSymbol()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
QmlIdSymbol const *QmlIdSymbol::asIdSymbol() const
|
QmlIdSymbol *QmlIdSymbol::asIdSymbol()
|
||||||
{ return this; }
|
{ return this; }
|
||||||
|
|
||||||
int QmlIdSymbol::line() const
|
int QmlIdSymbol::line() const
|
||||||
@@ -67,6 +163,16 @@ int QmlIdSymbol::line() const
|
|||||||
int QmlIdSymbol::column() const
|
int QmlIdSymbol::column() const
|
||||||
{ return idNode()->statement->firstSourceLocation().startColumn; }
|
{ return idNode()->statement->firstSourceLocation().startColumn; }
|
||||||
|
|
||||||
|
const QString QmlIdSymbol::id() const
|
||||||
|
{
|
||||||
|
if (ExpressionStatement *e = cast<ExpressionStatement*>(idNode()->statement))
|
||||||
|
if (IdentifierExpression *i = cast<IdentifierExpression*>(e->expression))
|
||||||
|
if (i->name)
|
||||||
|
return i->name->asString();
|
||||||
|
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
QmlJS::AST::UiScriptBinding *QmlIdSymbol::idNode() const
|
QmlJS::AST::UiScriptBinding *QmlIdSymbol::idNode() const
|
||||||
{ return cast<UiScriptBinding*>(node()); }
|
{ return cast<UiScriptBinding*>(node()); }
|
||||||
|
|
||||||
@@ -77,6 +183,9 @@ QmlPropertyDefinitionSymbol::QmlPropertyDefinitionSymbol(const QString &fileName
|
|||||||
QmlPropertyDefinitionSymbol::~QmlPropertyDefinitionSymbol()
|
QmlPropertyDefinitionSymbol::~QmlPropertyDefinitionSymbol()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
QmlPropertyDefinitionSymbol *QmlPropertyDefinitionSymbol::asPropertyDefinitionSymbol()
|
||||||
|
{ return this; }
|
||||||
|
|
||||||
int QmlPropertyDefinitionSymbol::line() const
|
int QmlPropertyDefinitionSymbol::line() const
|
||||||
{ return propertyNode()->identifierToken.startLine; }
|
{ return propertyNode()->identifierToken.startLine; }
|
||||||
|
|
||||||
@@ -85,3 +194,6 @@ int QmlPropertyDefinitionSymbol::column() const
|
|||||||
|
|
||||||
QmlJS::AST::UiPublicMember *QmlPropertyDefinitionSymbol::propertyNode() const
|
QmlJS::AST::UiPublicMember *QmlPropertyDefinitionSymbol::propertyNode() const
|
||||||
{ return cast<UiPublicMember*>(node()); }
|
{ return cast<UiPublicMember*>(node()); }
|
||||||
|
|
||||||
|
const QString QmlPropertyDefinitionSymbol::name() const
|
||||||
|
{ return propertyNode()->name->asString(); }
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef QMLSYMBOL_H
|
#ifndef QMLSYMBOL_H
|
||||||
#define QMLSYMBOL_H
|
#define QMLSYMBOL_H
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
#include "qmljsastfwd_p.h"
|
#include "qmljsastfwd_p.h"
|
||||||
@@ -10,25 +11,44 @@ namespace QmlEditor {
|
|||||||
class QmlSymbol
|
class QmlSymbol
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~QmlSymbol() = 0;
|
typedef QList<QmlSymbol*> List;
|
||||||
|
|
||||||
bool isBuildInSymbol() const;
|
public:
|
||||||
bool isSymbolFromFile() const;
|
virtual ~QmlSymbol();
|
||||||
bool isIdSymbol() const;
|
|
||||||
|
|
||||||
virtual class QmlBuildInSymbol const *asBuildInSymbol() const;
|
virtual const QString name() const = 0;
|
||||||
virtual class QmlSymbolFromFile const *asSymbolFromFile() const;
|
virtual const List members();
|
||||||
virtual class QmlIdSymbol const *asIdSymbol() const;
|
|
||||||
|
bool isBuildInSymbol();
|
||||||
|
bool isSymbolFromFile();
|
||||||
|
bool isIdSymbol();
|
||||||
|
bool isPropertyDefinitionSymbol();
|
||||||
|
|
||||||
|
virtual class QmlBuildInSymbol *asBuildInSymbol();
|
||||||
|
virtual class QmlSymbolFromFile *asSymbolFromFile();
|
||||||
|
virtual class QmlIdSymbol *asIdSymbol();
|
||||||
|
virtual class QmlPropertyDefinitionSymbol *asPropertyDefinitionSymbol();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
List _members;
|
||||||
};
|
};
|
||||||
|
|
||||||
class QmlBuildInSymbol: public QmlSymbol
|
class QmlBuildInSymbol: public QmlSymbol
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
QmlBuildInSymbol(const QString &name): _name(name) {}
|
||||||
virtual ~QmlBuildInSymbol();
|
virtual ~QmlBuildInSymbol();
|
||||||
|
|
||||||
virtual QmlBuildInSymbol const *asBuildInSymbol() const;
|
virtual QmlBuildInSymbol *asBuildInSymbol();
|
||||||
|
|
||||||
|
virtual const QString name() const
|
||||||
|
{ return _name; }
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// virtual const List members();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QString _name;
|
||||||
};
|
};
|
||||||
|
|
||||||
class QmlSymbolFromFile: public QmlSymbol
|
class QmlSymbolFromFile: public QmlSymbol
|
||||||
@@ -37,7 +57,7 @@ public:
|
|||||||
QmlSymbolFromFile(const QString &fileName, QmlJS::AST::UiObjectMember *node);
|
QmlSymbolFromFile(const QString &fileName, QmlJS::AST::UiObjectMember *node);
|
||||||
virtual ~QmlSymbolFromFile();
|
virtual ~QmlSymbolFromFile();
|
||||||
|
|
||||||
virtual QmlSymbolFromFile const *asSymbolFromFile() const;
|
virtual QmlSymbolFromFile *asSymbolFromFile();
|
||||||
|
|
||||||
QString fileName() const
|
QString fileName() const
|
||||||
{ return _fileName; }
|
{ return _fileName; }
|
||||||
@@ -48,30 +68,43 @@ public:
|
|||||||
QmlJS::AST::UiObjectMember *node() const
|
QmlJS::AST::UiObjectMember *node() const
|
||||||
{ return _node; }
|
{ return _node; }
|
||||||
|
|
||||||
|
virtual const QString name() const;
|
||||||
|
virtual const List members();
|
||||||
|
virtual QmlSymbolFromFile *findMember(QmlJS::AST::Node *memberNode);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void fillTodo(QmlJS::AST::UiObjectMemberList *members);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString _fileName;
|
QString _fileName;
|
||||||
QmlJS::AST::UiObjectMember *_node;
|
QmlJS::AST::UiObjectMember *_node;
|
||||||
|
QList<QmlJS::AST::Node*> todo;
|
||||||
};
|
};
|
||||||
|
|
||||||
class QmlIdSymbol: public QmlSymbolFromFile
|
class QmlIdSymbol: public QmlSymbolFromFile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QmlIdSymbol(const QString &fileName, QmlJS::AST::UiScriptBinding *idNode, const QmlSymbolFromFile &parentNode);
|
QmlIdSymbol(const QString &fileName, QmlJS::AST::UiScriptBinding *idNode, QmlSymbolFromFile *parentNode);
|
||||||
virtual ~QmlIdSymbol();
|
virtual ~QmlIdSymbol();
|
||||||
|
|
||||||
QmlIdSymbol const *asIdSymbol() const;
|
QmlIdSymbol *asIdSymbol();
|
||||||
|
|
||||||
virtual int line() const;
|
virtual int line() const;
|
||||||
virtual int column() const;
|
virtual int column() const;
|
||||||
|
|
||||||
QmlSymbolFromFile const *parentNode() const
|
QmlSymbolFromFile *parentNode() const
|
||||||
{ return &_parentNode; }
|
{ return _parentNode; }
|
||||||
|
|
||||||
|
virtual const QString name() const
|
||||||
|
{ return "id"; }
|
||||||
|
|
||||||
|
virtual const QString id() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QmlJS::AST::UiScriptBinding *idNode() const;
|
QmlJS::AST::UiScriptBinding *idNode() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QmlSymbolFromFile _parentNode;
|
QmlSymbolFromFile *_parentNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
class QmlPropertyDefinitionSymbol: public QmlSymbolFromFile
|
class QmlPropertyDefinitionSymbol: public QmlSymbolFromFile
|
||||||
@@ -80,9 +113,13 @@ public:
|
|||||||
QmlPropertyDefinitionSymbol(const QString &fileName, QmlJS::AST::UiPublicMember *propertyNode);
|
QmlPropertyDefinitionSymbol(const QString &fileName, QmlJS::AST::UiPublicMember *propertyNode);
|
||||||
virtual ~QmlPropertyDefinitionSymbol();
|
virtual ~QmlPropertyDefinitionSymbol();
|
||||||
|
|
||||||
|
QmlPropertyDefinitionSymbol *asPropertyDefinitionSymbol();
|
||||||
|
|
||||||
virtual int line() const;
|
virtual int line() const;
|
||||||
virtual int column() const;
|
virtual int column() const;
|
||||||
|
|
||||||
|
virtual const QString name() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QmlJS::AST::UiPublicMember *propertyNode() const;
|
QmlJS::AST::UiPublicMember *propertyNode() const;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user