CompilationDatabase: Ask for the root path and scan for headers

Let's use the same approach we have for CMake projects by using
the same TreeScanner class.

Compilation database does not have a concept of the root directory
so let's show a file dialog and ask for it the first time the project
is loaded. Next times we open it we take this path from settings.
This root path can later be changed from the project tree context menu.

Fixes: QTCREATORBUG-22031
Change-Id: I151aed8d0504b2e8aa14aa774cad25f8c86d5c17
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Ivan Donchevskii
2019-03-14 15:34:14 +01:00
committed by hjk
parent d34eb692fe
commit 2c5808bada
16 changed files with 197 additions and 47 deletions

View File

@@ -29,9 +29,10 @@
#include "compilationdatabaseutils.h"
#include <coreplugin/icontext.h>
#include <cpptools/projectinfo.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <cpptools/cppkitinfo.h>
#include <cpptools/cppprojectupdater.h>
#include <cpptools/projectinfo.h>
#include <projectexplorer/gcctoolchain.h>
#include <projectexplorer/headerpath.h>
#include <projectexplorer/kitinformation.h>
@@ -47,6 +48,7 @@
#include <utils/qtcassert.h>
#include <utils/runextensions.h>
#include <QFileDialog>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
@@ -283,13 +285,17 @@ FileType fileTypeForName(const QString &fileName)
void createTree(FolderNode *root,
const Utils::FileName &rootPath,
const CppTools::RawProjectParts &rpps)
const CppTools::RawProjectParts &rpps,
const QList<FileNode *> &scannedFiles = QList<FileNode *>())
{
root->setAbsoluteFilePathAndLine(rootPath, -1);
for (const CppTools::RawProjectPart &rpp : rpps) {
for (const QString &filePath : rpp.files) {
Utils::FileName fileName = Utils::FileName::fromString(filePath);
if (!fileName.isChildOf(rootPath))
continue;
FolderNode *parentNode = createFoldersIfNeeded(root, fileName.parentDir());
if (!parentNode->fileNode(fileName)) {
parentNode->addNode(std::make_unique<FileNode>(fileName,
@@ -297,6 +303,22 @@ void createTree(FolderNode *root,
}
}
}
for (FileNode *node : scannedFiles) {
if (node->fileType() != FileType::Header)
continue;
const Utils::FileName fileName = node->filePath();
if (!fileName.isChildOf(rootPath))
continue;
FolderNode *parentNode = createFoldersIfNeeded(root, fileName.parentDir());
if (!parentNode->fileNode(fileName)) {
std::unique_ptr<FileNode> headerNode(node->clone());
headerNode->setEnabled(false);
parentNode->addNode(std::move(headerNode));
}
}
qDeleteAll(scannedFiles);
}
struct Entry
@@ -354,7 +376,6 @@ void CompilationDatabaseProject::buildTreeAndProjectParts(const Utils::FileName
CppTools::KitInfo kitInfo(this);
QTC_ASSERT(kitInfo.isValid(), return);
CppTools::RawProjectParts rpps;
Utils::FileName commonPath;
std::sort(array.begin(), array.end(), [](const Entry &lhs, const Entry &rhs) {
return std::lexicographical_compare(lhs.flags.begin(), lhs.flags.end(),
@@ -370,10 +391,6 @@ void CompilationDatabaseProject::buildTreeAndProjectParts(const Utils::FileName
prevEntry = &entry;
commonPath = rpps.empty()
? entry.fileName.parentDir()
: Utils::FileUtils::commonPath(commonPath, entry.fileName);
CppTools::RawProjectPart rpp = makeRawProjectPart(projectFile,
m_kit.get(),
kitInfo.cToolChain,
@@ -385,7 +402,13 @@ void CompilationDatabaseProject::buildTreeAndProjectParts(const Utils::FileName
rpps.append(rpp);
}
createTree(root.get(), commonPath, rpps);
m_treeScanner.future().waitForFinished();
QCoreApplication::processEvents();
if (m_treeScanner.future().isCanceled())
createTree(root.get(), rootProjectDirectory(), rpps);
else
createTree(root.get(), rootProjectDirectory(), rpps, m_treeScanner.release());
root->addNode(std::make_unique<FileNode>(projectFile, FileType::Project));
@@ -407,7 +430,6 @@ CompilationDatabaseProject::CompilationDatabaseProject(const Utils::FileName &pr
setPreferredKitPredicate([](const Kit *) { return false; });
m_kit.reset(KitManager::defaultKit()->clone());
connect(this, &CompilationDatabaseProject::parsingFinished, this, [this]() {
if (!m_hasTarget) {
addTarget(createTarget(m_kit.get()));
@@ -415,22 +437,75 @@ CompilationDatabaseProject::CompilationDatabaseProject(const Utils::FileName &pr
}
});
reparseProject(projectFile);
m_treeScanner.setFilter([this](const Utils::MimeType &mimeType, const Utils::FileName &fn) {
// Mime checks requires more resources, so keep it last in check list
auto isIgnored = fn.toString().startsWith(projectFilePath().toString() + ".user")
|| TreeScanner::isWellKnownBinary(mimeType, fn);
// Cache mime check result for speed up
if (!isIgnored) {
auto it = m_mimeBinaryCache.find(mimeType.name());
if (it != m_mimeBinaryCache.end()) {
isIgnored = *it;
} else {
isIgnored = TreeScanner::isMimeBinary(mimeType, fn);
m_mimeBinaryCache[mimeType.name()] = isIgnored;
}
}
return isIgnored;
});
m_treeScanner.setTypeFactory([](const Utils::MimeType &mimeType, const Utils::FileName &fn) {
return TreeScanner::genericFileType(mimeType, fn);
});
connect(this,
&CompilationDatabaseProject::rootProjectDirectoryChanged,
this,
&CompilationDatabaseProject::reparseProject);
m_fileSystemWatcher.addFile(projectFile.toString(), Utils::FileSystemWatcher::WatchModifiedDate);
connect(&m_fileSystemWatcher,
&Utils::FileSystemWatcher::fileChanged,
this,
[this](const QString &projectFile) {
reparseProject(Utils::FileName::fromString(projectFile));
});
&CompilationDatabaseProject::reparseProject);
}
void CompilationDatabaseProject::reparseProject(const Utils::FileName &projectFile)
Project::RestoreResult CompilationDatabaseProject::fromMap(const QVariantMap &map,
QString *errorMessage)
{
Project::RestoreResult result = Project::fromMap(map, errorMessage);
if (result == Project::RestoreResult::Ok) {
const Utils::FileName rootPath = Utils::FileName::fromString(
namedSettings(ProjectExplorer::Constants::PROJECT_ROOT_PATH_KEY).toString());
if (rootPath.isEmpty())
changeRootProjectDirectory(); // This triggers reparse itself.
else
reparseProject();
}
return result;
}
void CompilationDatabaseProject::reparseProject()
{
emitParsingStarted();
const Utils::FileName rootPath = Utils::FileName::fromString(
namedSettings(ProjectExplorer::Constants::PROJECT_ROOT_PATH_KEY).toString());
if (!rootPath.isEmpty()) {
m_treeScanner.asyncScanForFiles(rootPath);
Core::ProgressManager::addTask(m_treeScanner.future(),
tr("Scan \"%1\" project tree").arg(displayName()),
"CompilationDatabase.Scan.Tree");
}
const QFuture<void> future = ::Utils::runAsync(
[this, projectFile]() { buildTreeAndProjectParts(projectFile); });
[this]() { buildTreeAndProjectParts(projectFilePath()); });
Core::ProgressManager::addTask(future,
tr("Parse \"%1\" project").arg(displayName()),
"CompilationDatabase.Parse");
m_parserWatcher.setFuture(future);
}

View File

@@ -26,6 +26,7 @@
#pragma once
#include <projectexplorer/project.h>
#include <projectexplorer/treescanner.h>
#include <texteditor/texteditor.h>
#include <utils/filesystemwatcher.h>
@@ -35,7 +36,9 @@ namespace CppTools {
class CppProjectUpdater;
}
namespace ProjectExplorer { class Kit; }
namespace ProjectExplorer {
class Kit;
}
namespace CompilationDatabaseProjectManager {
namespace Internal {
@@ -51,13 +54,16 @@ public:
bool needsBuildConfigurations() const override { return false; }
private:
void reparseProject(const Utils::FileName &projectFile);
RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) override;
void reparseProject();
void buildTreeAndProjectParts(const Utils::FileName &projectFile);
QFutureWatcher<void> m_parserWatcher;
std::unique_ptr<CppTools::CppProjectUpdater> m_cppCodeModelUpdater;
std::unique_ptr<ProjectExplorer::Kit> m_kit;
Utils::FileSystemWatcher m_fileSystemWatcher;
ProjectExplorer::TreeScanner m_treeScanner;
QHash<QString, bool> m_mimeBinaryCache;
bool m_hasTarget = false;
};

View File

@@ -29,13 +29,21 @@
#include "compilationdatabaseproject.h"
#include "compilationdatabasetests.h"
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/fileiconprovider.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectmanager.h>
#include <projectexplorer/projecttree.h>
#include <projectexplorer/session.h>
#include <utils/utilsicons.h>
namespace CompilationDatabaseProjectManager {
namespace Internal {
const char CHANGEROOTDIR[] = "CompilationDatabaseProjectManager.ChangeRootDirectory";
bool CompilationDatabaseProjectManagerPlugin::initialize(const QStringList &arguments, QString *errorMessage)
{
Q_UNUSED(arguments);
@@ -45,10 +53,39 @@ bool CompilationDatabaseProjectManagerPlugin::initialize(const QStringList &argu
ProjectExplorer::ProjectManager::registerProjectType<CompilationDatabaseProject>(
Constants::COMPILATIONDATABASEMIMETYPE);
m_changeProjectRootDirectoryAction = new QAction(tr("Change Root Directory"), this);
Core::Command *cmd = Core::ActionManager::registerAction(m_changeProjectRootDirectoryAction,
CHANGEROOTDIR);
Core::ActionContainer *mprojectContextMenu = Core::ActionManager::actionContainer(
ProjectExplorer::Constants::M_PROJECTCONTEXT);
mprojectContextMenu->addSeparator(ProjectExplorer::Constants::G_PROJECT_TREE);
mprojectContextMenu->addAction(cmd, ProjectExplorer::Constants::G_PROJECT_TREE);
connect(m_changeProjectRootDirectoryAction,
&QAction::triggered,
ProjectExplorer::ProjectTree::instance(),
&ProjectExplorer::ProjectTree::changeProjectRootDirectory);
connect(ProjectExplorer::SessionManager::instance(),
&ProjectExplorer::SessionManager::startupProjectChanged,
this,
&CompilationDatabaseProjectManagerPlugin::projectChanged);
connect(ProjectExplorer::ProjectTree::instance(),
&ProjectExplorer::ProjectTree::currentProjectChanged,
this,
&CompilationDatabaseProjectManagerPlugin::projectChanged);
return true;
}
void CompilationDatabaseProjectManagerPlugin::projectChanged()
{
const auto *currentProject = qobject_cast<CompilationDatabaseProject *>(
ProjectExplorer::ProjectTree::currentProject());
m_changeProjectRootDirectoryAction->setEnabled(currentProject);
}
void CompilationDatabaseProjectManagerPlugin::extensionsInitialized()
{
}

View File

@@ -43,9 +43,12 @@ public:
bool initialize(const QStringList &arguments, QString *errorMessage) final;
void extensionsInitialized() final;
private:
void projectChanged();
QList<QObject *> createTestObjects() const final;
CompilationDatabaseEditorFactory factory;
QAction *m_changeProjectRootDirectoryAction;
};
} // namespace Internal