diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp index 5cb7b0a163b..4c892216a56 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -49,7 +50,7 @@ #include #include #include -#include +#include #include @@ -362,6 +363,32 @@ bool pInfoLessThanAll(const ModelManagerInterface::ProjectInfo &p1, const ModelM } return false; } + +bool pInfoLessThanImports(const ModelManagerInterface::ProjectInfo &p1, const ModelManagerInterface::ProjectInfo &p2) +{ + if (p1.qtQmlPath < p2.qtQmlPath) + return true; + if (p1.qtQmlPath > p2.qtQmlPath) + return false; + if (p1.qtImportsPath < p2.qtImportsPath) + return true; + if (p1.qtImportsPath > p2.qtImportsPath) + return false; + QStringList s1 = p1.importPaths; + QStringList s2 = p2.importPaths; + if (s1.size() < s2.size()) + return true; + if (s1.size() > s2.size()) + return false; + for (int i = 0; i < s1.size(); ++i) { + if (s1.at(i) < s2.at(i)) + return true; + else if (s1.at(i) > s2.at(i)) + return false; + } + return false; +} + } QStringList ModelManagerInterface::filesAtQrcPath(const QString &path, const QLocale *locale, @@ -531,14 +558,32 @@ void ModelManagerInterface::removeProjectInfo(ProjectExplorer::Project *project) } } -ModelManagerInterface::ProjectInfo ModelManagerInterface::projectInfoForPath(QString path) +ModelManagerInterface::ProjectInfo ModelManagerInterface::projectInfoForPath(QString path) const { - QMutexLocker locker(&m_mutex); + QList projects; + { + QMutexLocker locker(&m_mutex); + projects = m_fileToProject.values(path); + } + QList infos; + foreach (ProjectExplorer::Project *project, projects) { + ProjectInfo info = projectInfo(project); + if (info.isValid()) + infos.append(info); + } + std::sort(infos.begin(), infos.end(), &pInfoLessThanImports); - foreach (const ProjectInfo &p, m_projects) - if (p.sourceFiles.contains(path)) - return p; - return ProjectInfo(); + ProjectInfo res; + foreach (const ProjectInfo &pInfo, infos) { + if (res.qtImportsPath.isEmpty()) + res.qtImportsPath = pInfo.qtImportsPath; + if (res.qtQmlPath.isEmpty()) + res.qtQmlPath = pInfo.qtQmlPath; + foreach (const QString &path, pInfo.importPaths) + if (res.importPaths.contains(path)) + res.importPaths.append(path); + } + return res; } void ModelManagerInterface::emitDocumentChangedOnDisk(Document::Ptr doc) @@ -1003,21 +1048,26 @@ void ModelManagerInterface::updateImportPaths() QStringList allImportPaths; QmlLanguageBundles activeBundles; QmlLanguageBundles extendedBundles; - QMapIterator it(m_projects); - while (it.hasNext()) { - it.next(); - foreach (const QString &path, it.value().importPaths) { + QMapIterator pInfoIter(m_projects); + QHashIterator vCtxsIter = m_defaultVContexts; + while (pInfoIter.hasNext()) { + pInfoIter.next(); + foreach (const QString &path, pInfoIter.value().importPaths) { const QString canonicalPath = QFileInfo(path).canonicalFilePath(); if (!canonicalPath.isEmpty()) allImportPaths += canonicalPath; } } - it.toFront(); - while (it.hasNext()) { - it.next(); - activeBundles.mergeLanguageBundles(it.value().activeBundle); - foreach (Language::Enum l, it.value().activeBundle.languages()) { - foreach (const QString &path, it.value().activeBundle.bundleForLanguage(l) + while (vCtxsIter.hasNext()) { + vCtxsIter.next(); + allImportPaths << vCtxsIter.value().paths; + } + pInfoIter.toFront(); + while (pInfoIter.hasNext()) { + pInfoIter.next(); + activeBundles.mergeLanguageBundles(pInfoIter.value().activeBundle); + foreach (Language::Enum l, pInfoIter.value().activeBundle.languages()) { + foreach (const QString &path, pInfoIter.value().activeBundle.bundleForLanguage(l) .searchPaths().stringList()) { const QString canonicalPath = QFileInfo(path).canonicalFilePath(); if (!canonicalPath.isEmpty()) @@ -1025,18 +1075,33 @@ void ModelManagerInterface::updateImportPaths() } } } - it.toFront(); - while (it.hasNext()) { - it.next(); - extendedBundles.mergeLanguageBundles(it.value().extendedBundle); - foreach (Language::Enum l, it.value().extendedBundle.languages()) { - foreach (const QString &path, it.value().extendedBundle.bundleForLanguage(l) - .searchPaths().stringList()) { - const QString canonicalPath = QFileInfo(path).canonicalFilePath(); - if (!canonicalPath.isEmpty()) - allImportPaths += canonicalPath; - } - } + pInfoIter.toFront(); + while (pInfoIter.hasNext()) { + pInfoIter.next(); + QString pathAtt = pInfoIter.value().qtQmlPath; + if (!pathAtt.isEmpty() && allImportPaths.size() > 0 + && allImportPaths.value(allImportPaths.size()) != pathAtt) + allImportPaths.append(pathAtt); + } + { + QString pathAtt = defaultProjectInfo().qtQmlPath; + if (!pathAtt.isEmpty() && allImportPaths.size() > 0 + && allImportPaths.value(allImportPaths.size()) != pathAtt) + allImportPaths.append(pathAtt); + } + pInfoIter.toFront(); + while (pInfoIter.hasNext()) { + pInfoIter.next(); + QString pathAtt = pInfoIter.value().qtImportsPath; + if (!pathAtt.isEmpty() && allImportPaths.size() > 0 + && allImportPaths.value(allImportPaths.size()) != pathAtt) + allImportPaths.append(pathAtt); + } + { + QString pathAtt = defaultProjectInfo().qtImportsPath; + if (!pathAtt.isEmpty() && allImportPaths.size() > 0 + && allImportPaths.value(allImportPaths.size()) != pathAtt) + allImportPaths.append(pathAtt); } allImportPaths += m_defaultImportPaths; allImportPaths.removeDuplicates(); @@ -1064,13 +1129,6 @@ void ModelManagerInterface::updateImportPaths() maybeScan(allImportPaths, Language::Qml); } -ModelManagerInterface::ProjectInfo ModelManagerInterface::defaultProjectInfo() const -{ - if (m_projects.isEmpty()) - return ProjectInfo(); - return m_projects.begin().value(); -} - void ModelManagerInterface::loadPluginTypes(const QString &libraryPath, const QString &importPath, const QString &importUri, const QString &importVersion) { @@ -1185,54 +1243,126 @@ ModelManagerInterface::CppDataHash ModelManagerInterface::cppData() const LibraryInfo ModelManagerInterface::builtins(const Document::Ptr &doc) const { - QList projects = m_fileToProject.values(doc->fileName()); - - ProjectExplorer::Project *project = 0; - foreach (ProjectExplorer::Project *p, projects) { - if (p) { - project = p; - break; - } - } - - if (!project) - return LibraryInfo(); - - QMutexLocker locker(&m_mutex); - ProjectInfo info = m_projects.value(project); + ProjectInfo info = projectInfoForPath(doc->path()); if (!info.isValid()) return LibraryInfo(); - return m_validSnapshot.libraryInfo(info.qtImportsPath); } ViewerContext ModelManagerInterface::completeVContext(const ViewerContext &vCtx, - const Document::Ptr &doc) const + const Document::Ptr &doc) const { - Q_UNUSED(doc); ViewerContext res = vCtx; + + if (vCtx.language == Language::Qml && !doc.isNull() && + (doc->language() == Language::QmlQtQuick1 || doc->language() == Language::QmlQtQuick2)) + res.language = doc->language(); + ProjectInfo info; + if (!doc.isNull()) + info = projectInfoForPath(doc->path()); + ViewerContext defaultVCtx = defaultVContext(res.language, Document::Ptr(0), false); + ProjectInfo defaultInfo = defaultProjectInfo(); + if (info.qtImportsPath.isEmpty()) + info.qtImportsPath = defaultInfo.qtImportsPath; + if (info.qtQmlPath.isEmpty()) + info.qtQmlPath = defaultInfo.qtQmlPath; switch (res.flags) { case ViewerContext::Complete: break; - case ViewerContext::AddQtPath: + case ViewerContext::AddAllPathsAndDefaultSelectors: + res.selectors.append(defaultVCtx.selectors); + // fallthrough case ViewerContext::AddAllPaths: - res.paths << importPaths(); + { + foreach (const QString &path, defaultVCtx.paths) + res.maybeAddPath(path); + switch (res.language) { + case Language::Unknown: + case Language::Qml: + res.maybeAddPath(info.qtQmlPath); + // fallthrough + case Language::QmlQtQuick1: + res.maybeAddPath(info.qtImportsPath); + // fallthrough + case Language::QmlQtQuick2: + { + if (res.language == Language::QmlQtQuick2) + res.maybeAddPath(info.qtQmlPath); + QList allProjects; + { + QMutexLocker locker(&m_mutex); + allProjects = m_projects.values(); + } + std::sort(allProjects.begin(), allProjects.end(), &pInfoLessThanImports); + foreach (const ProjectInfo &pInfo, allProjects) { + foreach (const QString &path, pInfo.importPaths) + res.maybeAddPath(path); + } + break; + } + case Language::JavaScript: + case Language::QmlTypeInfo: + case Language::Json: + case Language::QmlQbs: + case Language::QmlProject: + break; + } + break; + } + case ViewerContext::AddDefaultPathsAndSelectors: + res.selectors.append(defaultVCtx.selectors); + // fallthrough + case ViewerContext::AddDefaultPaths: + foreach (const QString &path, defaultVCtx.paths) + res.maybeAddPath(path); + if (res.language == Language::Unknown || res.language == Language::Qml + || res.language == Language::QmlQtQuick2) + res.maybeAddPath(info.qtImportsPath); + if (res.language == Language::Unknown || res.language == Language::Qml + || res.language == Language::QmlQtQuick1) + res.maybeAddPath(info.qtQmlPath); + break; } res.flags = ViewerContext::Complete; return res; } -ViewerContext ModelManagerInterface::defaultVContext(bool autoComplete, const Document::Ptr &doc) const +ViewerContext ModelManagerInterface::defaultVContext(Language::Enum language, + const Document::Ptr &doc, + bool autoComplete) const { + if (!doc.isNull()) { + if (language == Language::Unknown) + language = doc->language(); + else if (language == Language::Qml && + (doc->language() == Language::QmlQtQuick1 || doc->language() == Language::QmlQtQuick2)) + language = doc->language(); + } + ViewerContext defaultCtx; + { + QMutexLocker locker(&m_mutex); + defaultCtx = m_defaultVContexts.value(language); + } if (autoComplete) - return completeVContext(m_vContext, doc); + return completeVContext(defaultCtx, doc); else - return m_vContext; + return defaultCtx; +} + +ModelManagerInterface::ProjectInfo ModelManagerInterface::defaultProjectInfo() const +{ + ProjectInfo res; + res.qtImportsPath = QLibraryInfo::location(QLibraryInfo::ImportsPath); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + res.qtQmlPath = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath); +#endif + return res; } void ModelManagerInterface::setDefaultVContext(const ViewerContext &vContext) { - m_vContext = vContext; + QMutexLocker locker(&m_mutex); + m_defaultVContexts[vContext.language] = vContext; } void ModelManagerInterface::joinAllThreads() diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.h b/src/libs/qmljs/qmljsmodelmanagerinterface.h index 0dc2cb7142b..e8b4748932f 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.h +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.h @@ -177,7 +177,7 @@ public: void updateLibraryInfo(const QString &path, const QmlJS::LibraryInfo &info); void emitDocumentChangedOnDisk(QmlJS::Document::Ptr doc); void updateQrcFile(const QString &path); - ProjectInfo projectInfoForPath(QString path); + ProjectInfo projectInfoForPath(QString path) const; QStringList importPaths() const; QmlJS::QmlLanguageBundles activeBundles() const; @@ -188,17 +188,16 @@ public: CppDataHash cppData() const; LibraryInfo builtins(const Document::Ptr &doc) const; - virtual ViewerContext completeVContext(const ViewerContext &vCtx, - const Document::Ptr &doc = Document::Ptr(0)) const; - virtual ViewerContext defaultVContext(bool autoComplete = true, - const Document::Ptr &doc = Document::Ptr(0)) const; - virtual void setDefaultVContext(const ViewerContext &vContext); + ViewerContext completeVContext(const ViewerContext &vCtx, + const Document::Ptr &doc = Document::Ptr(0)) const; + ViewerContext defaultVContext(Language::Enum language = Language::Qml, + const Document::Ptr &doc = Document::Ptr(0), + bool autoComplete = true) const; + void setDefaultVContext(const ViewerContext &vContext); + virtual ProjectInfo defaultProjectInfo() const; // Blocks until all parsing threads are done. Used for testing. void joinAllThreads(); - - virtual ModelManagerInterface::ProjectInfo defaultProjectInfo() const; - public slots: virtual void resetCodeModel(); void removeProjectInfo(ProjectExplorer::Project *project); @@ -256,7 +255,7 @@ private: QStringList m_defaultImportPaths; QmlJS::QmlLanguageBundles m_activeBundles; QmlJS::QmlLanguageBundles m_extendedBundles; - QmlJS::ViewerContext m_vContext; + QHash m_defaultVContexts; bool m_shouldScanImports; QSet m_scannedPaths; diff --git a/src/libs/qmljs/qmljsviewercontext.cpp b/src/libs/qmljs/qmljsviewercontext.cpp index 3a7e7c945e5..4750c23f53e 100644 --- a/src/libs/qmljs/qmljsviewercontext.cpp +++ b/src/libs/qmljs/qmljsviewercontext.cpp @@ -76,4 +76,10 @@ bool ViewerContext::languageIsCompatible(Language::Enum l) const return true; } +void ViewerContext::maybeAddPath(const QString &path) +{ + if (!path.isEmpty() && !paths.contains(path)) + paths.append(path); +} + } // namespace QmlJS diff --git a/src/libs/qmljs/qmljsviewercontext.h b/src/libs/qmljs/qmljsviewercontext.h index 32a93e9c959..f4b36392268 100644 --- a/src/libs/qmljs/qmljsviewercontext.h +++ b/src/libs/qmljs/qmljsviewercontext.h @@ -42,8 +42,10 @@ class QMLJS_EXPORT ViewerContext public: enum Flags { Complete, + AddAllPathsAndDefaultSelectors, AddAllPaths, - AddQtPath + AddDefaultPaths, + AddDefaultPathsAndSelectors }; ViewerContext(); @@ -52,6 +54,7 @@ public: Flags flags = AddAllPaths); bool languageIsCompatible(Language::Enum l) const; + void maybeAddPath(const QString &path); QStringList selectors; QStringList paths; diff --git a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp index ec6827edcc3..544a03394bd 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp @@ -103,7 +103,7 @@ static inline bool checkIfDerivedFromItem(const QString &fileName) snapshot.insert(document); - QmlJS::Link link(snapshot, modelManager->defaultVContext(), QmlJS::ModelManagerInterface::instance()->builtins(document)); + QmlJS::Link link(snapshot, modelManager->defaultVContext(document->language(), document), QmlJS::ModelManagerInterface::instance()->builtins(document)); QList diagnosticLinkMessages; QmlJS::ContextPtr context = link(document, &diagnosticLinkMessages); diff --git a/src/plugins/qmljseditor/qmljsfindreferences.cpp b/src/plugins/qmljseditor/qmljsfindreferences.cpp index 680d3592370..cbbb44a5d9b 100644 --- a/src/plugins/qmljseditor/qmljsfindreferences.cpp +++ b/src/plugins/qmljseditor/qmljsfindreferences.cpp @@ -831,7 +831,7 @@ static void find_helper(QFutureInterface &future, QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance(); - Link link(snapshot, modelManager->defaultVContext(), modelManager->builtins(doc)); + Link link(snapshot, modelManager->defaultVContext(doc->language(), doc), modelManager->builtins(doc)); ContextPtr context = link(); ScopeChain scopeChain(doc, context); diff --git a/src/plugins/qmljseditor/qmljssemanticinfoupdater.cpp b/src/plugins/qmljseditor/qmljssemanticinfoupdater.cpp index 64b44e49786..84d280aa242 100644 --- a/src/plugins/qmljseditor/qmljssemanticinfoupdater.cpp +++ b/src/plugins/qmljseditor/qmljssemanticinfoupdater.cpp @@ -122,7 +122,7 @@ QmlJSTools::SemanticInfo SemanticInfoUpdater::makeNewSemanticInfo(const QmlJS::D ModelManagerInterface *modelManager = ModelManagerInterface::instance(); - Link link(semanticInfo.snapshot, modelManager->defaultVContext(), modelManager->builtins(doc)); + Link link(semanticInfo.snapshot, modelManager->defaultVContext(doc->language(), doc), modelManager->builtins(doc)); semanticInfo.context = link(doc, &semanticInfo.semanticMessages); ScopeChain *scopeChain = new ScopeChain(doc, semanticInfo.context); diff --git a/src/plugins/qmljseditor/qmltaskmanager.cpp b/src/plugins/qmljseditor/qmltaskmanager.cpp index 496720e15a9..0b54640fdce 100644 --- a/src/plugins/qmljseditor/qmltaskmanager.cpp +++ b/src/plugins/qmljseditor/qmltaskmanager.cpp @@ -161,7 +161,7 @@ void QmlTaskManager::updateMessagesNow(bool updateSemantic) QFuture future = QtConcurrent::run( &collectMessages, modelManager->newestSnapshot(), modelManager->projectInfos(), - modelManager->defaultVContext(), updateSemantic); + modelManager->defaultVContext(Language::Unknown), updateSemantic); m_messageCollector.setFuture(future); } diff --git a/src/plugins/qmljstools/qmljsmodelmanager.cpp b/src/plugins/qmljstools/qmljsmodelmanager.cpp index 51144b8dbc9..a124733e39f 100644 --- a/src/plugins/qmljstools/qmljsmodelmanager.cpp +++ b/src/plugins/qmljstools/qmljsmodelmanager.cpp @@ -61,6 +61,8 @@ #include #include #include +#include +#include #include @@ -87,8 +89,8 @@ ModelManagerInterface::ProjectInfo QmlJSTools::defaultProjectInfoForProject( globs.append(MimeGlobPattern(QLatin1String("*.qmltypes"))); globs.append(MimeGlobPattern(QLatin1String("*.qmlproject"))); } - foreach (const QString &filePath - , project->files(ProjectExplorer::Project::ExcludeGeneratedFiles)) + foreach (const QString &filePath, + project->files(ProjectExplorer::Project::ExcludeGeneratedFiles)) foreach (const MimeGlobPattern &glob, globs) if (glob.matches(filePath)) projectInfo.sourceFiles << filePath; @@ -117,6 +119,12 @@ ModelManagerInterface::ProjectInfo QmlJSTools::defaultProjectInfoForProject( projectInfo.qtQmlPath = qtVersion->qmakeProperty("QT_INSTALL_QML"); projectInfo.qtImportsPath = qtVersion->qmakeProperty("QT_INSTALL_IMPORTS"); projectInfo.qtVersionString = qtVersion->qtVersionString(); + } else { +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + projectInfo.qtQmlPath = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath); +#endif + projectInfo.qtImportsPath = QLibraryInfo::location(QLibraryInfo::ImportsPath); + projectInfo.qtVersionString = QLatin1String(qVersion()); } if (projectInfo.tryQmlDump) { @@ -251,11 +259,9 @@ ModelManagerInterface::WorkingCopy ModelManager::workingCopyInternal() const ModelManagerInterface::ProjectInfo ModelManager::defaultProjectInfo() const { - ProjectExplorer::Project *activeProject = ProjectExplorer::SessionManager::startupProject(); - if (!activeProject) - return ModelManagerInterface::ProjectInfo(); - - return projectInfo(activeProject); + // needs to be performed in the ui therad (change?) + ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectExplorerPlugin::currentProject(); + return defaultProjectInfoForProject(currentProject); } // Check whether fileMimeType is the same or extends knownMimeType @@ -279,4 +285,3 @@ void ModelManager::addTaskInternal(QFuture result, const QString &msg, con { ProgressManager::addTask(result, msg, taskId); } -