2010-01-04 11:30:14 +01:00
|
|
|
/**************************************************************************
|
|
|
|
**
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
**
|
|
|
|
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
|
|
**
|
|
|
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
|
|
**
|
|
|
|
** Commercial Usage
|
|
|
|
**
|
|
|
|
** Licensees holding valid Qt Commercial licenses may use this file in
|
|
|
|
** accordance with the Qt Commercial License Agreement provided with the
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
** a written agreement between you and Nokia.
|
|
|
|
**
|
|
|
|
** GNU Lesser General Public License Usage
|
|
|
|
**
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
|
|
** General Public License version 2.1 as published by the Free Software
|
|
|
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
|
|
** packaging of this file. Please review the following information to
|
|
|
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
|
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
|
|
**
|
|
|
|
** If you are unsure which license is appropriate for your use, please
|
|
|
|
** contact the sales department at http://qt.nokia.com/contact.
|
|
|
|
**
|
|
|
|
**************************************************************************/
|
|
|
|
|
2009-09-22 16:32:49 +02:00
|
|
|
#include "qmlexpressionundercursor.h"
|
|
|
|
|
2010-01-15 13:39:54 +01:00
|
|
|
#include <qmljs/parser/qmljsast_p.h>
|
|
|
|
#include <qmljs/parser/qmljsastvisitor_p.h>
|
|
|
|
#include <qmljs/parser/qmljsengine_p.h>
|
|
|
|
#include <qmljs/parser/qmljslexer_p.h>
|
|
|
|
#include <qmljs/parser/qmljsnodepool_p.h>
|
|
|
|
#include <qmljs/parser/qmljsparser_p.h>
|
2009-12-02 17:59:27 +01:00
|
|
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
2009-12-07 16:57:31 +01:00
|
|
|
using namespace Qml;
|
2009-09-22 16:32:49 +02:00
|
|
|
using namespace QmlJS;
|
|
|
|
using namespace QmlJS::AST;
|
|
|
|
|
2010-01-15 17:20:03 +01:00
|
|
|
namespace QmlJSEditor {
|
2009-10-02 10:49:33 +02:00
|
|
|
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;
|
2010-01-18 12:38:36 +01:00
|
|
|
Node::accept(doc->qmlProgram(), this);
|
2009-10-02 10:49:33 +02:00
|
|
|
return _scopes;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
2009-12-01 11:33:13 +01:00
|
|
|
virtual bool visit(Block * /*ast*/)
|
2009-10-02 10:49:33 +02:00
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
// if (_pos > ast->lbraceToken.end() && _pos < ast->rbraceToken.offset) {
|
|
|
|
// push(ast);
|
|
|
|
// Node::accept(ast->statements, this);
|
|
|
|
// }
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(UiObjectBinding *ast)
|
|
|
|
{
|
2009-12-07 16:57:31 +01:00
|
|
|
if (ast->initializer && ast->initializer->lbraceToken.offset < _pos && _pos <= ast->initializer->rbraceToken.end()) {
|
2009-10-02 10:49:33 +02:00
|
|
|
push(ast);
|
|
|
|
Node::accept(ast->initializer, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool visit(UiObjectDefinition *ast)
|
|
|
|
{
|
2009-12-07 16:57:31 +01:00
|
|
|
if (ast->initializer && ast->initializer->lbraceToken.offset < _pos && _pos <= ast->initializer->rbraceToken.end()) {
|
2009-10-02 10:49:33 +02:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-15 17:20:03 +01:00
|
|
|
using namespace QmlJSEditor;
|
|
|
|
using namespace QmlJSEditor::Internal;
|
2009-10-02 10:49:33 +02:00
|
|
|
|
2009-09-22 16:32:49 +02:00
|
|
|
QmlExpressionUnderCursor::QmlExpressionUnderCursor()
|
2009-09-22 17:25:18 +02:00
|
|
|
: _expressionNode(0),
|
2009-10-02 10:49:33 +02:00
|
|
|
_pos(0), _engine(0), _nodePool(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QmlExpressionUnderCursor::~QmlExpressionUnderCursor()
|
2009-09-22 16:32:49 +02:00
|
|
|
{
|
2009-10-02 10:49:33 +02:00
|
|
|
if (_engine) { delete _engine; _engine = 0; }
|
|
|
|
if (_nodePool) { delete _nodePool; _nodePool = 0; }
|
2009-09-22 16:32:49 +02:00
|
|
|
}
|
|
|
|
|
2009-09-22 17:25:18 +02:00
|
|
|
void QmlExpressionUnderCursor::operator()(const QTextCursor &cursor,
|
2009-10-02 10:49:33 +02:00
|
|
|
const QmlDocument::Ptr &doc)
|
2009-09-22 16:32:49 +02:00
|
|
|
{
|
2009-10-02 10:49:33 +02:00
|
|
|
if (_engine) { delete _engine; _engine = 0; }
|
|
|
|
if (_nodePool) { delete _nodePool; _nodePool = 0; }
|
|
|
|
|
2009-09-22 16:32:49 +02:00
|
|
|
_pos = cursor.position();
|
2009-09-22 17:25:18 +02:00
|
|
|
_expressionNode = 0;
|
2009-09-23 12:21:43 +02:00
|
|
|
_expressionOffset = -1;
|
|
|
|
_expressionLength = -1;
|
2009-10-02 10:49:33 +02:00
|
|
|
_expressionScopes.clear();
|
2009-09-22 17:25:18 +02:00
|
|
|
|
2009-10-02 10:49:33 +02:00
|
|
|
const QTextBlock block = cursor.block();
|
|
|
|
parseExpression(block);
|
2009-09-22 16:32:49 +02:00
|
|
|
|
2009-10-02 10:49:33 +02:00
|
|
|
if (_expressionOffset != -1) {
|
|
|
|
ScopeCalculator calculator;
|
|
|
|
_expressionScopes = calculator(doc, _expressionOffset);
|
2009-09-23 12:21:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-02 10:49:33 +02:00
|
|
|
void QmlExpressionUnderCursor::parseExpression(const QTextBlock &block)
|
2009-09-23 12:21:43 +02:00
|
|
|
{
|
2009-10-02 10:49:33 +02:00
|
|
|
int textPosition = _pos - block.position();
|
|
|
|
const QString blockText = block.text();
|
|
|
|
if (textPosition > 0) {
|
|
|
|
if (blockText.at(textPosition - 1) == QLatin1Char('.'))
|
|
|
|
--textPosition;
|
|
|
|
} else {
|
|
|
|
textPosition = 0;
|
2009-09-23 12:21:43 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 10:49:33 +02:00
|
|
|
const QString text = blockText.left(textPosition);
|
2009-09-23 12:21:43 +02:00
|
|
|
|
2009-10-02 10:49:33 +02:00
|
|
|
Node *node = 0;
|
2009-09-22 16:32:49 +02:00
|
|
|
|
2009-10-02 10:49:33 +02:00
|
|
|
if (UiObjectMember *binding = tryBinding(text)) {
|
2009-10-02 11:29:54 +02:00
|
|
|
// qDebug() << "**** binding";
|
2009-10-02 10:49:33 +02:00
|
|
|
node = binding;
|
|
|
|
} else if (Statement *stmt = tryStatement(text)) {
|
2009-10-02 11:29:54 +02:00
|
|
|
// qDebug() << "**** statement";
|
2009-10-02 10:49:33 +02:00
|
|
|
node = stmt;
|
|
|
|
} else {
|
2009-10-02 11:29:54 +02:00
|
|
|
// qDebug() << "**** none";
|
2009-10-02 10:49:33 +02:00
|
|
|
}
|
2009-09-23 13:59:38 +02:00
|
|
|
|
2009-10-02 10:49:33 +02:00
|
|
|
if (node) {
|
|
|
|
PositionCalculator calculator;
|
|
|
|
_expressionNode = calculator(node, textPosition);
|
|
|
|
_expressionOffset = calculator.offset() + block.position();
|
|
|
|
_expressionLength = calculator.length();
|
|
|
|
}
|
2009-09-22 16:32:49 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 10:49:33 +02:00
|
|
|
Statement *QmlExpressionUnderCursor::tryStatement(const QString &text)
|
2009-09-22 16:32:49 +02:00
|
|
|
{
|
2009-10-02 10:49:33 +02:00
|
|
|
_engine = new Engine();
|
|
|
|
_nodePool = new NodePool("", _engine);
|
|
|
|
Lexer lexer(_engine);
|
|
|
|
Parser parser(_engine);
|
|
|
|
lexer.setCode(text, /*line = */ 1);
|
2009-09-23 13:59:38 +02:00
|
|
|
|
2009-10-02 10:49:33 +02:00
|
|
|
if (parser.parseStatement())
|
|
|
|
return parser.statement();
|
|
|
|
else
|
|
|
|
return 0;
|
2009-09-22 16:32:49 +02:00
|
|
|
}
|
|
|
|
|
2009-10-02 10:49:33 +02:00
|
|
|
UiObjectMember *QmlExpressionUnderCursor::tryBinding(const QString &text)
|
2009-09-22 16:32:49 +02:00
|
|
|
{
|
2009-10-02 10:49:33 +02:00
|
|
|
_engine = new Engine();
|
|
|
|
_nodePool = new NodePool("", _engine);
|
|
|
|
Lexer lexer(_engine);
|
|
|
|
Parser parser(_engine);
|
|
|
|
lexer.setCode(text, /*line = */ 1);
|
2009-09-23 13:59:38 +02:00
|
|
|
|
2009-10-02 10:49:33 +02:00
|
|
|
if (parser.parseUiObjectMember()) {
|
|
|
|
UiObjectMember *member = parser.uiObjectMember();
|
2009-09-23 13:59:38 +02:00
|
|
|
|
2009-10-02 10:49:33 +02:00
|
|
|
if (cast<UiObjectBinding*>(member) || cast<UiArrayBinding*>(member) || cast<UiScriptBinding*>(member))
|
|
|
|
return member;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return 0;
|
2009-09-23 13:59:38 +02:00
|
|
|
}
|
|
|
|
}
|