diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index 174234f076754dcae26f08018612e58ae03e6d0b..f3c9a9d53fbb4436a522f2a0b52e74eb9ecea548 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -52,7 +52,6 @@ #include <coreplugin/icore.h> #include <coreplugin/editormanager/editormanager.h> -#include <coreplugin/mimedatabase.h> #include <texteditor/itexteditor.h> #include <texteditor/itexteditable.h> #include <texteditor/basetexteditor.h> @@ -1216,29 +1215,13 @@ bool CppCodeCompletion::completeInclude(const QTextCursor &cursor) if (!includePaths.contains(currentFilePath)) includePaths.append(currentFilePath); - const Core::MimeDatabase *mimeDatabase = Core::ICore::instance()->mimeDatabase(); - const Core::MimeType mimeType = mimeDatabase->findByType(QLatin1String("text/x-c++hdr")); - const QStringList suffixes = mimeType.suffixes(); - foreach (const QString &includePath, includePaths) { QString realPath = includePath; if (!directoryPrefix.isEmpty()) { realPath += QLatin1Char('/'); realPath += directoryPrefix; } - // TODO: This should be cached - QDirIterator i(realPath, QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); - while (i.hasNext()) { - const QString fileName = i.next(); - const QFileInfo fileInfo = i.fileInfo(); - const QString suffix = fileInfo.suffix(); - if (suffix.isEmpty() || suffixes.contains(suffix)) { - QString text = fileName.mid(realPath.length() + 1); - if (fileInfo.isDir()) - text += QLatin1Char('/'); - items.append(text); - } - } + items.append(m_manager->includesInPath(realPath)); } if (!items.isEmpty()) { diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index f23fd06209fde0444058e51e4cd22999b6cd7485..c9c529983ca5553f0b947abf5a90d85ee2f4a6ff 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -701,6 +701,16 @@ QByteArray CppModelManager::internalDefinedMacros() const return macros; } +void CppModelManager::setIncludesInPaths(const QMap<QString, QStringList> includesInPaths) +{ + QMutexLocker locker(&mutex); + QMapIterator<QString, QStringList> i(includesInPaths); + while (i.hasNext()) { + i.next(); + m_includesInPaths.insert(i.key(), i.value()); + } +} + void CppModelManager::addEditorSupport(AbstractEditorSupport *editorSupport) { m_addtionalEditorSupport.insert(editorSupport); @@ -763,6 +773,23 @@ void CppModelManager::updateProjectInfo(const ProjectInfo &pinfo) m_projects.insert(pinfo.project, pinfo); m_dirty = true; + + QFuture<void> result = QtConcurrent::run(&CppModelManager::updateIncludesInPaths, + this, + pinfo.includePaths, + m_headerSuffixes); + + if (pinfo.includePaths.size() > 1) { + m_core->progressManager()->addTask(result, tr("Scanning"), + CppTools::Constants::TASK_INDEX, + Core::ProgressManager::CloseOnSuccess); + } +} + +QStringList CppModelManager::includesInPath(const QString &path) const +{ + QMutexLocker locker(&mutex); + return m_includesInPaths.value(path); } QFuture<void> CppModelManager::refreshSourceFiles(const QStringList &sourceFiles) @@ -1064,6 +1091,64 @@ void CppModelManager::onSessionUnloaded() GC(); } +void CppModelManager::updateIncludesInPaths(QFutureInterface<void> &future, + CppModelManager *manager, + QStringList paths, + QStringList suffixes) +{ + QMap<QString, QStringList> entriesInPaths; + int processed = 0; + + future.setProgressRange(0, paths.size()); + + while (!paths.isEmpty()) { + if (future.isPaused()) + future.waitForResume(); + + if (future.isCanceled()) + break; + + const QString path = paths.takeFirst(); + QStringList entries; + + QDirIterator i(path, QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); + while (i.hasNext()) { + const QString fileName = i.next(); + const QFileInfo fileInfo = i.fileInfo(); + const QString suffix = fileInfo.suffix(); + if (suffix.isEmpty() || suffixes.contains(suffix)) { + QString text = fileName.mid(path.length() + 1); + if (fileInfo.isDir()) { + text += QLatin1Char('/'); + + // Also scan subdirectory, but avoid endless recursion with symbolic links + if (fileInfo.isSymLink()) { + QMap<QString, QStringList>::const_iterator result = entriesInPaths.find(fileInfo.canonicalFilePath()); + if (result != entriesInPaths.constEnd()) { + entriesInPaths.insert(fileName, result.value()); + } else { + paths.append(fileName); + } + } else { + paths.append(fileName); + } + } + entries.append(text); + } + } + + entriesInPaths.insert(path, entries); + + ++processed; + future.setProgressRange(0, processed + paths.size()); + future.setProgressValue(processed); + } + + manager->setIncludesInPaths(entriesInPaths); + + future.reportFinished(); +} + void CppModelManager::parse(QFutureInterface<void> &future, CppPreprocessor *preproc, QStringList files) diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h index a662618809e8db447ff80e11452d80ef2c53bbdd..e911971773e7a941702e5f7964293ab052042051 100644 --- a/src/plugins/cpptools/cppmodelmanager.h +++ b/src/plugins/cpptools/cppmodelmanager.h @@ -77,6 +77,8 @@ public: virtual ProjectInfo projectInfo(ProjectExplorer::Project *project) const; virtual void updateProjectInfo(const ProjectInfo &pinfo); + virtual QStringList includesInPath(const QString &path) const; + virtual CPlusPlus::Snapshot snapshot() const; virtual void GC(); @@ -99,6 +101,9 @@ public: virtual void addEditorSupport(AbstractEditorSupport *editorSupport); virtual void removeEditorSupport(AbstractEditorSupport *editorSupport); + void setHeaderSuffixes(const QStringList &suffixes) + { m_headerSuffixes = suffixes; } + Q_SIGNALS: void projectPathChanged(const QString &projectPath); @@ -149,6 +154,13 @@ private: QStringList internalFrameworkPaths() const; QByteArray internalDefinedMacros() const; + void setIncludesInPaths(const QMap<QString, QStringList> includesInPaths); + + static void updateIncludesInPaths(QFutureInterface<void> &future, + CppModelManager *manager, + QStringList paths, + QStringList suffixes); + static void parse(QFutureInterface<void> &future, CppPreprocessor *preproc, QStringList files); @@ -164,6 +176,9 @@ private: QStringList m_frameworkPaths; QByteArray m_definedMacros; + QMap<QString, QStringList> m_includesInPaths; + QStringList m_headerSuffixes; + // editor integration QMap<TextEditor::ITextEditor *, CppEditorSupport *> m_editorSupport; diff --git a/src/plugins/cpptools/cppmodelmanagerinterface.h b/src/plugins/cpptools/cppmodelmanagerinterface.h index ce56686858137cbe9337a16e64b9d8a4dbb0c0ea..463e77a3679e8f7c858720f2fe7641653074a732 100644 --- a/src/plugins/cpptools/cppmodelmanagerinterface.h +++ b/src/plugins/cpptools/cppmodelmanagerinterface.h @@ -90,6 +90,8 @@ public: virtual ProjectInfo projectInfo(ProjectExplorer::Project *project) const = 0; virtual void updateProjectInfo(const ProjectInfo &pinfo) = 0; + virtual QStringList includesInPath(const QString &path) const = 0; + virtual void addEditorSupport(AbstractEditorSupport *editorSupport) = 0; virtual void removeEditorSupport(AbstractEditorSupport *editorSupport) = 0; }; diff --git a/src/plugins/cpptools/cpptoolsplugin.cpp b/src/plugins/cpptools/cpptoolsplugin.cpp index 30858508d44059a7ed05351620c000453196db2f..210419b92083281f1010957c5e61276cef7efad1 100644 --- a/src/plugins/cpptools/cpptoolsplugin.cpp +++ b/src/plugins/cpptools/cpptoolsplugin.cpp @@ -263,6 +263,11 @@ void CppToolsPlugin::extensionsInitialized() m_fileSettings->fromSettings(Core::ICore::instance()->settings()); if (!m_fileSettings->applySuffixesToMimeDB()) qWarning("Unable to apply cpp suffixes to mime database (cpp mime types not found).\n"); + + // Initialize header suffixes + const Core::MimeDatabase *mimeDatabase = Core::ICore::instance()->mimeDatabase(); + const Core::MimeType mimeType = mimeDatabase->findByType(QLatin1String("text/x-c++hdr")); + m_modelManager->setHeaderSuffixes(mimeType.suffixes()); } void CppToolsPlugin::shutdown()