forked from qt-creator/qt-creator
qmljs: new import/dep tracking
Change-Id: I9f4de2a06aad3afb80372a4b80e56db658683575 Reviewed-by: Thomas Hartmann <Thomas.Hartmann@digia.com>
This commit is contained in:
@@ -39,7 +39,9 @@ HEADERS += \
|
|||||||
$$PWD/qmljssimplereader.h \
|
$$PWD/qmljssimplereader.h \
|
||||||
$$PWD/persistenttrie.h \
|
$$PWD/persistenttrie.h \
|
||||||
$$PWD/qmljsqrcparser.h \
|
$$PWD/qmljsqrcparser.h \
|
||||||
$$PWD/qmljsconstants.h
|
$$PWD/qmljsconstants.h \
|
||||||
|
$$PWD/qmljsimportdependencies.h \
|
||||||
|
$$PWD/viewercontext.h
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
$$PWD/qmljsbind.cpp \
|
$$PWD/qmljsbind.cpp \
|
||||||
@@ -70,7 +72,10 @@ SOURCES += \
|
|||||||
$$PWD/consoleitem.cpp \
|
$$PWD/consoleitem.cpp \
|
||||||
$$PWD/qmljssimplereader.cpp \
|
$$PWD/qmljssimplereader.cpp \
|
||||||
$$PWD/persistenttrie.cpp \
|
$$PWD/persistenttrie.cpp \
|
||||||
$$PWD/qmljsqrcparser.cpp
|
$$PWD/qmljsqrcparser.cpp \
|
||||||
|
$$PWD/qmljsimportdependencies.cpp \
|
||||||
|
$$PWD/qmljsviewercontext.cpp
|
||||||
|
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
$$PWD/qmljs.qrc
|
$$PWD/qmljs.qrc
|
||||||
|
@@ -35,6 +35,7 @@ QtcLibrary {
|
|||||||
"qmljsevaluate.cpp", "qmljsevaluate.h",
|
"qmljsevaluate.cpp", "qmljsevaluate.h",
|
||||||
"qmljsicons.cpp", "qmljsicons.h",
|
"qmljsicons.cpp", "qmljsicons.h",
|
||||||
"qmljsicontextpane.h",
|
"qmljsicontextpane.h",
|
||||||
|
"qmljsimportdependencies.cpp", "qmljsimportdependencies.h",
|
||||||
"qmljsindenter.cpp", "qmljsindenter.h",
|
"qmljsindenter.cpp", "qmljsindenter.h",
|
||||||
"qmljsinterpreter.cpp", "qmljsinterpreter.h",
|
"qmljsinterpreter.cpp", "qmljsinterpreter.h",
|
||||||
"qmljslineinfo.cpp", "qmljslineinfo.h",
|
"qmljslineinfo.cpp", "qmljslineinfo.h",
|
||||||
@@ -52,7 +53,8 @@ QtcLibrary {
|
|||||||
"qmljsstaticanalysismessage.cpp", "qmljsstaticanalysismessage.h",
|
"qmljsstaticanalysismessage.cpp", "qmljsstaticanalysismessage.h",
|
||||||
"qmljstypedescriptionreader.cpp", "qmljstypedescriptionreader.h",
|
"qmljstypedescriptionreader.cpp", "qmljstypedescriptionreader.h",
|
||||||
"qmljsutils.cpp", "qmljsutils.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 {
|
namespace ImportType {
|
||||||
enum Enum {
|
enum Enum {
|
||||||
Invalid,
|
Invalid,
|
||||||
ImplicitDirectory,
|
|
||||||
Library,
|
Library,
|
||||||
File,
|
|
||||||
Directory,
|
Directory,
|
||||||
QrcFile,
|
ImplicitDirectory,
|
||||||
|
File,
|
||||||
|
UnknownFile, // refers a file/directory that wasn't found (or to an url)
|
||||||
QrcDirectory,
|
QrcDirectory,
|
||||||
ImplicitQrcDirectory,
|
QrcFile
|
||||||
UnknownFile // refers a file/directory that wasn't found
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ImportKind {
|
||||||
|
enum Enum {
|
||||||
|
Invalid,
|
||||||
|
Library,
|
||||||
|
Path,
|
||||||
|
QrcPath,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -54,17 +54,20 @@ using namespace QmlJS::AST;
|
|||||||
QmlJSTextEditorWidget::semanticInfo()::context.
|
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;
|
result->_ptr = result;
|
||||||
return 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),
|
: _snapshot(snapshot),
|
||||||
_valueOwner(valueOwner),
|
_valueOwner(valueOwner),
|
||||||
_imports(imports)
|
_imports(imports),
|
||||||
|
_vContext(vContext)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include "qmljs_global.h"
|
#include "qmljs_global.h"
|
||||||
#include "qmljsvalueowner.h"
|
#include "qmljsvalueowner.h"
|
||||||
|
#include "qmljsviewercontext.h"
|
||||||
|
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
|
|
||||||
@@ -50,7 +51,8 @@ public:
|
|||||||
typedef QHash<const Document *, QSharedPointer<const Imports> > ImportsPerDocument;
|
typedef QHash<const Document *, QSharedPointer<const Imports> > ImportsPerDocument;
|
||||||
|
|
||||||
// Context takes ownership of valueOwner
|
// 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();
|
~Context();
|
||||||
|
|
||||||
ContextPtr ptr() const;
|
ContextPtr ptr() const;
|
||||||
@@ -69,11 +71,13 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// Context takes ownership of valueOwner
|
// 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;
|
Snapshot _snapshot;
|
||||||
QSharedPointer<ValueOwner> _valueOwner;
|
QSharedPointer<ValueOwner> _valueOwner;
|
||||||
ImportsPerDocument _imports;
|
ImportsPerDocument _imports;
|
||||||
|
ViewerContext _vContext;
|
||||||
QWeakPointer<const Context> _ptr;
|
QWeakPointer<const Context> _ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
#include "qmljsdocument.h"
|
#include "qmljsdocument.h"
|
||||||
#include "qmljsbind.h"
|
#include "qmljsbind.h"
|
||||||
#include "qmljsconstants.h"
|
#include "qmljsconstants.h"
|
||||||
|
#include "qmljsimportdependencies.h"
|
||||||
#include <qmljs/parser/qmljslexer_p.h>
|
#include <qmljs/parser/qmljslexer_p.h>
|
||||||
#include <qmljs/parser/qmljsparser_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)
|
void Snapshot::insert(const Document::Ptr &document, bool allowInvalid)
|
||||||
{
|
{
|
||||||
if (document && (allowInvalid || document->qmlProgram() || document->jsProgram())) {
|
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(
|
Document::MutablePtr Snapshot::documentFromSource(
|
||||||
const QString &code, const QString &fileName,
|
const QString &code, const QString &fileName,
|
||||||
Language::Enum language) const
|
Language::Enum language) const
|
||||||
|
@@ -39,11 +39,13 @@
|
|||||||
#include "parser/qmljsengine_p.h"
|
#include "parser/qmljsengine_p.h"
|
||||||
#include "qmljs_global.h"
|
#include "qmljs_global.h"
|
||||||
#include "qmljsconstants.h"
|
#include "qmljsconstants.h"
|
||||||
|
#include "qmljsimportdependencies.h"
|
||||||
|
|
||||||
namespace QmlJS {
|
namespace QmlJS {
|
||||||
|
|
||||||
class Bind;
|
class Bind;
|
||||||
class Snapshot;
|
class Snapshot;
|
||||||
|
class ImportDependencies;
|
||||||
|
|
||||||
class QMLJS_EXPORT Document
|
class QMLJS_EXPORT Document
|
||||||
{
|
{
|
||||||
@@ -204,9 +206,11 @@ class QMLJS_EXPORT Snapshot
|
|||||||
QHash<QString, Document::Ptr> _documents;
|
QHash<QString, Document::Ptr> _documents;
|
||||||
QHash<QString, QList<Document::Ptr> > _documentsByPath;
|
QHash<QString, QList<Document::Ptr> > _documentsByPath;
|
||||||
QHash<QString, LibraryInfo> _libraries;
|
QHash<QString, LibraryInfo> _libraries;
|
||||||
|
ImportDependencies _dependencies;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Snapshot();
|
Snapshot();
|
||||||
|
Snapshot(const Snapshot &o);
|
||||||
~Snapshot();
|
~Snapshot();
|
||||||
|
|
||||||
typedef _Base::iterator iterator;
|
typedef _Base::iterator iterator;
|
||||||
@@ -219,6 +223,9 @@ public:
|
|||||||
void insertLibraryInfo(const QString &path, const LibraryInfo &info);
|
void insertLibraryInfo(const QString &path, const LibraryInfo &info);
|
||||||
void remove(const QString &fileName);
|
void remove(const QString &fileName);
|
||||||
|
|
||||||
|
const ImportDependencies *importDependencies() const;
|
||||||
|
ImportDependencies *importDependencies();
|
||||||
|
|
||||||
Document::Ptr document(const QString &fileName) const;
|
Document::Ptr document(const QString &fileName) const;
|
||||||
QList<Document::Ptr> documentsInDirectory(const QString &path) const;
|
QList<Document::Ptr> documentsInDirectory(const QString &path) const;
|
||||||
LibraryInfo libraryInfo(const QString &path) const;
|
LibraryInfo libraryInfo(const QString &path) const;
|
||||||
|
826
src/libs/qmljs/qmljsimportdependencies.cpp
Normal file
826
src/libs/qmljs/qmljsimportdependencies.cpp
Normal file
@@ -0,0 +1,826 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "qmljsimportdependencies.h"
|
||||||
|
#include "qmljsinterpreter.h"
|
||||||
|
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/function.h>
|
||||||
|
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace QmlJS {
|
||||||
|
|
||||||
|
ImportKind::Enum toImportKind(ImportType::Enum type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case ImportType::Invalid:
|
||||||
|
break;
|
||||||
|
case ImportType::Library:
|
||||||
|
return ImportKind::Library;
|
||||||
|
case ImportType::ImplicitDirectory:
|
||||||
|
case ImportType::File:
|
||||||
|
case ImportType::Directory:
|
||||||
|
case ImportType::UnknownFile:
|
||||||
|
return ImportKind::Path;
|
||||||
|
case ImportType::QrcFile:
|
||||||
|
case ImportType::QrcDirectory:
|
||||||
|
return ImportKind::QrcPath;
|
||||||
|
}
|
||||||
|
return ImportKind::Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImportMatchStrength::ImportMatchStrength(QList<int> match)
|
||||||
|
: m_match(match)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
int ImportMatchStrength::compareMatch(const ImportMatchStrength &o) const
|
||||||
|
{
|
||||||
|
int len1 = m_match.size();
|
||||||
|
int len2 = o.m_match.size();
|
||||||
|
int len = ((len1 < len2) ? len1 : len2);
|
||||||
|
for (int i = 0; i < len; ++ i) {
|
||||||
|
int v1 = m_match.at(i);
|
||||||
|
int v2 = o.m_match.at(i);
|
||||||
|
if (v1 < v2)
|
||||||
|
return -1;
|
||||||
|
if (v2 > v1)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (len1 < len2)
|
||||||
|
return -1;
|
||||||
|
if (len1 > len2)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImportMatchStrength::hasNoMatch()
|
||||||
|
{
|
||||||
|
return m_match.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImportMatchStrength::hasMatch()
|
||||||
|
{
|
||||||
|
return !m_match.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator ==(const ImportMatchStrength &m1, const ImportMatchStrength &m2)
|
||||||
|
{
|
||||||
|
return m1.m_match == m2.m_match;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator !=(const ImportMatchStrength &m1, const ImportMatchStrength &m2)
|
||||||
|
{
|
||||||
|
return !(m1 == m2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator <(const ImportMatchStrength &m1, const ImportMatchStrength &m2)
|
||||||
|
{
|
||||||
|
return m1.compareMatch(m2) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImportKey::ImportKey()
|
||||||
|
: type(ImportType::Invalid),
|
||||||
|
majorVersion(LanguageUtils::ComponentVersion::NoVersion),
|
||||||
|
minorVersion(LanguageUtils::ComponentVersion::NoVersion)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void ImportKey::addToHash(QCryptographicHash &hash) const
|
||||||
|
{
|
||||||
|
hash.addData(reinterpret_cast<const char *>(&type), sizeof(type));
|
||||||
|
hash.addData(reinterpret_cast<const char *>(&majorVersion), sizeof(majorVersion));
|
||||||
|
hash.addData(reinterpret_cast<const char *>(&minorVersion), sizeof(minorVersion));
|
||||||
|
foreach (const QString &s, splitPath) {
|
||||||
|
hash.addData("/", 1);
|
||||||
|
hash.addData(reinterpret_cast<const char *>(s.constData()), sizeof(QChar) * s.size());
|
||||||
|
}
|
||||||
|
hash.addData("/", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImportKey ImportKey::flatKey() const {
|
||||||
|
switch (type) {
|
||||||
|
case ImportType::Invalid:
|
||||||
|
return *this;
|
||||||
|
case ImportType::ImplicitDirectory:
|
||||||
|
case ImportType::Library:
|
||||||
|
case ImportType::File:
|
||||||
|
case ImportType::Directory:
|
||||||
|
case ImportType::QrcFile:
|
||||||
|
case ImportType::QrcDirectory:
|
||||||
|
case ImportType::UnknownFile:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
QStringList flatPath = splitPath;
|
||||||
|
int i = 0;
|
||||||
|
while (i < flatPath.size()) {
|
||||||
|
if (flatPath.at(i).startsWith(QLatin1Char('+')))
|
||||||
|
flatPath.removeAt(i);
|
||||||
|
else
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
if (flatPath.size() == splitPath.size())
|
||||||
|
return *this;
|
||||||
|
ImportKey res = *this;
|
||||||
|
res.splitPath = flatPath;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImportKey::ImportKey(const ImportInfo &info)
|
||||||
|
: type(info.type())
|
||||||
|
, majorVersion(info.version().majorVersion())
|
||||||
|
, minorVersion(info.version().minorVersion())
|
||||||
|
{
|
||||||
|
splitPath = QFileInfo(info.path()).canonicalFilePath().split(QChar::fromLatin1('/'),
|
||||||
|
QString::KeepEmptyParts);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ImportKey::path() const
|
||||||
|
{
|
||||||
|
QString res = splitPath.join(QString::fromLatin1("/"));
|
||||||
|
if (res.isEmpty() && !splitPath.isEmpty())
|
||||||
|
return QLatin1String("/");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImportMatchStrength ImportKey::matchImport(const ImportKey &o, const ViewerContext &vContext) const
|
||||||
|
{
|
||||||
|
if (majorVersion != o.majorVersion || minorVersion > o.minorVersion)
|
||||||
|
return ImportMatchStrength();
|
||||||
|
bool dirToFile = false;
|
||||||
|
switch (o.type) {
|
||||||
|
case ImportType::Invalid:
|
||||||
|
return ImportMatchStrength();
|
||||||
|
case ImportType::ImplicitDirectory:
|
||||||
|
case ImportType::Directory:
|
||||||
|
switch (type) {
|
||||||
|
case ImportType::File:
|
||||||
|
case ImportType::UnknownFile:
|
||||||
|
dirToFile = true;
|
||||||
|
break;
|
||||||
|
case ImportType::ImplicitDirectory:
|
||||||
|
case ImportType::Directory:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ImportMatchStrength();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ImportType::Library:
|
||||||
|
if (type != ImportType::Library)
|
||||||
|
return ImportMatchStrength();
|
||||||
|
break;
|
||||||
|
case ImportType::QrcDirectory:
|
||||||
|
switch (type) {
|
||||||
|
case ImportType::QrcFile:
|
||||||
|
dirToFile = true;
|
||||||
|
break;
|
||||||
|
case ImportType::QrcDirectory:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ImportMatchStrength();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ImportType::QrcFile:
|
||||||
|
if (type != ImportType::QrcFile)
|
||||||
|
return ImportMatchStrength();
|
||||||
|
case ImportType::UnknownFile:
|
||||||
|
case ImportType::File:
|
||||||
|
switch (type) {
|
||||||
|
case ImportType::UnknownFile:
|
||||||
|
case ImportType::File:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ImportMatchStrength();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<int> res;
|
||||||
|
int iPath1 = 0;
|
||||||
|
int lenPath1 = splitPath.size();
|
||||||
|
int iPath2 = 0;
|
||||||
|
int lenPath2 = o.splitPath.size();
|
||||||
|
if (dirToFile)
|
||||||
|
--lenPath1;
|
||||||
|
int iSelector = 0;
|
||||||
|
int nSelectors = vContext.selectors.size();
|
||||||
|
while (iPath1 < lenPath1) {
|
||||||
|
if (lenPath2 - iPath2 > lenPath1 - iPath1)
|
||||||
|
return ImportMatchStrength();
|
||||||
|
QString p1 = splitPath.at(iPath1);
|
||||||
|
if (iPath2 < lenPath2) {
|
||||||
|
QString p2 = splitPath.at(iPath2);
|
||||||
|
if (p1 == p2) {
|
||||||
|
++iPath1;
|
||||||
|
++iPath2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!p1.startsWith(QLatin1Char('+')))
|
||||||
|
return QList<int>();
|
||||||
|
QStringRef selectorAtt(&p1, 1, p1.size()-1);
|
||||||
|
while (iSelector < nSelectors) {
|
||||||
|
if (selectorAtt == vContext.selectors.at(iSelector))
|
||||||
|
break;
|
||||||
|
++iSelector;
|
||||||
|
}
|
||||||
|
if (iSelector == nSelectors)
|
||||||
|
return QList<int>();
|
||||||
|
res << (nSelectors - iSelector);
|
||||||
|
++iSelector;
|
||||||
|
++iPath1;
|
||||||
|
}
|
||||||
|
if (iPath2 != lenPath2)
|
||||||
|
return QList<int>();
|
||||||
|
if (res.isEmpty())
|
||||||
|
res << 0;
|
||||||
|
return ImportMatchStrength(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ImportKey::compare(const ImportKey &other) const
|
||||||
|
{
|
||||||
|
ImportKind::Enum k1 = toImportKind(type);
|
||||||
|
ImportKind::Enum k2 = toImportKind(other.type);
|
||||||
|
if (k1 < k2)
|
||||||
|
return -1;
|
||||||
|
if (k1 > k2)
|
||||||
|
return 1;
|
||||||
|
int len1 = splitPath.size();
|
||||||
|
int len2 = other.splitPath.size();
|
||||||
|
int len = ((len1 < len2) ? len1 : len2);
|
||||||
|
for (int i = 0; i < len; ++ i) {
|
||||||
|
QString v1 = splitPath.at(i);
|
||||||
|
QString v2 = other.splitPath.at(i);
|
||||||
|
if (v1 < v2)
|
||||||
|
return -1;
|
||||||
|
if (v2 > v1)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (len1 < len2)
|
||||||
|
return -1;
|
||||||
|
if (len1 > len2)
|
||||||
|
return 1;
|
||||||
|
if (majorVersion < other.majorVersion)
|
||||||
|
return -1;
|
||||||
|
if (majorVersion > other.majorVersion)
|
||||||
|
return 1;
|
||||||
|
if (minorVersion < other.minorVersion)
|
||||||
|
return -1;
|
||||||
|
if (minorVersion > other.minorVersion)
|
||||||
|
return 1;
|
||||||
|
if (type < other.type)
|
||||||
|
return -1;
|
||||||
|
if (type > other.type)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImportKey::isDirectoryLike() const
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case ImportType::Directory:
|
||||||
|
case ImportType::ImplicitDirectory:
|
||||||
|
case ImportType::QrcDirectory:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImportKey::DirCompareInfo ImportKey::compareDir(const ImportKey &superDir) const
|
||||||
|
{
|
||||||
|
// assumes dir/+selectors/file (i.e. no directories inside selectors)
|
||||||
|
switch (superDir.type) {
|
||||||
|
case ImportType::UnknownFile:
|
||||||
|
case ImportType::File:
|
||||||
|
case ImportType::Directory:
|
||||||
|
case ImportType::ImplicitDirectory:
|
||||||
|
if (type != ImportType::File && type != ImportType::ImplicitDirectory
|
||||||
|
&& type != ImportType::Directory && type != ImportType::UnknownFile)
|
||||||
|
return Incompatible;
|
||||||
|
break;
|
||||||
|
case ImportType::QrcDirectory:
|
||||||
|
case ImportType::QrcFile:
|
||||||
|
if (type != ImportType::QrcDirectory && type != ImportType::QrcFile)
|
||||||
|
return Incompatible;
|
||||||
|
break;
|
||||||
|
case ImportType::Invalid:
|
||||||
|
case ImportType::Library:
|
||||||
|
return Incompatible;
|
||||||
|
}
|
||||||
|
bool isDir1 = isDirectoryLike();
|
||||||
|
bool isDir2 = superDir.isDirectoryLike();
|
||||||
|
int len1 = splitPath.size();
|
||||||
|
int len2 = superDir.splitPath.size();
|
||||||
|
if (isDir1 && len1 > 0)
|
||||||
|
--len1;
|
||||||
|
if (isDir2 && len2 > 0)
|
||||||
|
--len2;
|
||||||
|
|
||||||
|
int i1 = 0;
|
||||||
|
int i2 = 0;
|
||||||
|
while (i1 < len1 && i2 < len2) {
|
||||||
|
QString p1 = splitPath.at(i1);
|
||||||
|
QString p2 = superDir.splitPath.at(i2);
|
||||||
|
if (p1 == p2) {
|
||||||
|
++i1;
|
||||||
|
++i2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (p1.startsWith(QLatin1Char('+'))) {
|
||||||
|
if (p2.startsWith(QLatin1Char('+')))
|
||||||
|
return SameDir;
|
||||||
|
return SecondInFirst;
|
||||||
|
}
|
||||||
|
if (p2.startsWith(QLatin1Char('+')))
|
||||||
|
return FirstInSecond;
|
||||||
|
return Different;
|
||||||
|
}
|
||||||
|
if (i1 < len1) {
|
||||||
|
if (splitPath.at(i1).startsWith(QLatin1Char('+')))
|
||||||
|
return SameDir;
|
||||||
|
return SecondInFirst;
|
||||||
|
}
|
||||||
|
if (i2 < len2) {
|
||||||
|
if (superDir.splitPath.at(i2).startsWith(QLatin1Char('+')))
|
||||||
|
return SameDir;
|
||||||
|
return SecondInFirst;
|
||||||
|
}
|
||||||
|
return SameDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint qHash(const ImportKey &info)
|
||||||
|
{
|
||||||
|
uint res = ::qHash(info.type) ^
|
||||||
|
::qHash(info.majorVersion) ^ ::qHash(info.minorVersion);
|
||||||
|
foreach (const QString &s, info.splitPath)
|
||||||
|
res = res ^ ::qHash(s);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const ImportKey &i1, const ImportKey &i2)
|
||||||
|
{
|
||||||
|
return i1.type == i2.type
|
||||||
|
&& i1.splitPath == i2.splitPath
|
||||||
|
&& i1.majorVersion == i2.majorVersion
|
||||||
|
&& i1.minorVersion == i2.minorVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator !=(const ImportKey &i1, const ImportKey &i2)
|
||||||
|
{
|
||||||
|
return ! (i1 == i2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator <(const ImportKey &i1, const ImportKey &i2)
|
||||||
|
{
|
||||||
|
return i1.compare(i2) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Export::Export()
|
||||||
|
: intrinsic(false)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Export::Export(ImportKey exportName, QString pathRequired, bool intrinsic)
|
||||||
|
: exportName(exportName), pathRequired(pathRequired), intrinsic(intrinsic)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
bool Export::visibleInVContext(const ViewerContext &vContext) const
|
||||||
|
{
|
||||||
|
return pathRequired.isEmpty() || vContext.paths.contains(pathRequired);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator ==(const Export &i1, const Export &i2)
|
||||||
|
{
|
||||||
|
return i1.exportName == i2.exportName
|
||||||
|
&& i1.pathRequired == i2.pathRequired
|
||||||
|
&& i1.intrinsic == i2.intrinsic;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator !=(const Export &i1, const Export &i2)
|
||||||
|
{
|
||||||
|
return !(i1 == i2);
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreImport::CoreImport() : language(Language::Qml) { }
|
||||||
|
|
||||||
|
CoreImport::CoreImport(const QString &importId, QList<Export> possibleExports,
|
||||||
|
Language::Enum language, QByteArray fingerprint)
|
||||||
|
: importId(importId), possibleExports(possibleExports), language(language),
|
||||||
|
fingerprint(fingerprint)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
bool CoreImport::valid() {
|
||||||
|
return !fingerprint.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray DependencyInfo::calculateFingerprint(const ImportDependencies &deps)
|
||||||
|
{
|
||||||
|
QCryptographicHash hash(QCryptographicHash::Sha1);
|
||||||
|
rootImport.addToHash(hash);
|
||||||
|
QStringList coreImports = allCoreImports.toList();
|
||||||
|
coreImports.sort();
|
||||||
|
foreach (const QString importId, coreImports) {
|
||||||
|
hash.addData(reinterpret_cast<const char*>(importId.constData()), importId.size() * sizeof(QChar));
|
||||||
|
QByteArray coreImportFingerprint = deps.coreImport(importId).fingerprint;
|
||||||
|
hash.addData(coreImportFingerprint);
|
||||||
|
}
|
||||||
|
hash.addData("/", 1);
|
||||||
|
QList<ImportKey> imports(allImports.toList());
|
||||||
|
std::sort(imports.begin(), imports.end());
|
||||||
|
foreach (const ImportKey &k, imports)
|
||||||
|
k.addToHash(hash);
|
||||||
|
return hash.result();
|
||||||
|
}
|
||||||
|
|
||||||
|
MatchedImport::MatchedImport()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
MatchedImport::MatchedImport(ImportMatchStrength matchStrength, ImportKey importKey,
|
||||||
|
QString coreImportId)
|
||||||
|
: matchStrength(matchStrength), importKey(importKey), coreImportId(coreImportId)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
int MatchedImport::compare(const MatchedImport &o) const {
|
||||||
|
int res = matchStrength.compareMatch(o.matchStrength);
|
||||||
|
if (res != 0)
|
||||||
|
return res;
|
||||||
|
res = importKey.compare(o.importKey);
|
||||||
|
if (res != 0)
|
||||||
|
return res;
|
||||||
|
res = coreImportId.compare(o.coreImportId);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator ==(const MatchedImport &m1, const MatchedImport &m2)
|
||||||
|
{
|
||||||
|
return m1.compare(m2) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator !=(const MatchedImport &m1, const MatchedImport &m2)
|
||||||
|
{
|
||||||
|
return m1.compare(m2) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator <(const MatchedImport &m1, const MatchedImport &m2)
|
||||||
|
{
|
||||||
|
return m1.compare(m2) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImportDependencies::ImportDependencies()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
ImportDependencies::~ImportDependencies()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void ImportDependencies::filter(const ViewerContext &vContext)
|
||||||
|
{
|
||||||
|
QMap<QString, CoreImport> newCoreImports;
|
||||||
|
QMap<ImportKey, QStringList> newImportCache;
|
||||||
|
QMapIterator<QString, CoreImport> j(m_coreImports);
|
||||||
|
bool hasChanges = false;
|
||||||
|
while (j.hasNext()) {
|
||||||
|
j.next();
|
||||||
|
const CoreImport &cImport = j.value();
|
||||||
|
if (vContext.languageIsCompatible(cImport.language)) {
|
||||||
|
QList<Export> newExports;
|
||||||
|
foreach (const Export &e, cImport.possibleExports) {
|
||||||
|
if (e.visibleInVContext(vContext)) {
|
||||||
|
newExports.append(e);
|
||||||
|
QStringList &candidateImports = newImportCache[e.exportName];
|
||||||
|
if (!candidateImports.contains(cImport.importId))
|
||||||
|
candidateImports.append(cImport.importId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newExports.size() == cImport.possibleExports.size()) {
|
||||||
|
newCoreImports.insert(cImport.importId, cImport);
|
||||||
|
} else if (newExports.length() > 0) {
|
||||||
|
CoreImport newCImport = cImport;
|
||||||
|
newCImport.possibleExports = newExports;
|
||||||
|
newCoreImports.insert(newCImport.importId, newCImport);
|
||||||
|
hasChanges = true;
|
||||||
|
} else {
|
||||||
|
hasChanges = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hasChanges = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!hasChanges)
|
||||||
|
return;
|
||||||
|
m_coreImports = newCoreImports;
|
||||||
|
m_importCache = newImportCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreImport ImportDependencies::coreImport(const QString &importId) const
|
||||||
|
{
|
||||||
|
return m_coreImports.value(importId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDependencies::iterateOnCandidateImports(
|
||||||
|
const ImportKey &key, const ViewerContext &vContext,
|
||||||
|
Utils::function<bool (const ImportMatchStrength &,const Export &,const CoreImport &)>
|
||||||
|
const &iterF) const
|
||||||
|
{
|
||||||
|
switch (key.type) {
|
||||||
|
case ImportType::Directory:
|
||||||
|
case ImportType::QrcDirectory:
|
||||||
|
case ImportType::ImplicitDirectory:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
QStringList imp = m_importCache.value(key.flatKey());
|
||||||
|
foreach (const QString &cImportName, imp) {
|
||||||
|
CoreImport cImport = coreImport(cImportName);
|
||||||
|
if (vContext.languageIsCompatible(cImport.language)) {
|
||||||
|
foreach (const Export e, cImport.possibleExports) {
|
||||||
|
if (e.visibleInVContext(vContext)) {
|
||||||
|
ImportMatchStrength m = e.exportName.matchImport(key, vContext);
|
||||||
|
if (m.hasMatch()) {
|
||||||
|
if (!iterF(m, e, cImport))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QMap<ImportKey, QStringList>::const_iterator lb = m_importCache.lowerBound(key.flatKey());
|
||||||
|
QMap<ImportKey, QStringList>::const_iterator end = m_importCache.constEnd();
|
||||||
|
while (lb != end) {
|
||||||
|
ImportKey::DirCompareInfo c = key.compareDir(lb.key());
|
||||||
|
if (c == ImportKey::SameDir) {
|
||||||
|
foreach (const QString &cImportName, lb.value()) {
|
||||||
|
CoreImport cImport = coreImport(cImportName);
|
||||||
|
if (vContext.languageIsCompatible(cImport.language)) {
|
||||||
|
foreach (const Export e, cImport.possibleExports) {
|
||||||
|
if (e.visibleInVContext(vContext)) {
|
||||||
|
ImportMatchStrength m = e.exportName.matchImport(key, vContext);
|
||||||
|
if (m.hasMatch()) {
|
||||||
|
if (!iterF(m, e, cImport))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (c != ImportKey::SecondInFirst) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++lb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CollectCandidateImports
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ImportDependencies::ImportElements &res;
|
||||||
|
|
||||||
|
CollectCandidateImports(ImportDependencies::ImportElements & res)
|
||||||
|
: res(res)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
bool operator ()(const ImportMatchStrength &m, const Export &e, const CoreImport &cI) const
|
||||||
|
{
|
||||||
|
ImportKey flatName = e.exportName.flatKey();
|
||||||
|
res[flatName].append(MatchedImport(m, e.exportName, cI.importId));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ImportDependencies::ImportElements ImportDependencies::candidateImports(
|
||||||
|
const ImportKey &key,
|
||||||
|
const ViewerContext &vContext) const
|
||||||
|
{
|
||||||
|
ImportDependencies::ImportElements res;
|
||||||
|
CollectCandidateImports collector(res);
|
||||||
|
iterateOnCandidateImports(key, vContext, collector);
|
||||||
|
typedef QMap<ImportKey, QList<MatchedImport> >::iterator iter_t;
|
||||||
|
iter_t i = res.begin();
|
||||||
|
iter_t end = res.end();
|
||||||
|
while (i != end) {
|
||||||
|
std::sort(i.value().begin(), i.value().end());
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<DependencyInfo::ConstPtr> ImportDependencies::createDependencyInfos(
|
||||||
|
const ImportKey &mainDoc, const ViewerContext &vContext) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(mainDoc);
|
||||||
|
Q_UNUSED(vContext);
|
||||||
|
QList<DependencyInfo::ConstPtr> res;
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDependencies::addCoreImport(const CoreImport &import)
|
||||||
|
{
|
||||||
|
CoreImport newImport = import;
|
||||||
|
if (m_coreImports.contains(import.importId)) {
|
||||||
|
CoreImport oldVal = m_coreImports.value(import.importId);
|
||||||
|
foreach (const Export &e, oldVal.possibleExports)
|
||||||
|
if (!e.intrinsic)
|
||||||
|
newImport.possibleExports.append(e);
|
||||||
|
}
|
||||||
|
m_coreImports.insert(newImport.importId, newImport);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDependencies::removeCoreImport(const QString &importId)
|
||||||
|
{
|
||||||
|
if (!m_coreImports.contains(importId)) {
|
||||||
|
qDebug() << "missing importId in removeCoreImport(" << importId << ")";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CoreImport &cImport = m_coreImports[importId];
|
||||||
|
QList<Export> newExports;
|
||||||
|
foreach (const Export &e, cImport.possibleExports)
|
||||||
|
if (!e.intrinsic)
|
||||||
|
newExports.append(e);
|
||||||
|
if (newExports.size()>0)
|
||||||
|
cImport.possibleExports = newExports;
|
||||||
|
else
|
||||||
|
m_coreImports.remove(importId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDependencies::addExport(const QString &importId, const ImportKey &importKey,
|
||||||
|
const QString &requiredPath)
|
||||||
|
{
|
||||||
|
if (!m_coreImports.contains(importId)) {
|
||||||
|
CoreImport newImport(importId);
|
||||||
|
newImport.language = Language::Unknown;
|
||||||
|
newImport.possibleExports.append(Export(importKey, requiredPath, false));
|
||||||
|
m_coreImports.insert(newImport.importId, newImport);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CoreImport &importValue = m_coreImports[importId];
|
||||||
|
importValue.possibleExports.append(Export(importKey, requiredPath, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDependencies::removeExport(const QString &importId, const ImportKey &importKey,
|
||||||
|
const QString &requiredPath)
|
||||||
|
{
|
||||||
|
if (!m_coreImports.contains(importId)) {
|
||||||
|
qDebug() << "non existing core import for removeExport(" << importId << ", "
|
||||||
|
<< importKey.path() << ")";
|
||||||
|
} else {
|
||||||
|
CoreImport &importValue = m_coreImports[importId];
|
||||||
|
if (!importValue.possibleExports.removeOne(Export(importKey, requiredPath, false))) {
|
||||||
|
qDebug() << "non existing export for removeExport(" << importId << ", "
|
||||||
|
<< importKey.path() << ")";
|
||||||
|
}
|
||||||
|
if (importValue.possibleExports.isEmpty() && importValue.fingerprint.isEmpty())
|
||||||
|
m_coreImports.remove(importId);
|
||||||
|
}
|
||||||
|
if (!m_importCache.contains(importKey)) {
|
||||||
|
qDebug() << "missing possibleExport for " << importKey.path() << " when removing export of "
|
||||||
|
<< importId;
|
||||||
|
} else {
|
||||||
|
QStringList &cImp = m_importCache[importKey];
|
||||||
|
if (!cImp.removeOne(importId)) {
|
||||||
|
qDebug() << "missing possibleExport backpointer for " << importKey.path() << " to "
|
||||||
|
<< importId;
|
||||||
|
}
|
||||||
|
if (cImp.isEmpty())
|
||||||
|
m_importCache.remove(importKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDependencies::iterateOnCoreImports(
|
||||||
|
const ViewerContext &vContext,
|
||||||
|
Utils::function<bool (const CoreImport &)> const &iterF) const
|
||||||
|
{
|
||||||
|
QMapIterator<QString, CoreImport> i(m_coreImports);
|
||||||
|
while (i.hasNext()) {
|
||||||
|
i.next();
|
||||||
|
if (vContext.languageIsCompatible(i.value().language))
|
||||||
|
iterF(i.value()); // check also that at least one export is visible?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDependencies::iterateOnLibraryImports(
|
||||||
|
const ViewerContext &vContext,
|
||||||
|
Utils::function<bool (const ImportMatchStrength &,
|
||||||
|
const Export &,
|
||||||
|
const CoreImport &)> const &iterF) const
|
||||||
|
{
|
||||||
|
typedef QMap<ImportKey, QStringList>::const_iterator iter_t;
|
||||||
|
ImportKey firstLib;
|
||||||
|
firstLib.type = ImportType::Library;
|
||||||
|
iter_t i = m_importCache.lowerBound(firstLib);
|
||||||
|
iter_t end = m_importCache.constEnd();
|
||||||
|
while (i != end && i.key().type == ImportType::Library) {
|
||||||
|
foreach (const QString &cImportName, i.value()) {
|
||||||
|
CoreImport cImport = coreImport(cImportName);
|
||||||
|
if (vContext.languageIsCompatible(cImport.language)) {
|
||||||
|
foreach (const Export &e, cImport.possibleExports) {
|
||||||
|
if (e.visibleInVContext(vContext) && e.exportName.type == ImportType::Library) {
|
||||||
|
ImportMatchStrength m = e.exportName.matchImport(i.key(), vContext);
|
||||||
|
if (m.hasMatch()) {
|
||||||
|
if (!iterF(m, e, cImport))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDependencies::iterateOnSubImports(
|
||||||
|
const ImportKey &baseKey,
|
||||||
|
const ViewerContext &vContext,
|
||||||
|
Utils::function<bool (const ImportMatchStrength &,
|
||||||
|
const Export &,
|
||||||
|
const CoreImport &)> const &iterF) const
|
||||||
|
{
|
||||||
|
typedef QMap<ImportKey, QStringList>::const_iterator iter_t;
|
||||||
|
iter_t i = m_importCache.lowerBound(baseKey);
|
||||||
|
iter_t end = m_importCache.constEnd();
|
||||||
|
while (i != end) {
|
||||||
|
ImportKey::DirCompareInfo c = baseKey.compareDir(i.key());
|
||||||
|
if (c != ImportKey::SameDir && c != ImportKey::SecondInFirst)
|
||||||
|
break;
|
||||||
|
foreach (const QString &cImportName, i.value()) {
|
||||||
|
CoreImport cImport = coreImport(cImportName);
|
||||||
|
if (vContext.languageIsCompatible(cImport.language)) {
|
||||||
|
foreach (const Export &e, cImport.possibleExports) {
|
||||||
|
if (e.visibleInVContext(vContext)) {
|
||||||
|
ImportMatchStrength m = e.exportName.matchImport(i.key(), vContext);
|
||||||
|
if (m.hasMatch()) {
|
||||||
|
if (!iterF(m, e, cImport))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CollectImportKeys {
|
||||||
|
public:
|
||||||
|
QSet<ImportKey> &imports;
|
||||||
|
CollectImportKeys(QSet<ImportKey> &imports)
|
||||||
|
: imports(imports)
|
||||||
|
{ }
|
||||||
|
bool operator()(const ImportMatchStrength &m,
|
||||||
|
const Export &e,
|
||||||
|
const CoreImport &cI) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(m);
|
||||||
|
Q_UNUSED(cI);
|
||||||
|
imports.insert(e.exportName.flatKey());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QSet<ImportKey> ImportDependencies::libraryImports(const ViewerContext &viewContext) const
|
||||||
|
{
|
||||||
|
QSet<ImportKey> res;
|
||||||
|
CollectImportKeys importCollector(res);
|
||||||
|
iterateOnLibraryImports(viewContext, importCollector);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSet<ImportKey> ImportDependencies::subdirImports(
|
||||||
|
const ImportKey &baseKey, const ViewerContext &viewContext) const
|
||||||
|
{
|
||||||
|
QSet<ImportKey> res;
|
||||||
|
CollectImportKeys importCollector(res);
|
||||||
|
iterateOnSubImports(baseKey, viewContext, importCollector);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QmlJS
|
223
src/libs/qmljs/qmljsimportdependencies.h
Normal file
223
src/libs/qmljs/qmljsimportdependencies.h
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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/qmljsdocument.h>
|
||||||
#include <qmljs/qmljs_global.h>
|
#include <qmljs/qmljs_global.h>
|
||||||
#include <qmljs/qmljsconstants.h>
|
#include <qmljs/qmljsconstants.h>
|
||||||
|
#include <qmljs/qmljsimportdependencies.h>
|
||||||
|
|
||||||
#include <QFileInfoList>
|
#include <QFileInfoList>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
@@ -912,6 +913,7 @@ public:
|
|||||||
// const!
|
// const!
|
||||||
ObjectValue *object;
|
ObjectValue *object;
|
||||||
ImportInfo info;
|
ImportInfo info;
|
||||||
|
DependencyInfo::ConstPtr deps;
|
||||||
// uri imports: path to library, else empty
|
// uri imports: path to library, else empty
|
||||||
QString libraryPath;
|
QString libraryPath;
|
||||||
// whether the import succeeded
|
// whether the import succeeded
|
||||||
|
@@ -34,7 +34,8 @@
|
|||||||
#include "qmljsbind.h"
|
#include "qmljsbind.h"
|
||||||
#include "qmljsutils.h"
|
#include "qmljsutils.h"
|
||||||
#include "qmljsmodelmanagerinterface.h"
|
#include "qmljsmodelmanagerinterface.h"
|
||||||
#include <qmljs/qmljsqrcparser.h>
|
#include "qmljsqrcparser.h"
|
||||||
|
#include "qmljsconstants.h"
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
@@ -83,6 +84,7 @@ public:
|
|||||||
ValueOwner *valueOwner;
|
ValueOwner *valueOwner;
|
||||||
QStringList importPaths;
|
QStringList importPaths;
|
||||||
LibraryInfo builtins;
|
LibraryInfo builtins;
|
||||||
|
ViewerContext vContext;
|
||||||
|
|
||||||
QHash<ImportCacheKey, Import> importCache;
|
QHash<ImportCacheKey, Import> importCache;
|
||||||
|
|
||||||
@@ -131,13 +133,14 @@ public:
|
|||||||
\l{QmlJSEditor::SemanticInfo} of a \l{QmlJSEditor::QmlJSTextEditorWidget}.
|
\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(new LinkPrivate)
|
||||||
{
|
{
|
||||||
d->valueOwner = new ValueOwner;
|
d->valueOwner = new ValueOwner;
|
||||||
d->snapshot = snapshot;
|
d->snapshot = snapshot;
|
||||||
d->importPaths = importPaths;
|
d->importPaths = vContext.paths;
|
||||||
d->builtins = builtins;
|
d->builtins = builtins;
|
||||||
|
d->vContext = vContext;
|
||||||
|
|
||||||
d->diagnosticMessages = 0;
|
d->diagnosticMessages = 0;
|
||||||
d->allDiagnosticMessages = 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)
|
ContextPtr Link::operator()(QHash<QString, QList<DiagnosticMessage> > *messages)
|
||||||
{
|
{
|
||||||
d->allDiagnosticMessages = 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)
|
ContextPtr Link::operator()(const Document::Ptr &doc, QList<DiagnosticMessage> *messages)
|
||||||
{
|
{
|
||||||
d->document = doc;
|
d->document = doc;
|
||||||
d->diagnosticMessages = messages;
|
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()
|
Link::~Link()
|
||||||
|
@@ -48,7 +48,7 @@ class QMLJS_EXPORT Link
|
|||||||
Q_DECLARE_TR_FUNCTIONS(QmlJS::Link)
|
Q_DECLARE_TR_FUNCTIONS(QmlJS::Link)
|
||||||
|
|
||||||
public:
|
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)
|
// Link all documents in snapshot, collecting all diagnostic messages (if messages != 0)
|
||||||
ContextPtr operator()(QHash<QString, QList<DiagnosticMessage> > *messages = 0);
|
ContextPtr operator()(QHash<QString, QList<DiagnosticMessage> > *messages = 0);
|
||||||
|
@@ -33,7 +33,8 @@
|
|||||||
#include "qmljs_global.h"
|
#include "qmljs_global.h"
|
||||||
#include "qmljsdocument.h"
|
#include "qmljsdocument.h"
|
||||||
#include "qmljsbundle.h"
|
#include "qmljsbundle.h"
|
||||||
|
#include "qmljsconstants.h"
|
||||||
|
#include "qmljsviewercontext.h"
|
||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
@@ -175,6 +176,12 @@ public:
|
|||||||
|
|
||||||
virtual LibraryInfo builtins(const Document::Ptr &doc) const = 0;
|
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.
|
// Blocks until all parsing threads are done. Used for testing.
|
||||||
virtual void joinAllThreads() = 0;
|
virtual void joinAllThreads() = 0;
|
||||||
|
|
||||||
|
82
src/libs/qmljs/qmljsviewercontext.cpp
Normal file
82
src/libs/qmljs/qmljsviewercontext.cpp
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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
|
63
src/libs/qmljs/qmljsviewercontext.h
Normal file
63
src/libs/qmljs/qmljsviewercontext.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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);
|
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;
|
QList<QmlJS::DiagnosticMessage> diagnosticLinkMessages;
|
||||||
QmlJS::ContextPtr context = link(document, &diagnosticLinkMessages);
|
QmlJS::ContextPtr context = link(document, &diagnosticLinkMessages);
|
||||||
|
@@ -306,10 +306,10 @@ class ReadingContext
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ReadingContext(const Snapshot &snapshot, const Document::Ptr &doc,
|
ReadingContext(const Snapshot &snapshot, const Document::Ptr &doc,
|
||||||
const QStringList importPaths)
|
const ViewerContext &vContext)
|
||||||
: m_snapshot(snapshot)
|
: m_snapshot(snapshot)
|
||||||
, m_doc(doc)
|
, m_doc(doc)
|
||||||
, m_link(snapshot, importPaths,
|
, m_link(snapshot, vContext,
|
||||||
QmlJS::ModelManagerInterface::instance()->builtins(doc))
|
QmlJS::ModelManagerInterface::instance()->builtins(doc))
|
||||||
, m_context(m_link(doc, &m_diagnosticLinkMessages))
|
, m_context(m_link(doc, &m_diagnosticLinkMessages))
|
||||||
, m_scopeChain(doc, m_context)
|
, m_scopeChain(doc, m_context)
|
||||||
@@ -751,7 +751,11 @@ bool TextToModelMerger::load(const QString &data, DifferenceHandler &differenceH
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
snapshot.insert(doc);
|
snapshot.insert(doc);
|
||||||
ReadingContext ctxt(snapshot, doc, importPaths);
|
QmlJS::ViewerContext vContext;
|
||||||
|
vContext.language = QmlJS::Language::Qml;
|
||||||
|
vContext.paths = importPaths;
|
||||||
|
vContext.flags = QmlJS::ViewerContext::Complete;
|
||||||
|
ReadingContext ctxt(snapshot, doc, vContext);
|
||||||
m_scopeChain = QSharedPointer<const ScopeChain>(
|
m_scopeChain = QSharedPointer<const ScopeChain>(
|
||||||
new ScopeChain(ctxt.scopeChain()));
|
new ScopeChain(ctxt.scopeChain()));
|
||||||
m_document = doc;
|
m_document = doc;
|
||||||
|
@@ -831,7 +831,7 @@ static void find_helper(QFutureInterface<FindReferences::Usage> &future,
|
|||||||
|
|
||||||
QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
|
QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
|
||||||
|
|
||||||
Link link(snapshot, modelManager->importPaths(), modelManager->builtins(doc));
|
Link link(snapshot, modelManager->defaultVContext(), modelManager->builtins(doc));
|
||||||
ContextPtr context = link();
|
ContextPtr context = link();
|
||||||
|
|
||||||
ScopeChain scopeChain(doc, context);
|
ScopeChain scopeChain(doc, context);
|
||||||
|
@@ -122,7 +122,7 @@ QmlJSTools::SemanticInfo SemanticInfoUpdater::makeNewSemanticInfo(const QmlJS::D
|
|||||||
|
|
||||||
ModelManagerInterface *modelManager = ModelManagerInterface::instance();
|
ModelManagerInterface *modelManager = ModelManagerInterface::instance();
|
||||||
|
|
||||||
Link link(semanticInfo.snapshot, modelManager->importPaths(), modelManager->builtins(doc));
|
Link link(semanticInfo.snapshot, modelManager->defaultVContext(), modelManager->builtins(doc));
|
||||||
semanticInfo.context = link(doc, &semanticInfo.semanticMessages);
|
semanticInfo.context = link(doc, &semanticInfo.semanticMessages);
|
||||||
|
|
||||||
ScopeChain *scopeChain = new ScopeChain(doc, semanticInfo.context);
|
ScopeChain *scopeChain = new ScopeChain(doc, semanticInfo.context);
|
||||||
|
@@ -92,13 +92,13 @@ static QList<ProjectExplorer::Task> convertToTasks(const QList<StaticAnalysis::M
|
|||||||
void QmlTaskManager::collectMessages(
|
void QmlTaskManager::collectMessages(
|
||||||
QFutureInterface<FileErrorMessages> &future,
|
QFutureInterface<FileErrorMessages> &future,
|
||||||
Snapshot snapshot, QList<ModelManagerInterface::ProjectInfo> projectInfos,
|
Snapshot snapshot, QList<ModelManagerInterface::ProjectInfo> projectInfos,
|
||||||
QStringList importPaths, bool updateSemantic)
|
ViewerContext vContext, bool updateSemantic)
|
||||||
{
|
{
|
||||||
foreach (const ModelManagerInterface::ProjectInfo &info, projectInfos) {
|
foreach (const ModelManagerInterface::ProjectInfo &info, projectInfos) {
|
||||||
QHash<QString, QList<DiagnosticMessage> > linkMessages;
|
QHash<QString, QList<DiagnosticMessage> > linkMessages;
|
||||||
ContextPtr context;
|
ContextPtr context;
|
||||||
if (updateSemantic) {
|
if (updateSemantic) {
|
||||||
Link link(snapshot, importPaths, snapshot.libraryInfo(info.qtImportsPath));
|
Link link(snapshot, vContext, snapshot.libraryInfo(info.qtImportsPath));
|
||||||
context = link(&linkMessages);
|
context = link(&linkMessages);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ void QmlTaskManager::updateMessagesNow(bool updateSemantic)
|
|||||||
QFuture<FileErrorMessages> future =
|
QFuture<FileErrorMessages> future =
|
||||||
QtConcurrent::run<FileErrorMessages>(
|
QtConcurrent::run<FileErrorMessages>(
|
||||||
&collectMessages, modelManager->newestSnapshot(), modelManager->projectInfos(),
|
&collectMessages, modelManager->newestSnapshot(), modelManager->projectInfos(),
|
||||||
modelManager->importPaths(), updateSemantic);
|
modelManager->defaultVContext(), updateSemantic);
|
||||||
m_messageCollector.setFuture(future);
|
m_messageCollector.setFuture(future);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -85,7 +85,7 @@ private:
|
|||||||
static void collectMessages(QFutureInterface<FileErrorMessages> &future,
|
static void collectMessages(QFutureInterface<FileErrorMessages> &future,
|
||||||
QmlJS::Snapshot snapshot,
|
QmlJS::Snapshot snapshot,
|
||||||
QList<QmlJS::ModelManagerInterface::ProjectInfo> projectInfos,
|
QList<QmlJS::ModelManagerInterface::ProjectInfo> projectInfos,
|
||||||
QStringList importPaths,
|
QmlJS::ViewerContext vContext,
|
||||||
bool updateSemantic);
|
bool updateSemantic);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -1121,6 +1121,34 @@ LibraryInfo ModelManager::builtins(const Document::Ptr &doc) const
|
|||||||
return _validSnapshot.libraryInfo(info.qtImportsPath);
|
return _validSnapshot.libraryInfo(info.qtImportsPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ViewerContext ModelManager::completeVContext(const ViewerContext &vCtx,
|
||||||
|
const Document::Ptr &doc) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(doc);
|
||||||
|
ViewerContext res = vCtx;
|
||||||
|
switch (res.flags) {
|
||||||
|
case ViewerContext::Complete:
|
||||||
|
break;
|
||||||
|
case ViewerContext::AddQtPath:
|
||||||
|
case ViewerContext::AddAllPaths:
|
||||||
|
res.paths << importPaths();
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewerContext ModelManager::defaultVContext(bool autoComplete, const Document::Ptr &doc) const
|
||||||
|
{
|
||||||
|
if (autoComplete)
|
||||||
|
return completeVContext(m_vContext, doc);
|
||||||
|
else
|
||||||
|
return m_vContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelManager::setDefaultVContext(const ViewerContext &vContext)
|
||||||
|
{
|
||||||
|
m_vContext = vContext;
|
||||||
|
}
|
||||||
|
|
||||||
void ModelManager::joinAllThreads()
|
void ModelManager::joinAllThreads()
|
||||||
{
|
{
|
||||||
foreach (QFuture<void> future, m_synchronizer.futures())
|
foreach (QFuture<void> future, m_synchronizer.futures())
|
||||||
|
@@ -115,6 +115,14 @@ public:
|
|||||||
|
|
||||||
QmlJS::LibraryInfo builtins(const QmlJS::Document::Ptr &doc) const QTC_OVERRIDE;
|
QmlJS::LibraryInfo builtins(const QmlJS::Document::Ptr &doc) const QTC_OVERRIDE;
|
||||||
|
|
||||||
|
QmlJS::ViewerContext completeVContext(
|
||||||
|
const QmlJS::ViewerContext &vCtx,
|
||||||
|
const QmlJS::Document::Ptr &doc = QmlJS::Document::Ptr(0)) const QTC_OVERRIDE;
|
||||||
|
QmlJS::ViewerContext defaultVContext(
|
||||||
|
bool autoComplete = true,
|
||||||
|
const QmlJS::Document::Ptr &doc = QmlJS::Document::Ptr(0)) const QTC_OVERRIDE;
|
||||||
|
void setDefaultVContext(const QmlJS::ViewerContext &vContext) QTC_OVERRIDE;
|
||||||
|
|
||||||
void joinAllThreads() QTC_OVERRIDE;
|
void joinAllThreads() QTC_OVERRIDE;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
@@ -158,6 +166,7 @@ private:
|
|||||||
QStringList m_defaultImportPaths;
|
QStringList m_defaultImportPaths;
|
||||||
QmlJS::QmlLanguageBundles m_activeBundles;
|
QmlJS::QmlLanguageBundles m_activeBundles;
|
||||||
QmlJS::QmlLanguageBundles m_extendedBundles;
|
QmlJS::QmlLanguageBundles m_extendedBundles;
|
||||||
|
QmlJS::ViewerContext m_vContext;
|
||||||
|
|
||||||
QTimer *m_updateCppQmlTypesTimer;
|
QTimer *m_updateCppQmlTypesTimer;
|
||||||
QTimer *m_asyncResetTimer;
|
QTimer *m_asyncResetTimer;
|
||||||
|
@@ -53,7 +53,7 @@ void QmlJSTools::Internal::QmlJSToolsPlugin::test_basic()
|
|||||||
Document::Ptr doc = snapshot.document(welcomescreenRootPath);
|
Document::Ptr doc = snapshot.document(welcomescreenRootPath);
|
||||||
QVERIFY(doc && doc->isQmlDocument());
|
QVERIFY(doc && doc->isQmlDocument());
|
||||||
|
|
||||||
ContextPtr context = Link(snapshot, QStringList(), LibraryInfo())();
|
ContextPtr context = Link(snapshot, ViewerContext(), LibraryInfo())();
|
||||||
QVERIFY(context);
|
QVERIFY(context);
|
||||||
|
|
||||||
const CppComponentValue *rectangleValue = context->valueOwner()->cppQmlTypes().objectByQualifiedName(
|
const CppComponentValue *rectangleValue = context->valueOwner()->cppQmlTypes().objectByQualifiedName(
|
||||||
|
Reference in New Issue
Block a user