QmlJS: Separate imported types and imported JS scopes.

Task-number: QTCREATORBUG-4981
Change-Id: I06d3e428ca4928296a3d5977aeff29fc3217c37c
Reviewed-on: http://codereview.qt.nokia.com/175
Reviewed-by: Fawzi Mohamed <fawzi.mohamed@nokia.com>
This commit is contained in:
Christian Kamm
2011-05-27 10:43:06 +02:00
parent ca1eaca136
commit a7f4e5fab5
7 changed files with 194 additions and 92 deletions

View File

@@ -1308,6 +1308,7 @@ void StringValue::accept(ValueVisitor *visitor) const
ScopeChain::ScopeChain()
: globalScope(0)
, qmlTypes(0)
, jsImports(0)
{
}
@@ -1369,7 +1370,8 @@ void ScopeChain::update()
_all += ids;
if (qmlTypes)
_all += qmlTypes;
// qmlTypes are not added on purpose
if (jsImports)
_all += jsImports;
_all += jsScopes;
}
@@ -1412,18 +1414,18 @@ ScopeChain &Context::scopeChain()
return _scopeChain;
}
const TypeEnvironment *Context::typeEnvironment(const QmlJS::Document *doc) const
const Imports *Context::imports(const QmlJS::Document *doc) const
{
if (!doc)
return 0;
return _typeEnvironments.value(doc, 0);
return _imports.value(doc).data();
}
void Context::setTypeEnvironment(const QmlJS::Document *doc, const TypeEnvironment *typeEnvironment)
void Context::setImports(const QmlJS::Document *doc, const Imports *imports)
{
if (!doc)
return;
_typeEnvironments[doc] = typeEnvironment;
_imports[doc] = QSharedPointer<const Imports>(imports);
}
const Value *Context::lookup(const QString &name, const ObjectValue **foundInScope) const
@@ -1446,7 +1448,10 @@ const Value *Context::lookup(const QString &name, const ObjectValue **foundInSco
const ObjectValue *Context::lookupType(const QmlJS::Document *doc, UiQualifiedId *qmlTypeName) const
{
const ObjectValue *objectValue = typeEnvironment(doc);
const Imports *importsObj = imports(doc);
if (!importsObj)
return 0;
const ObjectValue *objectValue = importsObj->typeScope();
if (!objectValue)
return 0;
@@ -1466,7 +1471,12 @@ const ObjectValue *Context::lookupType(const QmlJS::Document *doc, UiQualifiedId
const ObjectValue *Context::lookupType(const QmlJS::Document *doc, const QStringList &qmlTypeName) const
{
const ObjectValue *objectValue = typeEnvironment(doc);
const Imports *importsObj = imports(doc);
if (!importsObj)
return 0;
const ObjectValue *objectValue = importsObj->typeScope();
if (!objectValue)
return 0;
foreach (const QString &name, qmlTypeName) {
if (!objectValue)
@@ -3398,25 +3408,30 @@ UiImport *ImportInfo::ast() const
return _ast;
}
TypeEnvironment::Import::Import()
Import::Import()
: object(0)
{}
TypeEnvironment::TypeEnvironment(Engine *engine)
TypeScope::TypeScope(const Imports *imports, Engine *engine)
: ObjectValue(engine)
, _imports(imports)
{
}
const Value *TypeEnvironment::lookupMember(const QString &name, const Context *context,
const Value *TypeScope::lookupMember(const QString &name, const Context *context,
const ObjectValue **foundInObject, bool) const
{
QListIterator<Import> it(_imports);
QListIterator<Import> it(_imports->all());
it.toBack();
while (it.hasPrevious()) {
const Import &i = it.previous();
const ObjectValue *import = i.object;
const ImportInfo &info = i.info;
// JS import has no types
if (info.type() == ImportInfo::FileImport)
continue;
if (!info.id().isEmpty()) {
if (info.id() == name) {
if (foundInObject)
@@ -3426,15 +3441,59 @@ const Value *TypeEnvironment::lookupMember(const QString &name, const Context *c
continue;
}
if (info.type() == ImportInfo::FileImport) {
if (import->className() == name) {
if (foundInObject)
*foundInObject = this;
return import;
}
if (const Value *v = import->lookupMember(name, context, foundInObject))
return v;
}
if (foundInObject)
*foundInObject = 0;
return 0;
}
void TypeScope::processMembers(MemberProcessor *processor) const
{
QListIterator<Import> it(_imports->all());
it.toBack();
while (it.hasPrevious()) {
const Import &i = it.previous();
const ObjectValue *import = i.object;
const ImportInfo &info = i.info;
// JS import has no types
if (info.type() == ImportInfo::FileImport)
continue;
if (!info.id().isEmpty()) {
processor->processProperty(info.id(), import);
} else {
if (const Value *v = import->lookupMember(name, context, foundInObject))
return v;
import->processMembers(processor);
}
}
}
JSImportScope::JSImportScope(const Imports *imports, Engine *engine)
: ObjectValue(engine)
, _imports(imports)
{
}
const Value *JSImportScope::lookupMember(const QString &name, const Context *,
const ObjectValue **foundInObject, bool) const
{
QListIterator<Import> it(_imports->all());
it.toBack();
while (it.hasPrevious()) {
const Import &i = it.previous();
const ObjectValue *import = i.object;
const ImportInfo &info = i.info;
// JS imports are always: import "somefile.js" as Foo
if (info.type() != ImportInfo::FileImport)
continue;
if (info.id() == name) {
if (foundInObject)
*foundInObject = this;
return import;
}
}
if (foundInObject)
@@ -3442,32 +3501,31 @@ const Value *TypeEnvironment::lookupMember(const QString &name, const Context *c
return 0;
}
void TypeEnvironment::processMembers(MemberProcessor *processor) const
void JSImportScope::processMembers(MemberProcessor *processor) const
{
QListIterator<Import> it(_imports);
QListIterator<Import> it(_imports->all());
it.toBack();
while (it.hasPrevious()) {
const Import &i = it.previous();
const ObjectValue *import = i.object;
const ImportInfo &info = i.info;
if (!info.id().isEmpty()) {
if (info.type() == ImportInfo::FileImport)
processor->processProperty(info.id(), import);
} else {
if (info.type() == ImportInfo::FileImport)
processor->processProperty(import->className(), import);
else
import->processMembers(processor);
}
}
}
void TypeEnvironment::addImport(const Import &import)
Imports::Imports(Engine *engine)
: _typeScope(new TypeScope(this, engine))
, _jsImportScope(new JSImportScope(this, engine))
{}
void Imports::append(const Import &import)
{
_imports.append(import);
}
ImportInfo TypeEnvironment::importInfo(const QString &name, const Context *context) const
ImportInfo Imports::info(const QString &name, const Context *context) const
{
QString firstId = name;
int dotIdx = firstId.indexOf(QLatin1Char('.'));
@@ -3498,11 +3556,21 @@ ImportInfo TypeEnvironment::importInfo(const QString &name, const Context *conte
return ImportInfo();
}
QList<TypeEnvironment::Import> TypeEnvironment::imports() const
QList<Import> Imports::all() const
{
return _imports;
}
const TypeScope *Imports::typeScope() const
{
return _typeScope;
}
const JSImportScope *Imports::jsImportScope() const
{
return _jsImportScope;
}
#ifdef QT_DEBUG
class MemberDumper: public MemberProcessor
@@ -3541,9 +3609,9 @@ public:
}
};
void TypeEnvironment::dump() const
void Imports::dump() const
{
qDebug() << "Type environment contents, in search order:";
qDebug() << "Imports contents, in search order:";
QListIterator<Import> it(_imports);
it.toBack();
while (it.hasPrevious()) {

View File

@@ -71,8 +71,9 @@ class FunctionValue;
class Reference;
class ColorValue;
class AnchorLineValue;
class TypeEnvironment;
class AttachedTypeEnvironment;
class Imports;
class TypeScope;
class JSImportScope;
typedef QList<const Value *> ValueList;
@@ -303,7 +304,8 @@ public:
const ObjectValue *globalScope;
QSharedPointer<const QmlComponentChain> qmlComponentScope;
QList<const ObjectValue *> qmlScopeObjects;
const TypeEnvironment *qmlTypes;
const TypeScope *qmlTypes;
const JSImportScope *jsImports;
QList<const ObjectValue *> jsScopes;
// rebuilds the flat list of all scopes
@@ -326,8 +328,8 @@ public:
const ScopeChain &scopeChain() const;
ScopeChain &scopeChain();
const TypeEnvironment *typeEnvironment(const Document *doc) const;
void setTypeEnvironment(const Document *doc, const TypeEnvironment *typeEnvironment);
const Imports *imports(const Document *doc) const;
void setImports(const Document *doc, const Imports *imports);
const Value *lookup(const QString &name, const ObjectValue **foundInScope = 0) const;
const ObjectValue *lookupType(const Document *doc, AST::UiQualifiedId *qmlTypeName) const;
@@ -345,7 +347,7 @@ private:
Snapshot _snapshot;
QSharedPointer<Engine> _engine;
QHash<const ObjectValue *, Properties> _properties;
QHash<const Document *, const TypeEnvironment *> _typeEnvironments;
QHash<const Document *, QSharedPointer<const Imports> > _imports;
ScopeChain _scopeChain;
int _qmlScopeObjectIndex;
bool _qmlScopeObjectSet;
@@ -1030,32 +1032,59 @@ private:
AST::UiImport *_ast;
};
class QMLJS_EXPORT TypeEnvironment: public ObjectValue
class QMLJS_EXPORT Import {
public:
Import();
// const!
ObjectValue *object;
ImportInfo info;
// uri imports: path to library, else empty
QString libraryPath;
};
class Imports;
class QMLJS_EXPORT TypeScope: public ObjectValue
{
public:
class Import {
public:
Import();
// const!
ObjectValue *object;
ImportInfo info;
// uri imports: path to library, else empty
QString libraryPath;
};
public:
TypeEnvironment(Engine *engine);
TypeScope(const Imports *imports, Engine *engine);
virtual const Value *lookupMember(const QString &name, const Context *context,
const ObjectValue **foundInObject = 0,
bool examinePrototypes = true) const;
virtual void processMembers(MemberProcessor *processor) const;
void addImport(const Import &import);
private:
const Imports *_imports;
};
ImportInfo importInfo(const QString &name, const Context *context) const;
QList<Import> imports() const;
class QMLJS_EXPORT JSImportScope: public ObjectValue
{
public:
JSImportScope(const Imports *imports, Engine *engine);
virtual const Value *lookupMember(const QString &name, const Context *context,
const ObjectValue **foundInObject = 0,
bool examinePrototypes = true) const;
virtual void processMembers(MemberProcessor *processor) const;
private:
const Imports *_imports;
};
class QMLJS_EXPORT Imports
{
public:
Imports(Engine *engine);
void append(const Import &import);
ImportInfo info(const QString &name, const Context *context) const;
QList<Import> all() const;
const TypeScope *typeScope() const;
const JSImportScope *jsImportScope() const;
#ifdef QT_DEBUG
void dump() const;
@@ -1065,6 +1094,8 @@ private:
// holds imports in the order they appeared,
// lookup order is back to front
QList<Import> _imports;
TypeScope *_typeScope;
JSImportScope *_jsImportScope;
};
} } // namespace QmlJS::Interpreter

View File

@@ -89,7 +89,7 @@ public:
Interpreter::Context *context;
QStringList importPaths;
QHash<ImportCacheKey, TypeEnvironment::Import> importCache;
QHash<ImportCacheKey, Import> importCache;
Document::Ptr doc;
QList<DiagnosticMessage> *diagnosticMessages;
@@ -161,22 +161,22 @@ void Link::linkImports()
if (d->doc) {
// do it on d->doc first, to make sure import errors are shown
TypeEnvironment *typeEnv = new TypeEnvironment(engine());
populateImportedTypes(typeEnv, d->doc);
d->context->setTypeEnvironment(d->doc.data(), typeEnv);
Imports *imports = new Imports(engine());
populateImportedTypes(imports, d->doc);
d->context->setImports(d->doc.data(), imports);
}
foreach (Document::Ptr doc, d->snapshot) {
if (doc == d->doc)
continue;
TypeEnvironment *typeEnv = new TypeEnvironment(engine());
populateImportedTypes(typeEnv, doc);
d->context->setTypeEnvironment(doc.data(), typeEnv);
Imports *imports = new Imports(engine());
populateImportedTypes(imports, doc);
d->context->setImports(doc.data(), imports);
}
}
void Link::populateImportedTypes(TypeEnvironment *typeEnv, Document::Ptr doc)
void Link::populateImportedTypes(Imports *imports, Document::Ptr doc)
{
Q_D(Link);
@@ -184,15 +184,15 @@ void Link::populateImportedTypes(TypeEnvironment *typeEnv, Document::Ptr doc)
return;
// implicit imports: the <default> package is always available
loadImplicitDefaultImports(typeEnv);
loadImplicitDefaultImports(imports);
// implicit imports:
// qml files in the same directory are available without explicit imports
loadImplicitDirectoryImports(typeEnv, doc);
loadImplicitDirectoryImports(imports, doc);
// explicit imports, whether directories, files or libraries
foreach (const ImportInfo &info, doc->bind()->imports()) {
TypeEnvironment::Import import = d->importCache.value(ImportCacheKey(info));
Import import = d->importCache.value(ImportCacheKey(info));
if (!import.object) {
switch (info.type()) {
@@ -210,7 +210,7 @@ void Link::populateImportedTypes(TypeEnvironment *typeEnv, Document::Ptr doc)
d->importCache.insert(ImportCacheKey(info), import);
}
if (import.object)
typeEnv->addImport(import);
imports->append(import);
}
}
@@ -221,12 +221,14 @@ void Link::populateImportedTypes(TypeEnvironment *typeEnv, Document::Ptr doc)
import "content" 4.6 as Xxx
import "http://www.ovi.com/" as Ovi
import "file.js" as Foo
*/
TypeEnvironment::Import Link::importFileOrDirectory(Document::Ptr doc, const ImportInfo &importInfo)
Import Link::importFileOrDirectory(Document::Ptr doc, const ImportInfo &importInfo)
{
Q_D(Link);
TypeEnvironment::Import import;
Import import;
import.info = importInfo;
import.object = 0;
@@ -259,11 +261,11 @@ TypeEnvironment::Import Link::importFileOrDirectory(Document::Ptr doc, const Imp
import Qt 4.6 as Xxx
(import com.nokia.qt is the same as the ones above)
*/
TypeEnvironment::Import Link::importNonFile(Document::Ptr doc, const ImportInfo &importInfo)
Import Link::importNonFile(Document::Ptr doc, const ImportInfo &importInfo)
{
Q_D(Link);
TypeEnvironment::Import import;
Import import;
import.info = importInfo;
import.object = new ObjectValue(engine());
@@ -305,7 +307,7 @@ TypeEnvironment::Import Link::importNonFile(Document::Ptr doc, const ImportInfo
bool Link::importLibrary(Document::Ptr doc,
const QString &libraryPath,
TypeEnvironment::Import *import,
Import *import,
const QString &importPath)
{
Q_D(Link);
@@ -435,32 +437,32 @@ void Link::loadQmldirComponents(Interpreter::ObjectValue *import, ComponentVersi
}
}
void Link::loadImplicitDirectoryImports(TypeEnvironment *typeEnv, Document::Ptr doc)
void Link::loadImplicitDirectoryImports(Imports *imports, Document::Ptr doc)
{
Q_D(Link);
ImportInfo implcitDirectoryImportInfo(
ImportInfo::ImplicitDirectoryImport, doc->path());
TypeEnvironment::Import directoryImport = d->importCache.value(ImportCacheKey(implcitDirectoryImportInfo));
Import directoryImport = d->importCache.value(ImportCacheKey(implcitDirectoryImportInfo));
if (!directoryImport.object) {
directoryImport = importFileOrDirectory(doc, implcitDirectoryImportInfo);
if (directoryImport.object)
d->importCache.insert(ImportCacheKey(implcitDirectoryImportInfo), directoryImport);
}
if (directoryImport.object) {
typeEnv->addImport(directoryImport);
imports->append(directoryImport);
}
}
void Link::loadImplicitDefaultImports(TypeEnvironment *typeEnv)
void Link::loadImplicitDefaultImports(Imports *imports)
{
Q_D(Link);
const QString defaultPackage = CppQmlTypes::defaultPackage;
if (engine()->cppQmlTypes().hasPackage(defaultPackage)) {
ImportInfo info(ImportInfo::LibraryImport, defaultPackage);
TypeEnvironment::Import import = d->importCache.value(ImportCacheKey(info));
Import import = d->importCache.value(ImportCacheKey(info));
if (!import.object) {
import.info = info;
import.object = new ObjectValue(engine());
@@ -470,6 +472,6 @@ void Link::loadImplicitDefaultImports(TypeEnvironment *typeEnv)
}
d->importCache.insert(ImportCacheKey(info), import);
}
typeEnv->addImport(import);
imports->append(import);
}
}

View File

@@ -73,25 +73,25 @@ private:
void linkImports();
void populateImportedTypes(Interpreter::TypeEnvironment *typeEnv, Document::Ptr doc);
Interpreter::TypeEnvironment::Import importFileOrDirectory(
void populateImportedTypes(Interpreter::Imports *imports, Document::Ptr doc);
Interpreter::Import importFileOrDirectory(
Document::Ptr doc,
const Interpreter::ImportInfo &importInfo);
Interpreter::TypeEnvironment::Import importNonFile(
Interpreter::Import importNonFile(
Document::Ptr doc,
const Interpreter::ImportInfo &importInfo);
void importObject(Bind *bind, const QString &name, Interpreter::ObjectValue *object, NameId *targetNamespace);
bool importLibrary(Document::Ptr doc,
const QString &libraryPath,
Interpreter::TypeEnvironment::Import *import,
Interpreter::Import *import,
const QString &importPath = QString());
void loadQmldirComponents(Interpreter::ObjectValue *import,
LanguageUtils::ComponentVersion version,
const LibraryInfo &libraryInfo,
const QString &libraryPath);
void loadImplicitDirectoryImports(Interpreter::TypeEnvironment *typeEnv, Document::Ptr doc);
void loadImplicitDefaultImports(Interpreter::TypeEnvironment *typeEnv);
void loadImplicitDirectoryImports(Interpreter::Imports *imports, Document::Ptr doc);
void loadImplicitDefaultImports(Interpreter::Imports *imports);
void error(const Document::Ptr &doc, const AST::SourceLocation &loc, const QString &message);
void warning(const Document::Ptr &doc, const AST::SourceLocation &loc, const QString &message);

View File

@@ -127,8 +127,9 @@ void ScopeBuilder::initializeRootScope()
componentScopes.insert(_doc.data(), chain);
makeComponentChain(_doc, snapshot, chain, &componentScopes);
if (const TypeEnvironment *typeEnvironment = _context->typeEnvironment(_doc.data())) {
scopeChain.qmlTypes = typeEnvironment;
if (const Imports *imports = _context->imports(_doc.data())) {
scopeChain.qmlTypes = imports->typeScope();
scopeChain.jsImports = imports->jsImportScope();
}
} else {
// add scope chains for all components that import this file