QmlJS: Split Context and ScopeChain.

Context is created by Link and has information about imports
for all Documents in a Snapshot.

ScopeChain represents how lookup is done at a specific place in
a Document.

Change-Id: I874102d57bbaf1a497fa3f27633bed6ee75dcf10
Reviewed-on: http://codereview.qt.nokia.com/1694
Reviewed-by: Fawzi Mohamed <fawzi.mohamed@nokia.com>
This commit is contained in:
Christian Kamm
2011-07-12 14:55:27 +02:00
parent ed1321a4f9
commit f87dc61986
22 changed files with 671 additions and 416 deletions

View File

@@ -48,6 +48,7 @@
#include <qmljs/parser/qmljsast_p.h>
#include <qmljs/qmljsinterpreter.h>
#include <qmljs/qmljscontext.h>
#include <qmljs/qmljsscopechain.h>
#include <qmljs/qmljslookupcontext.h>
#include <qmljs/qmljsscanner.h>
#include <qmljs/qmljsbind.h>
@@ -86,15 +87,15 @@ class EnumerateProperties: private Interpreter::MemberProcessor
bool _globalCompletion;
bool _enumerateGeneratedSlots;
bool _enumerateSlots;
const Interpreter::Context *_context;
const Interpreter::ScopeChain *_scopeChain;
const Interpreter::ObjectValue *_currentObject;
public:
EnumerateProperties(const Interpreter::Context *context)
EnumerateProperties(const Interpreter::ScopeChain *scopeChain)
: _globalCompletion(false),
_enumerateGeneratedSlots(false),
_enumerateSlots(true),
_context(context),
_scopeChain(scopeChain),
_currentObject(0)
{
}
@@ -131,7 +132,7 @@ public:
_properties.clear();
_currentObject = 0;
foreach (const Interpreter::ObjectValue *scope, _context->scopeChain().all())
foreach (const Interpreter::ObjectValue *scope, _scopeChain->all())
enumerateProperties(scope);
return _properties;
@@ -192,7 +193,7 @@ private:
return;
_processed.insert(object);
enumerateProperties(object->prototype(_context));
enumerateProperties(object->prototype(_scopeChain->context()));
object->processMembers(this);
}
@@ -422,6 +423,7 @@ IAssistProposal *QmlJSCompletionAssistProcessor::perform(const IAssistInterface
const QList<AST::Node *> path = semanticInfo.rangePath(m_interface->position());
LookupContext::Ptr lookupContext = semanticInfo.lookupContext(path);
const Interpreter::Context *context = lookupContext->context();
const Interpreter::ScopeChain &scopeChain = lookupContext->scopeChain();
// Search for the operator that triggered the completion.
QChar completionOperator;
@@ -521,7 +523,7 @@ IAssistProposal *QmlJSCompletionAssistProcessor::perform(const IAssistInterface
doJsKeywordCompletion = false;
doQmlTypeCompletion = true;
EnumerateProperties enumerateProperties(context);
EnumerateProperties enumerateProperties(&scopeChain);
enumerateProperties.setGlobalCompletion(true);
enumerateProperties.setEnumerateGeneratedSlots(true);
enumerateProperties.setEnumerateSlots(false);
@@ -539,8 +541,8 @@ IAssistProposal *QmlJSCompletionAssistProcessor::perform(const IAssistInterface
contextFinder.isAfterOnInLhsOfBinding());
if (ScopeBuilder::isPropertyChangesObject(context, qmlScopeType)
&& context->scopeChain().qmlScopeObjects.size() == 2) {
addCompletions(enumerateProperties(context->scopeChain().qmlScopeObjects.first()),
&& scopeChain.qmlScopeObjects().size() == 2) {
addCompletions(enumerateProperties(scopeChain.qmlScopeObjects().first()),
m_interface->symbolIcon(),
SymbolOrder);
}
@@ -564,15 +566,15 @@ IAssistProposal *QmlJSCompletionAssistProcessor::perform(const IAssistInterface
doQmlTypeCompletion = true;
if (doQmlTypeCompletion) {
if (const Interpreter::ObjectValue *qmlTypes = context->scopeChain().qmlTypes) {
EnumerateProperties enumerateProperties(context);
if (const Interpreter::ObjectValue *qmlTypes = scopeChain.qmlTypes()) {
EnumerateProperties enumerateProperties(&scopeChain);
addCompletions(enumerateProperties(qmlTypes), m_interface->symbolIcon(), TypeOrder);
}
}
if (doGlobalCompletion) {
// It's a global completion.
EnumerateProperties enumerateProperties(context);
EnumerateProperties enumerateProperties(&scopeChain);
enumerateProperties.setGlobalCompletion(true);
addCompletions(enumerateProperties(), m_interface->symbolIcon(), SymbolOrder);
}
@@ -619,7 +621,7 @@ IAssistProposal *QmlJSCompletionAssistProcessor::perform(const IAssistInterface
//qDebug() << "type:" << interp->typeId(value);
if (value && completionOperator == QLatin1Char('.')) { // member completion
EnumerateProperties enumerateProperties(context);
EnumerateProperties enumerateProperties(&scopeChain);
if (contextFinder.isInLhsOfBinding() && qmlScopeType) {
enumerateProperties.setEnumerateGeneratedSlots(true);
addCompletionsPropertyLhs(enumerateProperties(value),

View File

@@ -1260,7 +1260,7 @@ TextEditor::BaseTextEditorWidget::Link QmlJSTextEditorWidget::findLinkAt(const Q
}
LookupContext::Ptr lookupContext = semanticInfo.lookupContext(semanticInfo.rangePath(cursorPosition));
Evaluate evaluator(lookupContext->context());
Evaluate evaluator(&lookupContext->scopeChain());
const Interpreter::Value *value = evaluator.reference(node);
QString fileName;

View File

@@ -80,10 +80,9 @@ public:
FindUsages(Document::Ptr doc, Context *context)
: _doc(doc)
, _context(context)
, _builder(context, doc)
, _scopeChain(doc, context)
, _builder(&_scopeChain)
{
_builder.initializeRootScope();
}
Result operator()(const QString &name, const ObjectValue *scope)
@@ -106,7 +105,7 @@ protected:
{
if (node->name
&& node->name->asString() == _name
&& _context->scopeChain().qmlScopeObjects.contains(_scope)) {
&& _scopeChain.qmlScopeObjects().contains(_scope)) {
_usages.append(node->identifierToken);
}
if (AST::cast<Block *>(node->statement)) {
@@ -176,7 +175,7 @@ protected:
return false;
const ObjectValue *scope;
_context->lookup(_name, &scope);
_scopeChain.lookup(_name, &scope);
if (!scope)
return false;
if (check(scope)) {
@@ -188,14 +187,14 @@ protected:
// so it might still be a use - we just found a different value in a different scope first
// if scope is one of these, our match wasn't inside the instantiating components list
const ScopeChain &chain = _context->scopeChain();
if (chain.jsScopes.contains(scope)
|| chain.qmlScopeObjects.contains(scope)
|| chain.qmlTypes == scope
|| chain.globalScope == scope)
const ScopeChain &chain = _scopeChain;
if (chain.jsScopes().contains(scope)
|| chain.qmlScopeObjects().contains(scope)
|| chain.qmlTypes() == scope
|| chain.globalScope() == scope)
return false;
if (contains(chain.qmlComponentScope.data()))
if (contains(chain.qmlComponentChain().data()))
_usages.append(node->identifierToken);
return false;
@@ -206,7 +205,7 @@ protected:
if (!node->name || node->name->asString() != _name)
return true;
Evaluate evaluate(_context);
Evaluate evaluate(&_scopeChain);
const Value *lhsValue = evaluate(node->base);
if (!lhsValue)
return true;
@@ -245,19 +244,19 @@ protected:
}
private:
bool contains(const ScopeChain::QmlComponentChain *chain)
bool contains(const QmlComponentChain *chain)
{
if (!chain || !chain->document)
if (!chain || !chain->document())
return false;
if (chain->document->bind()->idEnvironment()->lookupMember(_name, _context))
return chain->document->bind()->idEnvironment() == _scope;
const ObjectValue *root = chain->document->bind()->rootObjectValue();
if (root->lookupMember(_name, _context)) {
if (chain->document()->bind()->idEnvironment()->lookupMember(_name, _scopeChain.context()))
return chain->document()->bind()->idEnvironment() == _scope;
const ObjectValue *root = chain->document()->bind()->rootObjectValue();
if (root->lookupMember(_name, _scopeChain.context())) {
return check(root);
}
foreach (const ScopeChain::QmlComponentChain *parent, chain->instantiatingComponents) {
foreach (const QmlComponentChain *parent, chain->instantiatingComponents()) {
if (contains(parent))
return true;
}
@@ -269,13 +268,13 @@ private:
if (!s)
return false;
const ObjectValue *definingObject;
s->lookupMember(_name, _context, &definingObject);
s->lookupMember(_name, _scopeChain.context(), &definingObject);
return definingObject == _scope;
}
bool checkQmlScope()
{
foreach (const ObjectValue *s, _context->scopeChain().qmlScopeObjects) {
foreach (const ObjectValue *s, _scopeChain.qmlScopeObjects()) {
if (check(s))
return true;
}
@@ -285,14 +284,14 @@ private:
bool checkLookup()
{
const ObjectValue *scope = 0;
_context->lookup(_name, &scope);
_scopeChain.lookup(_name, &scope);
return check(scope);
}
Result _usages;
Document::Ptr _doc;
Context *_context;
ScopeChain _scopeChain;
ScopeBuilder _builder;
QString _name;
@@ -307,9 +306,9 @@ public:
FindTypeUsages(Document::Ptr doc, Context *context)
: _doc(doc)
, _context(context)
, _builder(context, doc)
, _scopeChain(doc, context)
, _builder(&_scopeChain)
{
_builder.initializeRootScope();
}
Result operator()(const QString &name, const ObjectValue *typeValue)
@@ -380,7 +379,7 @@ protected:
return false;
const ObjectValue *scope;
const Value *objV = _context->lookup(_name, &scope);
const Value *objV = _scopeChain.lookup(_name, &scope);
if (objV == _typeValue)
_usages.append(node->identifierToken);
return false;
@@ -390,7 +389,7 @@ protected:
{
if (!node->name || node->name->asString() != _name)
return true;
Evaluate evaluate(_context);
Evaluate evaluate(&_scopeChain);
const Value *lhsValue = evaluate(node->base);
if (!lhsValue)
return true;
@@ -452,6 +451,7 @@ private:
Document::Ptr _doc;
Context *_context;
ScopeChain _scopeChain;
ScopeBuilder _builder;
QString _name;
@@ -466,8 +466,8 @@ public:
TypeKind
};
FindTargetExpression(Document::Ptr doc, Context *context)
: _doc(doc), _context(context)
FindTargetExpression(Document::Ptr doc, const ScopeChain *scopeChain)
: _doc(doc), _scopeChain(scopeChain)
{
}
@@ -488,7 +488,7 @@ public:
const ObjectValue *scope()
{
if (!_scope)
_context->lookup(_name, &_scope);
_scopeChain->lookup(_name, &_scope);
return _scope;
}
@@ -524,7 +524,7 @@ protected:
_name = node->name->asString();
if ((!_name.isEmpty()) && _name.at(0).isUpper()) {
// a possible type
_targetValue = _context->lookup(_name, &_scope);
_targetValue = _scopeChain->lookup(_name, &_scope);
if (value_cast<const ObjectValue*>(_targetValue))
_typeKind = TypeKind;
}
@@ -539,14 +539,14 @@ protected:
_name = node->name->asString();
if ((!_name.isEmpty()) && _name.at(0).isUpper()) {
// a possible type
Evaluate evaluate(_context);
Evaluate evaluate(_scopeChain);
const Value *lhsValue = evaluate(node->base);
if (!lhsValue)
return true;
const ObjectValue *lhsObj = lhsValue->asObjectValue();
if (lhsObj) {
_scope = lhsObj;
_targetValue = lhsObj->lookupMember(_name, _context);
_targetValue = lhsObj->lookupMember(_name, _scopeChain->context());
_typeKind = TypeKind;
}
}
@@ -593,7 +593,7 @@ protected:
if (containsOffset(node->typeToken)){
if (node->memberType){
_name = node->memberType->asString();
_targetValue = _context->lookupType(_doc.data(), QStringList(_name));
_targetValue = _scopeChain->context()->lookupType(_doc.data(), QStringList(_name));
_scope = 0;
_typeKind = TypeKind;
}
@@ -654,7 +654,7 @@ private:
{
for (UiQualifiedId *att = id; att; att = att->next) {
if (att->name && containsOffset(att->identifierToken)) {
_targetValue = _context->lookupType(_doc.data(), id, att->next);
_targetValue = _scopeChain->context()->lookupType(_doc.data(), id, att->next);
_scope = 0;
_name = att->name->asString();
_typeKind = TypeKind;
@@ -666,7 +666,7 @@ private:
void setScope(Node *node)
{
Evaluate evaluate(_context);
Evaluate evaluate(_scopeChain);
const Value *v = evaluate(node);
if (v)
_scope = v->asObjectValue();
@@ -677,7 +677,7 @@ private:
const Value *_targetValue;
Node *_objectNode;
Document::Ptr _doc;
Context *_context;
const ScopeChain *_scopeChain;
quint32 _offset;
Kind _typeKind;
};
@@ -823,12 +823,12 @@ static void find_helper(QFutureInterface<FindReferences::Usage> &future,
Link link(snapshot, modelManager->importPaths(), modelManager->builtins(doc));
Context context = link();
ScopeBuilder builder(&context, doc);
builder.initializeRootScope();
ScopeChain scopeChain(doc, &context);
ScopeBuilder builder(&scopeChain);
ScopeAstPath astPath(doc);
builder.push(astPath(offset));
FindTargetExpression findTarget(doc, &context);
FindTargetExpression findTarget(doc, &scopeChain);
findTarget(offset);
const QString &name = findTarget.name();
if (name.isEmpty())

View File

@@ -186,7 +186,7 @@ bool HoverHandler::matchColorItem(const LookupContext::Ptr &lookupContext,
} else if (const AST::UiPublicMember *publicMember =
AST::cast<const AST::UiPublicMember *>(member)) {
if (publicMember->name && posIsInSource(pos, publicMember->statement)) {
value = lookupContext->context()->lookup(publicMember->name->asString());
value = lookupContext->scopeChain().lookup(publicMember->name->asString());
if (const Interpreter::Reference *ref = value->asReference())
value = lookupContext->context()->lookupReference(ref);
color = textAt(qmlDocument,
@@ -306,7 +306,7 @@ static const Interpreter::ObjectValue *isMember(const LookupContext::Ptr &lookup
if (!identExp->name)
return 0;
*name = identExp->name->asString();
lookupContext->context()->lookup(*name, &owningObject);
lookupContext->scopeChain().lookup(*name, &owningObject);
} else if (AST::FieldMemberExpression *fme = AST::cast<AST::FieldMemberExpression *>(node)) {
if (!fme->base || !fme->name)
return 0;
@@ -321,7 +321,7 @@ static const Interpreter::ObjectValue *isMember(const LookupContext::Ptr &lookup
if (!qid->name)
return 0;
*name = qid->name->asString();
const Interpreter::Value *value = lookupContext->context()->lookup(*name, &owningObject);
const Interpreter::Value *value = lookupContext->scopeChain().lookup(*name, &owningObject);
for (AST::UiQualifiedId *it = qid->next; it; it = it->next) {
if (!value)
return 0;

View File

@@ -78,7 +78,7 @@ static inline const Interpreter::ObjectValue * getPropertyChangesTarget(Node *no
if (scriptBinding->qualifiedId
&& scriptBinding->qualifiedId->name->asString() == QLatin1String("target")
&& ! scriptBinding->qualifiedId->next) {
Evaluate evaluator(lookupContext->context());
Evaluate evaluator(&lookupContext->scopeChain());
const Interpreter::Value *targetValue = evaluator(scriptBinding->statement);
if (const Interpreter::ObjectValue *targetObject = Interpreter::value_cast<const Interpreter::ObjectValue *>(targetValue)) {
return targetObject;