forked from qt-creator/qt-creator
QmlJS: Fix resolution of "alias" directives in qrc files
Previously qrc paths of QML/JS documents were not considered for implicit imports. Only the path of the document in the file system was considered. The QML engine, however, doesn't know the original path at all and only uses the qrc paths for import resolution. This created a mismatch between what the QML engine could recognize and what the code model suggested. Without alias directives, any files imported from a qrc file would have to reside in the same directory as the one implicitly importing them, so this arrangement happened to work, most of the time. In order to support aliases we have to search the files in the same qrc path to figure out the imports. To do that, we keep a reverse map of qrc paths to files in the QrcParser and iterate that when resolving imports. Change-Id: I84baae6cbfbe96ddd5322c81494c1e4a3f473f3f Reviewed-by: Eike Ziller <eike.ziller@theqtcompany.com> Reviewed-by: Tobias Hunger <tobias.hunger@theqtcompany.com>
This commit is contained in:
@@ -2277,6 +2277,14 @@ ImportInfo ImportInfo::implicitDirectoryImport(const QString &directory)
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImportInfo ImportInfo::qrcDirectoryImport(const QString &directory)
|
||||||
|
{
|
||||||
|
ImportInfo info;
|
||||||
|
info.m_type = ImportType::QrcDirectory;
|
||||||
|
info.m_path = directory;
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
bool ImportInfo::isValid() const
|
bool ImportInfo::isValid() const
|
||||||
{
|
{
|
||||||
return m_type != ImportType::Invalid;
|
return m_type != ImportType::Invalid;
|
||||||
|
|||||||
@@ -1002,6 +1002,7 @@ public:
|
|||||||
const QString &as, AST::UiImport *ast = 0);
|
const QString &as, AST::UiImport *ast = 0);
|
||||||
static ImportInfo invalidImport(AST::UiImport *ast = 0);
|
static ImportInfo invalidImport(AST::UiImport *ast = 0);
|
||||||
static ImportInfo implicitDirectoryImport(const QString &directory);
|
static ImportInfo implicitDirectoryImport(const QString &directory);
|
||||||
|
static ImportInfo qrcDirectoryImport(const QString &directory);
|
||||||
|
|
||||||
bool isValid() const;
|
bool isValid() const;
|
||||||
ImportType::Enum type() const;
|
ImportType::Enum type() const;
|
||||||
|
|||||||
@@ -575,16 +575,23 @@ void LinkPrivate::loadQmldirComponents(ObjectValue *import, ComponentVersion ver
|
|||||||
|
|
||||||
void LinkPrivate::loadImplicitDirectoryImports(Imports *imports, Document::Ptr doc)
|
void LinkPrivate::loadImplicitDirectoryImports(Imports *imports, Document::Ptr doc)
|
||||||
{
|
{
|
||||||
ImportInfo implcitDirectoryImportInfo = ImportInfo::implicitDirectoryImport(doc->path());
|
auto processImport = [this, imports, doc](const ImportInfo &importInfo){
|
||||||
|
Import directoryImport = importCache.value(ImportCacheKey(importInfo));
|
||||||
Import directoryImport = importCache.value(ImportCacheKey(implcitDirectoryImportInfo));
|
if (!directoryImport.object) {
|
||||||
if (!directoryImport.object) {
|
directoryImport = importFileOrDirectory(doc, importInfo);
|
||||||
directoryImport = importFileOrDirectory(doc, implcitDirectoryImportInfo);
|
if (directoryImport.object)
|
||||||
|
importCache.insert(ImportCacheKey(importInfo), directoryImport);
|
||||||
|
}
|
||||||
if (directoryImport.object)
|
if (directoryImport.object)
|
||||||
importCache.insert(ImportCacheKey(implcitDirectoryImportInfo), directoryImport);
|
imports->append(directoryImport);
|
||||||
|
};
|
||||||
|
|
||||||
|
processImport(ImportInfo::implicitDirectoryImport(doc->path()));
|
||||||
|
foreach (const QString &path,
|
||||||
|
ModelManagerInterface::instance()->qrcPathsForFile(doc->fileName())) {
|
||||||
|
processImport(ImportInfo::qrcDirectoryImport(
|
||||||
|
QrcParser::qrcDirectoryPathForQrcFilePath(path)));
|
||||||
}
|
}
|
||||||
if (directoryImport.object)
|
|
||||||
imports->append(directoryImport);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinkPrivate::loadImplicitDefaultImports(Imports *imports)
|
void LinkPrivate::loadImplicitDefaultImports(Imports *imports)
|
||||||
|
|||||||
@@ -427,46 +427,10 @@ bool pInfoLessThanImports(const ModelManagerInterface::ProjectInfo &p1, const Mo
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList ModelManagerInterface::filesAtQrcPath(const QString &path, const QLocale *locale,
|
void ModelManagerInterface::iterateQrcFiles(ProjectExplorer::Project *project,
|
||||||
ProjectExplorer::Project *project,
|
QrcResourceSelector resources,
|
||||||
QrcResourceSelector resources)
|
std::function<void(QrcParser::ConstPtr)> callback)
|
||||||
{
|
{
|
||||||
QString normPath = QrcParser::normalizedQrcFilePath(path);
|
|
||||||
QList<ProjectInfo> pInfos;
|
|
||||||
if (project)
|
|
||||||
pInfos.append(projectInfo(project));
|
|
||||||
else
|
|
||||||
pInfos = projectInfos();
|
|
||||||
|
|
||||||
QStringList res;
|
|
||||||
QSet<QString> pathsChecked;
|
|
||||||
foreach (const ModelManagerInterface::ProjectInfo &pInfo, pInfos) {
|
|
||||||
QStringList qrcFilePaths;
|
|
||||||
if (resources == ActiveQrcResources)
|
|
||||||
qrcFilePaths = pInfo.activeResourceFiles;
|
|
||||||
else
|
|
||||||
qrcFilePaths = pInfo.allResourceFiles;
|
|
||||||
foreach (const QString &qrcFilePath, qrcFilePaths) {
|
|
||||||
if (pathsChecked.contains(qrcFilePath))
|
|
||||||
continue;
|
|
||||||
pathsChecked.insert(qrcFilePath);
|
|
||||||
QrcParser::ConstPtr qrcFile = m_qrcCache.parsedPath(qrcFilePath);
|
|
||||||
if (qrcFile.isNull())
|
|
||||||
continue;
|
|
||||||
qrcFile->collectFilesAtPath(normPath, &res, locale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res.sort(); // make the result predictable
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
QMap<QString, QStringList> ModelManagerInterface::filesInQrcPath(const QString &path,
|
|
||||||
const QLocale *locale,
|
|
||||||
ProjectExplorer::Project *project,
|
|
||||||
bool addDirs,
|
|
||||||
QrcResourceSelector resources)
|
|
||||||
{
|
|
||||||
QString normPath = QrcParser::normalizedQrcDirectoryPath(path);
|
|
||||||
QList<ProjectInfo> pInfos;
|
QList<ProjectInfo> pInfos;
|
||||||
if (project) {
|
if (project) {
|
||||||
pInfos.append(projectInfo(project));
|
pInfos.append(projectInfo(project));
|
||||||
@@ -477,7 +441,7 @@ QMap<QString, QStringList> ModelManagerInterface::filesInQrcPath(const QString &
|
|||||||
else
|
else
|
||||||
qSort(pInfos.begin(), pInfos.end(), &pInfoLessThanAll);
|
qSort(pInfos.begin(), pInfos.end(), &pInfoLessThanAll);
|
||||||
}
|
}
|
||||||
QMap<QString, QStringList> res;
|
|
||||||
QSet<QString> pathsChecked;
|
QSet<QString> pathsChecked;
|
||||||
foreach (const ModelManagerInterface::ProjectInfo &pInfo, pInfos) {
|
foreach (const ModelManagerInterface::ProjectInfo &pInfo, pInfos) {
|
||||||
QStringList qrcFilePaths;
|
QStringList qrcFilePaths;
|
||||||
@@ -490,12 +454,47 @@ QMap<QString, QStringList> ModelManagerInterface::filesInQrcPath(const QString &
|
|||||||
continue;
|
continue;
|
||||||
pathsChecked.insert(qrcFilePath);
|
pathsChecked.insert(qrcFilePath);
|
||||||
QrcParser::ConstPtr qrcFile = m_qrcCache.parsedPath(qrcFilePath);
|
QrcParser::ConstPtr qrcFile = m_qrcCache.parsedPath(qrcFilePath);
|
||||||
|
|
||||||
if (qrcFile.isNull())
|
if (qrcFile.isNull())
|
||||||
continue;
|
continue;
|
||||||
qrcFile->collectFilesInPath(normPath, &res, addDirs, locale);
|
callback(qrcFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList ModelManagerInterface::qrcPathsForFile(const QString &file, const QLocale *locale,
|
||||||
|
ProjectExplorer::Project *project,
|
||||||
|
QrcResourceSelector resources)
|
||||||
|
{
|
||||||
|
QStringList res;
|
||||||
|
iterateQrcFiles(project, resources, [&](QrcParser::ConstPtr qrcFile) {
|
||||||
|
qrcFile->collectResourceFilesForSourceFile(file, &res, locale);
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList ModelManagerInterface::filesAtQrcPath(const QString &path, const QLocale *locale,
|
||||||
|
ProjectExplorer::Project *project,
|
||||||
|
QrcResourceSelector resources)
|
||||||
|
{
|
||||||
|
QString normPath = QrcParser::normalizedQrcFilePath(path);
|
||||||
|
QStringList res;
|
||||||
|
iterateQrcFiles(project, resources, [&](QrcParser::ConstPtr qrcFile) {
|
||||||
|
qrcFile->collectFilesAtPath(normPath, &res, locale);
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, QStringList> ModelManagerInterface::filesInQrcPath(const QString &path,
|
||||||
|
const QLocale *locale,
|
||||||
|
ProjectExplorer::Project *project,
|
||||||
|
bool addDirs,
|
||||||
|
QrcResourceSelector resources)
|
||||||
|
{
|
||||||
|
QString normPath = QrcParser::normalizedQrcDirectoryPath(path);
|
||||||
|
QMap<QString, QStringList> res;
|
||||||
|
iterateQrcFiles(project, resources, [&](QrcParser::ConstPtr qrcFile) {
|
||||||
|
qrcFile->collectFilesInPath(normPath, &res, addDirs, locale);
|
||||||
|
});
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -153,6 +153,9 @@ public:
|
|||||||
bool emitDocumentOnDiskChanged);
|
bool emitDocumentOnDiskChanged);
|
||||||
void fileChangedOnDisk(const QString &path);
|
void fileChangedOnDisk(const QString &path);
|
||||||
void removeFiles(const QStringList &files);
|
void removeFiles(const QStringList &files);
|
||||||
|
QStringList qrcPathsForFile(const QString &file, const QLocale *locale = 0,
|
||||||
|
ProjectExplorer::Project *project = 0,
|
||||||
|
QrcResourceSelector resources = AllQrcResources);
|
||||||
QStringList filesAtQrcPath(const QString &path, const QLocale *locale = 0,
|
QStringList filesAtQrcPath(const QString &path, const QLocale *locale = 0,
|
||||||
ProjectExplorer::Project *project = 0,
|
ProjectExplorer::Project *project = 0,
|
||||||
QrcResourceSelector resources = AllQrcResources);
|
QrcResourceSelector resources = AllQrcResources);
|
||||||
@@ -250,6 +253,9 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void cleanupFutures();
|
void cleanupFutures();
|
||||||
|
void iterateQrcFiles(ProjectExplorer::Project *project,
|
||||||
|
QrcResourceSelector resources,
|
||||||
|
std::function<void(QrcParser::ConstPtr)> callback);
|
||||||
|
|
||||||
mutable QMutex m_mutex;
|
mutable QMutex m_mutex;
|
||||||
QmlJS::Snapshot m_validSnapshot;
|
QmlJS::Snapshot m_validSnapshot;
|
||||||
|
|||||||
@@ -74,6 +74,9 @@ public:
|
|||||||
bool hasDirAtPath(const QString &path, const QLocale *locale = 0) const;
|
bool hasDirAtPath(const QString &path, const QLocale *locale = 0) const;
|
||||||
void collectFilesInPath(const QString &path, QMap<QString,QStringList> *res, bool addDirs = false,
|
void collectFilesInPath(const QString &path, QMap<QString,QStringList> *res, bool addDirs = false,
|
||||||
const QLocale *locale = 0) const;
|
const QLocale *locale = 0) const;
|
||||||
|
void collectResourceFilesForSourceFile(const QString &sourceFile, QStringList *res,
|
||||||
|
const QLocale *locale = 0) const;
|
||||||
|
|
||||||
QStringList errorMessages() const;
|
QStringList errorMessages() const;
|
||||||
QStringList languages() const;
|
QStringList languages() const;
|
||||||
private:
|
private:
|
||||||
@@ -81,6 +84,7 @@ private:
|
|||||||
QStringList allUiLanguages(const QLocale *locale) const;
|
QStringList allUiLanguages(const QLocale *locale) const;
|
||||||
|
|
||||||
SMap m_resources;
|
SMap m_resources;
|
||||||
|
SMap m_files;
|
||||||
QStringList m_languages;
|
QStringList m_languages;
|
||||||
QStringList m_errorMessages;
|
QStringList m_errorMessages;
|
||||||
};
|
};
|
||||||
@@ -130,6 +134,11 @@ QString QrcParser::normalizedQrcDirectoryPath(const QString &path) {
|
|||||||
return normPath;
|
return normPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString QrcParser::qrcDirectoryPathForQrcFilePath(const QString &file)
|
||||||
|
{
|
||||||
|
return file.left(file.lastIndexOf(QLatin1Char('/')));
|
||||||
|
}
|
||||||
|
|
||||||
QrcParser::QrcParser()
|
QrcParser::QrcParser()
|
||||||
{
|
{
|
||||||
d = new Internal::QrcParserPrivate(this);
|
d = new Internal::QrcParserPrivate(this);
|
||||||
@@ -181,6 +190,12 @@ void QrcParser::collectFilesInPath(const QString &path, QMap<QString,QStringList
|
|||||||
d->collectFilesInPath(path, res, addDirs, locale);
|
d->collectFilesInPath(path, res, addDirs, locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QrcParser::collectResourceFilesForSourceFile(const QString &sourceFile, QStringList *res,
|
||||||
|
const QLocale *locale) const
|
||||||
|
{
|
||||||
|
d->collectResourceFilesForSourceFile(sourceFile, res, locale);
|
||||||
|
}
|
||||||
|
|
||||||
/*! \brief returns the errors found while parsing
|
/*! \brief returns the errors found while parsing
|
||||||
*/
|
*/
|
||||||
QStringList QrcParser::errorMessages() const
|
QStringList QrcParser::errorMessages() const
|
||||||
@@ -297,13 +312,12 @@ bool QrcParserPrivate::parseFile(const QString &path)
|
|||||||
accessPath = language + prefix + alias;
|
accessPath = language + prefix + alias;
|
||||||
else
|
else
|
||||||
accessPath = language + prefix + fileName;
|
accessPath = language + prefix + fileName;
|
||||||
if (m_resources.contains(accessPath)) {
|
QStringList &resources = m_resources[accessPath];
|
||||||
QStringList &val = m_resources[accessPath];
|
if (!resources.contains(filePath))
|
||||||
if (!val.contains(filePath))
|
resources.append(filePath);
|
||||||
val.append(filePath);
|
QStringList &files = m_files[filePath];
|
||||||
} else {
|
if (!files.contains(accessPath))
|
||||||
m_resources.insert(accessPath, QStringList(filePath));
|
files.append(accessPath);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -388,6 +402,24 @@ void QrcParserPrivate::collectFilesInPath(const QString &path, QMap<QString,QStr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QrcParserPrivate::collectResourceFilesForSourceFile(const QString &sourceFile,
|
||||||
|
QStringList *results,
|
||||||
|
const QLocale *locale) const
|
||||||
|
{
|
||||||
|
QTC_CHECK(sourceFile.startsWith(QLatin1Char('/')));
|
||||||
|
QTC_CHECK(!sourceFile.endsWith(QLatin1Char('/')));
|
||||||
|
QStringList langs = allUiLanguages(locale);
|
||||||
|
SMap::const_iterator file = m_files.find(sourceFile);
|
||||||
|
if (file == m_files.end())
|
||||||
|
return;
|
||||||
|
foreach (const QString &resource, file.value()) {
|
||||||
|
foreach (const QString &language, langs) {
|
||||||
|
if (resource.startsWith(language) && !results->contains(resource))
|
||||||
|
results->append(resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QStringList QrcParserPrivate::errorMessages() const
|
QStringList QrcParserPrivate::errorMessages() const
|
||||||
{
|
{
|
||||||
return m_errorMessages;
|
return m_errorMessages;
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ public:
|
|||||||
bool hasDirAtPath(const QString &path, const QLocale *locale = 0) const;
|
bool hasDirAtPath(const QString &path, const QLocale *locale = 0) const;
|
||||||
void collectFilesInPath(const QString &path, QMap<QString,QStringList> *res, bool addDirs = false,
|
void collectFilesInPath(const QString &path, QMap<QString,QStringList> *res, bool addDirs = false,
|
||||||
const QLocale *locale = 0) const;
|
const QLocale *locale = 0) const;
|
||||||
|
void collectResourceFilesForSourceFile(const QString &sourceFile, QStringList *results,
|
||||||
|
const QLocale *locale = 0) const;
|
||||||
|
|
||||||
QStringList errorMessages() const;
|
QStringList errorMessages() const;
|
||||||
QStringList languages() const;
|
QStringList languages() const;
|
||||||
bool isValid() const;
|
bool isValid() const;
|
||||||
@@ -60,6 +63,7 @@ public:
|
|||||||
static Ptr parseQrcFile(const QString &path);
|
static Ptr parseQrcFile(const QString &path);
|
||||||
static QString normalizedQrcFilePath(const QString &path);
|
static QString normalizedQrcFilePath(const QString &path);
|
||||||
static QString normalizedQrcDirectoryPath(const QString &path);
|
static QString normalizedQrcDirectoryPath(const QString &path);
|
||||||
|
static QString qrcDirectoryPathForQrcFilePath(const QString &file);
|
||||||
private:
|
private:
|
||||||
QrcParser();
|
QrcParser();
|
||||||
QrcParser(const QrcParser &);
|
QrcParser(const QrcParser &);
|
||||||
|
|||||||
Reference in New Issue
Block a user