Commit e1b44e87 authored by Fawzi Mohamed's avatar Fawzi Mohamed

qmljs: new import/dep tracking

Change-Id: I9f4de2a06aad3afb80372a4b80e56db658683575
Reviewed-by: default avatarThomas Hartmann <Thomas.Hartmann@digia.com>
parent 5bf3ed7c
......@@ -39,7 +39,9 @@ HEADERS += \
$$PWD/qmljssimplereader.h \
$$PWD/persistenttrie.h \
$$PWD/qmljsqrcparser.h \
$$PWD/qmljsconstants.h
$$PWD/qmljsconstants.h \
$$PWD/qmljsimportdependencies.h \
$$PWD/viewercontext.h
SOURCES += \
$$PWD/qmljsbind.cpp \
......@@ -70,7 +72,10 @@ SOURCES += \
$$PWD/consoleitem.cpp \
$$PWD/qmljssimplereader.cpp \
$$PWD/persistenttrie.cpp \
$$PWD/qmljsqrcparser.cpp
$$PWD/qmljsqrcparser.cpp \
$$PWD/qmljsimportdependencies.cpp \
$$PWD/qmljsviewercontext.cpp
RESOURCES += \
$$PWD/qmljs.qrc
......
......@@ -35,6 +35,7 @@ QtcLibrary {
"qmljsevaluate.cpp", "qmljsevaluate.h",
"qmljsicons.cpp", "qmljsicons.h",
"qmljsicontextpane.h",
"qmljsimportdependencies.cpp", "qmljsimportdependencies.h",
"qmljsindenter.cpp", "qmljsindenter.h",
"qmljsinterpreter.cpp", "qmljsinterpreter.h",
"qmljslineinfo.cpp", "qmljslineinfo.h",
......@@ -52,7 +53,8 @@ QtcLibrary {
"qmljsstaticanalysismessage.cpp", "qmljsstaticanalysismessage.h",
"qmljstypedescriptionreader.cpp", "qmljstypedescriptionreader.h",
"qmljsutils.cpp", "qmljsutils.h",
"qmljsvalueowner.cpp", "qmljsvalueowner.h"
"qmljsvalueowner.cpp", "qmljsvalueowner.h",
"qmljsviewercontext.cpp", "qmljsviewercontext.h"
]
}
......
......@@ -35,14 +35,22 @@ namespace QmlJS {
namespace ImportType {
enum Enum {
Invalid,
ImplicitDirectory,
Library,
File,
Directory,
QrcFile,
ImplicitDirectory,
File,
UnknownFile, // refers a file/directory that wasn't found (or to an url)
QrcDirectory,
ImplicitQrcDirectory,
UnknownFile // refers a file/directory that wasn't found
QrcFile
};
}
namespace ImportKind {
enum Enum {
Invalid,
Library,
Path,
QrcPath,
};
}
......
......@@ -54,17 +54,20 @@ using namespace QmlJS::AST;
QmlJSTextEditorWidget::semanticInfo()::context.
*/
ContextPtr Context::create(const QmlJS::Snapshot &snapshot, ValueOwner *valueOwner, const ImportsPerDocument &imports)
ContextPtr Context::create(const QmlJS::Snapshot &snapshot, ValueOwner *valueOwner,
const ImportsPerDocument &imports, const ViewerContext &vContext)
{
QSharedPointer<Context> result(new Context(snapshot, valueOwner, imports));
QSharedPointer<Context> result(new Context(snapshot, valueOwner, imports, vContext));
result->_ptr = result;
return result;
}
Context::Context(const QmlJS::Snapshot &snapshot, ValueOwner *valueOwner, const ImportsPerDocument &imports)
Context::Context(const QmlJS::Snapshot &snapshot, ValueOwner *valueOwner,
const ImportsPerDocument &imports, const ViewerContext &vContext)
: _snapshot(snapshot),
_valueOwner(valueOwner),
_imports(imports)
_imports(imports),
_vContext(vContext)
{
}
......
......@@ -32,6 +32,7 @@
#include "qmljs_global.h"
#include "qmljsvalueowner.h"
#include "qmljsviewercontext.h"
#include <QSharedPointer>
......@@ -50,7 +51,8 @@ public:
typedef QHash<const Document *, QSharedPointer<const Imports> > ImportsPerDocument;
// Context takes ownership of valueOwner
static ContextPtr create(const Snapshot &snapshot, ValueOwner *valueOwner, const ImportsPerDocument &imports);
static ContextPtr create(const Snapshot &snapshot, ValueOwner *valueOwner,
const ImportsPerDocument &imports, const ViewerContext &vContext);
~Context();
ContextPtr ptr() const;
......@@ -69,11 +71,13 @@ public:
private:
// Context takes ownership of valueOwner
Context(const Snapshot &snapshot, ValueOwner *valueOwner, const ImportsPerDocument &imports);
Context(const Snapshot &snapshot, ValueOwner *valueOwner, const ImportsPerDocument &imports,
const ViewerContext &vContext);
Snapshot _snapshot;
QSharedPointer<ValueOwner> _valueOwner;
ImportsPerDocument _imports;
ViewerContext _vContext;
QWeakPointer<const Context> _ptr;
};
......
......@@ -30,6 +30,7 @@
#include "qmljsdocument.h"
#include "qmljsbind.h"
#include "qmljsconstants.h"
#include "qmljsimportdependencies.h"
#include <qmljs/parser/qmljslexer_p.h>
#include <qmljs/parser/qmljsparser_p.h>
......@@ -396,6 +397,14 @@ Snapshot::~Snapshot()
{
}
Snapshot::Snapshot(const Snapshot &o)
: _documents(o._documents),
_documentsByPath(o._documentsByPath),
_libraries(o._libraries),
_dependencies(o._dependencies)
{
}
void Snapshot::insert(const Document::Ptr &document, bool allowInvalid)
{
if (document && (allowInvalid || document->qmlProgram() || document->jsProgram())) {
......@@ -427,6 +436,16 @@ void Snapshot::remove(const QString &fileName)
}
}
const QmlJS::ImportDependencies *Snapshot::importDependencies() const
{
return &_dependencies;
}
QmlJS::ImportDependencies *Snapshot::importDependencies()
{
return &_dependencies;
}
Document::MutablePtr Snapshot::documentFromSource(
const QString &code, const QString &fileName,
Language::Enum language) const
......
......@@ -39,11 +39,13 @@
#include "parser/qmljsengine_p.h"
#include "qmljs_global.h"
#include "qmljsconstants.h"
#include "qmljsimportdependencies.h"
namespace QmlJS {
class Bind;
class Snapshot;
class ImportDependencies;
class QMLJS_EXPORT Document
{
......@@ -204,9 +206,11 @@ class QMLJS_EXPORT Snapshot
QHash<QString, Document::Ptr> _documents;
QHash<QString, QList<Document::Ptr> > _documentsByPath;
QHash<QString, LibraryInfo> _libraries;
ImportDependencies _dependencies;
public:
Snapshot();
Snapshot(const Snapshot &o);
~Snapshot();
typedef _Base::iterator iterator;
......@@ -219,6 +223,9 @@ public:
void insertLibraryInfo(const QString &path, const LibraryInfo &info);
void remove(const QString &fileName);
const ImportDependencies *importDependencies() const;
ImportDependencies *importDependencies();
Document::Ptr document(const QString &fileName) const;
QList<Document::Ptr> documentsInDirectory(const QString &path) const;
LibraryInfo libraryInfo(const QString &path) const;
......
This diff is collapsed.
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef QMLJSIMPORTCACHE_H
#define QMLJSIMPORTCACHE_H
#include "qmljsviewercontext.h"
#include <languageutils/componentversion.h>
#include <utils/qtcoverride.h>
#include <utils/function.h>
#include <QObject>
#include <QString>
#include <QStringList>
#include <QList>
#include <QMap>
#include <QSet>
#include <QSharedPointer>
QT_BEGIN_NAMESPACE
class QCryptographicHash;
QT_END_NAMESPACE
namespace QmlJS {
class ImportInfo;
namespace Internal {
class ImportDependenciesPrivate;
}
class ImportDependencies;
// match strenght wrt to the selectors of a ViewerContext
// this is valid only within a ViewerContext
class QMLJS_EXPORT ImportMatchStrength
{
public:
explicit ImportMatchStrength() {}
ImportMatchStrength(QList<int> match);
int compareMatch(const ImportMatchStrength &o) const;
bool hasNoMatch();
bool hasMatch();
private:
friend bool operator ==(const ImportMatchStrength &m1, const ImportMatchStrength &m2);
QList<int> m_match;
};
bool operator ==(const ImportMatchStrength &m1, const ImportMatchStrength &m2);
bool operator !=(const ImportMatchStrength &m1, const ImportMatchStrength &m2);
bool operator <(const ImportMatchStrength &m1, const ImportMatchStrength &m2);
/*!
* \brief The ImportKey class represent an import (or export), and can be used as hash key
*
* This represent only what is to be imported, *not* how (i.e. no as clause)
*/
class QMLJS_EXPORT ImportKey
{
public:
enum DirCompareInfo {
SameDir,
FirstInSecond,
SecondInFirst,
Different,
Incompatible
};
explicit ImportKey();
explicit ImportKey(const ImportInfo &info);
ImportType::Enum type;
QStringList splitPath;
int majorVersion;
int minorVersion;
QString path() const;
void addToHash(QCryptographicHash &hash) const;
ImportKey flatKey() const;
// wrap QList in a special type?
ImportMatchStrength matchImport(const ImportKey &o, const ViewerContext &vContext) const;
int compare(const ImportKey &other) const;
bool isDirectoryLike() const;
DirCompareInfo compareDir(const ImportKey &other) const;
};
uint qHash(const ImportKey &info);
bool operator ==(const ImportKey &i1, const ImportKey &i2);
bool operator !=(const ImportKey &i1, const ImportKey &i2);
bool operator <(const ImportKey &i1, const ImportKey &i2);
class QMLJS_EXPORT Export
{
public:
Export();
Export(ImportKey exportName, QString pathRequired, bool intrinsic = false);
ImportKey exportName;
QString pathRequired;
bool intrinsic;
bool visibleInVContext(const ViewerContext &vContext) const;
};
bool operator ==(const Export &i1, const Export &i2);
bool operator !=(const Export &i1, const Export &i2);
class QMLJS_EXPORT CoreImport
{
public:
CoreImport();
CoreImport(const QString &importId, QList<Export> possibleExports = QList<Export>(),
Language::Enum language = Language::Qml, QByteArray fingerprint = QByteArray());
QString importId;
QList<Export> possibleExports;
Language::Enum language;
QByteArray fingerprint;
bool valid();
};
class QMLJS_EXPORT DependencyInfo
{
public:
typedef QSharedPointer<const DependencyInfo> ConstPtr;
typedef QSharedPointer<DependencyInfo> Ptr;
QByteArray calculateFingerprint(const ImportDependencies &deps);
ImportKey rootImport;
QSet<QString> allCoreImports;
QSet<ImportKey> allImports;
QByteArray fingerprint;
};
class QMLJS_EXPORT MatchedImport
{
public:
MatchedImport();
MatchedImport(ImportMatchStrength matchStrength, ImportKey importKey, QString coreImportId);
ImportMatchStrength matchStrength;
ImportKey importKey;
QString coreImportId;
int compare(const MatchedImport &o) const;
};
bool operator ==(const MatchedImport &m1, const MatchedImport &m2);
bool operator !=(const MatchedImport &m1, const MatchedImport &m2);
bool operator <(const MatchedImport &m1, const MatchedImport &m2);
class QMLJS_EXPORT ImportDependencies
{
public:
typedef QMap<ImportKey, QList<MatchedImport> > ImportElements;
explicit ImportDependencies();
~ImportDependencies();
void filter(const ViewerContext &vContext);
CoreImport coreImport(const QString &importId) const;
void iterateOnCandidateImports(const ImportKey &key, const ViewerContext &vContext,
Utils::function<bool(const ImportMatchStrength &,
const Export &,
const CoreImport &)> const &iterF) const;
ImportElements candidateImports(const ImportKey &key, const ViewerContext &vContext) const;
QList<DependencyInfo::ConstPtr> createDependencyInfos(const ImportKey &mainDoc,
const ViewerContext &vContext) const;
void addCoreImport(const CoreImport &import);
void removeCoreImport(const QString &importId);
void addExport(const QString &importId, const ImportKey &importKey,
const QString &requiredPath);
void removeExport(const QString &importId, const ImportKey &importKey,
const QString &requiredPath);
void iterateOnCoreImports(const ViewerContext &vContext,
Utils::function<bool(const CoreImport &)> const &iterF) const;
void iterateOnLibraryImports(const ViewerContext &vContext,
Utils::function<bool(const ImportMatchStrength &,
const Export &,
const CoreImport &)> const &iterF) const;
void iterateOnSubImports(const ImportKey &baseKey, const ViewerContext &vContext,
Utils::function<bool(const ImportMatchStrength &,
const Export &,
const CoreImport &)> const &iterF) const;
QSet<ImportKey> libraryImports(const ViewerContext &viewContext) const;
QSet<ImportKey> subdirImports(const ImportKey &baseKey, const ViewerContext &viewContext) const;
private:
QMap<ImportKey, QStringList> m_importCache;
QMap<QString, CoreImport> m_coreImports;
};
} // namespace QmlJS
#endif // QMLJSIMPORTCACHE_H
......@@ -33,6 +33,7 @@
#include <qmljs/qmljsdocument.h>
#include <qmljs/qmljs_global.h>
#include <qmljs/qmljsconstants.h>
#include <qmljs/qmljsimportdependencies.h>
#include <QFileInfoList>
#include <QList>
......@@ -912,6 +913,7 @@ public:
// const!
ObjectValue *object;
ImportInfo info;
DependencyInfo::ConstPtr deps;
// uri imports: path to library, else empty
QString libraryPath;
// whether the import succeeded
......
......@@ -34,7 +34,8 @@
#include "qmljsbind.h"
#include "qmljsutils.h"
#include "qmljsmodelmanagerinterface.h"
#include <qmljs/qmljsqrcparser.h>
#include "qmljsqrcparser.h"
#include "qmljsconstants.h"
#include <QDir>
#include <QDebug>
......@@ -83,6 +84,7 @@ public:
ValueOwner *valueOwner;
QStringList importPaths;
LibraryInfo builtins;
ViewerContext vContext;
QHash<ImportCacheKey, Import> importCache;
......@@ -131,13 +133,14 @@ public:
\l{QmlJSEditor::SemanticInfo} of a \l{QmlJSEditor::QmlJSTextEditorWidget}.
*/
Link::Link(const Snapshot &snapshot, const QStringList &importPaths, const LibraryInfo &builtins)
Link::Link(const Snapshot &snapshot, const ViewerContext &vContext, const LibraryInfo &builtins)
: d(new LinkPrivate)
{
d->valueOwner = new ValueOwner;
d->snapshot = snapshot;
d->importPaths = importPaths;
d->importPaths = vContext.paths;
d->builtins = builtins;
d->vContext = vContext;
d->diagnosticMessages = 0;
d->allDiagnosticMessages = 0;
......@@ -173,14 +176,14 @@ Link::Link(const Snapshot &snapshot, const QStringList &importPaths, const Libra
ContextPtr Link::operator()(QHash<QString, QList<DiagnosticMessage> > *messages)
{
d->allDiagnosticMessages = messages;
return Context::create(d->snapshot, d->valueOwner, d->linkImports());
return Context::create(d->snapshot, d->valueOwner, d->linkImports(), d->vContext);
}
ContextPtr Link::operator()(const Document::Ptr &doc, QList<DiagnosticMessage> *messages)
{
d->document = doc;
d->diagnosticMessages = messages;
return Context::create(d->snapshot, d->valueOwner, d->linkImports());
return Context::create(d->snapshot, d->valueOwner, d->linkImports(), d->vContext);
}
Link::~Link()
......
......@@ -48,7 +48,7 @@ class QMLJS_EXPORT Link
Q_DECLARE_TR_FUNCTIONS(QmlJS::Link)
public:
Link(const Snapshot &snapshot, const QStringList &importPaths, const LibraryInfo &builtins);
Link(const Snapshot &snapshot, const ViewerContext &vContext, const LibraryInfo &builtins);
// Link all documents in snapshot, collecting all diagnostic messages (if messages != 0)
ContextPtr operator()(QHash<QString, QList<DiagnosticMessage> > *messages = 0);
......
......@@ -33,7 +33,8 @@
#include "qmljs_global.h"
#include "qmljsdocument.h"
#include "qmljsbundle.h"
#include "qmljsconstants.h"
#include "qmljsviewercontext.h"
#include <utils/environment.h>
#include <QObject>
......@@ -175,6 +176,12 @@ public:
virtual LibraryInfo builtins(const Document::Ptr &doc) const = 0;
virtual ViewerContext completeVContext(const ViewerContext &vCtx,
const Document::Ptr &doc = Document::Ptr(0)) const = 0;
virtual ViewerContext defaultVContext(bool autoComplete = true,
const Document::Ptr &doc = Document::Ptr(0)) const = 0;
virtual void setDefaultVContext(const ViewerContext &vContext) = 0;
// Blocks until all parsing threads are done. Used for testing.
virtual void joinAllThreads() = 0;
......
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "qmljsviewercontext.h"
namespace QmlJS {
/*!
\class QmlJS::ViewerContext
\brief The ViewerContext class encapsulate selector and paths for a given viewer.
Using a a different viewer context can emulate (the pure qml part) of a device.
This allows checking how a given qml would be interpreted on another platform/viewer.
Screen information will also most likely need to be added here.
*/
ViewerContext::ViewerContext()
: language(Language::Qml), flags(AddAllPaths)
{ }
ViewerContext::ViewerContext(QStringList selectors, QStringList paths,
QmlJS::Language::Enum language,
QmlJS::ViewerContext::Flags flags)
: selectors(selectors), paths(paths), language(language),
flags(flags)
{ }
/*
which languages might be imported in this context
*/
bool ViewerContext::languageIsCompatible(Language::Enum l) const
{
switch (language) {
case Language::JavaScript:
return l == Language::JavaScript;
case Language::Json:
return l == Language::Json;
case Language::Qml:
return l == Language::Qml || l == Language::QmlQtQuick1 || l == Language::QmlQtQuick2
|| Language::JavaScript;
case Language::QmlProject:
return l == Language::QmlProject;
case Language::QmlQbs:
return l == Language::QmlQbs;
case Language::QmlQtQuick1:
return l == Language::Qml || l == Language::QmlQtQuick1 || Language::JavaScript;
case Language::QmlQtQuick2:
return l == Language::Qml || l == Language::QmlQtQuick2 || Language::JavaScript;
case Language::QmlTypeInfo:
return l == Language::QmlTypeInfo;
case Language::Unknown: // ?
return true;
}
}
} // namespace QmlJS
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef VIEWERCONTEXT_H
#define VIEWERCONTEXT_H
#include "qmljs_global.h"
#include "qmljsconstants.h"
#include <QStringList>
namespace QmlJS {
class QMLJS_EXPORT ViewerContext
{
public:
enum Flags {
Complete,
AddAllPaths,
AddQtPath
};
ViewerContext();
ViewerContext(QStringList selectors, QStringList paths,
Language::Enum language = Language::Qml,
Flags flags = AddAllPaths);
bool languageIsCompatible(Language::Enum l) const;
QStringList selectors;
QStringList paths;
Language::Enum language;
Flags flags;
};
} // namespace QmlJS
#endif // VIEWERCONTEXT_H
......@@ -101,7 +101,7 @@ static inline bool checkIfDerivedFromItem(const QString &fileName)
snapshot.insert(document);
QmlJS::Link link(snapshot, modelManager->importPaths(), QmlJS::ModelManagerInterface::instance()->builtins(document));
QmlJS::Link link(snapshot, modelManager->defaultVContext(), QmlJS::ModelManagerInterface::instance()->builtins(document));
QList<QmlJS::DiagnosticMessage> diagnosticLinkMessages;
QmlJS::ContextPtr context = link(document, &diagnosticLinkMessages);
......
......@@ -306,10 +306,10 @@ class ReadingContext
{
public:
ReadingContext(const Snapshot &snapshot, const Document::Ptr &doc,
const QStringList importPaths)
const ViewerContext &vContext)
: m_snapshot(snapshot)
, m_doc(doc)
, m_link(snapshot, importPaths,
, m_link(snapshot, vContext,
QmlJS::ModelManagerInterface::instance()->builtins(doc))
, m_context(m_link(doc, &m_diagnosticLinkMessages))
, m_scopeChain(doc, m_context)
......@@ -751,7 +751,11 @@ bool TextToModelMerger::load(const QString &data, DifferenceHandler &differenceH
return false;
}
snapshot.insert(doc);
ReadingContext ctxt(snapshot, doc, importPaths);
QmlJS::ViewerContext vContext;
vContext.language = QmlJS::Language::Qml;