forked from qt-creator/qt-creator
Utils: improve readability of FileInProjectFinder
Preserve existing functionality, but split the large findFileOrDirectory logic into check* helper methods Change-Id: Ib7f1d1cebc001d014261616e15e4a87f6d01e8ac Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -15,8 +15,6 @@
|
||||
#include <QMenu>
|
||||
#include <QUrl>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
static Q_LOGGING_CATEGORY(finderLog, "qtc.utils.fileinprojectfinder", QtWarningMsg);
|
||||
}
|
||||
@@ -161,24 +159,32 @@ bool FileInProjectFinder::handleSuccess(const FilePath &originalPath, const File
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileInProjectFinder::findFileOrDirectory(const FilePath &originalPath, FileHandler fileHandler,
|
||||
bool FileInProjectFinder::checkRootDirectory(const FilePath &originalPath,
|
||||
DirectoryHandler directoryHandler) const
|
||||
{
|
||||
if (originalPath.isEmpty()) {
|
||||
qCDebug(finderLog) << "FileInProjectFinder: malformed original path, returning";
|
||||
if (!directoryHandler)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (directoryHandler && originalPath == m_projectDir && originalPath.isDir()) {
|
||||
const QStringList realEntries = QDir(originalPath.toFSPathString())
|
||||
if (originalPath != m_projectDir || !originalPath.isDir())
|
||||
return false;
|
||||
|
||||
const QString originalFSPath = originalPath.toFSPathString();
|
||||
const QStringList realEntries = QDir(originalFSPath)
|
||||
.entryList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
|
||||
directoryHandler(realEntries, originalPath.toFSPathString().size());
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto segments = originalPath.toFSPathString().split('/', Qt::SkipEmptyParts);
|
||||
directoryHandler(realEntries, originalFSPath.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileInProjectFinder::checkMappedPath(const FilePath &originalPath,
|
||||
FileHandler fileHandler,
|
||||
DirectoryHandler directoryHandler) const
|
||||
{
|
||||
const QString origFsPath = originalPath.toFSPathString();
|
||||
const auto segments = origFsPath.split('/', Qt::SkipEmptyParts);
|
||||
|
||||
const PathMappingNode *node = &m_pathMapRoot;
|
||||
for (const auto &segment : segments) {
|
||||
for (const QString &segment : segments) {
|
||||
auto it = node->children.find(segment);
|
||||
if (it == node->children.end()) {
|
||||
node = nullptr;
|
||||
@@ -186,13 +192,14 @@ bool FileInProjectFinder::findFileOrDirectory(const FilePath &originalPath, File
|
||||
}
|
||||
node = *it;
|
||||
}
|
||||
if (!node)
|
||||
return false;
|
||||
|
||||
const int origLength = origFsPath.size();
|
||||
|
||||
const int origLength = originalPath.toFSPathString().length();
|
||||
if (node) {
|
||||
if (!node->localPath.isEmpty()) {
|
||||
if (checkPath(node->localPath, origLength, fileHandler, directoryHandler)) {
|
||||
return handleSuccess(originalPath, {node->localPath}, origLength,
|
||||
"in mapped paths");
|
||||
return handleSuccess(originalPath, {node->localPath}, origLength, "in mapped paths");
|
||||
}
|
||||
} else if (directoryHandler) {
|
||||
directoryHandler(node->children.keys(), origLength);
|
||||
@@ -200,12 +207,18 @@ bool FileInProjectFinder::findFileOrDirectory(const FilePath &originalPath, File
|
||||
<< "in mapped paths";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileInProjectFinder::checkCache(const FilePath &originalPath,
|
||||
FileHandler fileHandler,
|
||||
DirectoryHandler directoryHandler) const
|
||||
{
|
||||
auto it = m_cache.find(originalPath);
|
||||
if (it != m_cache.end()) {
|
||||
if (it == m_cache.end())
|
||||
return false;
|
||||
|
||||
qCDebug(finderLog) << "FileInProjectFinder: checking cache ...";
|
||||
// check if cached path is still there
|
||||
CacheEntry &candidate = it.value();
|
||||
for (auto pathIt = candidate.paths.begin(); pathIt != candidate.paths.end();) {
|
||||
if (checkPath(*pathIt, candidate.matchLength, fileHandler, directoryHandler)) {
|
||||
@@ -215,16 +228,28 @@ bool FileInProjectFinder::findFileOrDirectory(const FilePath &originalPath, File
|
||||
pathIt = candidate.paths.erase(pathIt);
|
||||
}
|
||||
}
|
||||
|
||||
if (!candidate.paths.empty())
|
||||
return true;
|
||||
m_cache.erase(it);
|
||||
}
|
||||
|
||||
if (!m_projectDir.isEmpty()) {
|
||||
m_cache.erase(it);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileInProjectFinder::checkProjectDirectory(const FilePath &originalPath,
|
||||
FileHandler fileHandler,
|
||||
DirectoryHandler directoryHandler) const
|
||||
{
|
||||
if (m_projectDir.isEmpty())
|
||||
return false;
|
||||
|
||||
qCDebug(finderLog) << "FileInProjectFinder: checking project directory ...";
|
||||
|
||||
int prefixToIgnore = -1;
|
||||
const QString origFsPath = originalPath.toFSPathString();
|
||||
const int origLength = origFsPath.size();
|
||||
const QChar separator = QLatin1Char('/');
|
||||
|
||||
int prefixToIgnore = -1;
|
||||
if (originalPath.startsWith(m_projectDir.toFSPathString() + separator)) {
|
||||
if (originalPath.osType() == OsTypeMac) {
|
||||
// starting with the project path is not sufficient if the file was
|
||||
@@ -233,99 +258,138 @@ bool FileInProjectFinder::findFileOrDirectory(const FilePath &originalPath, File
|
||||
if (originalPath.contains(appResourcePath)) {
|
||||
// the path is inside the project, but most probably as a resource of an insource build
|
||||
// so ignore that path
|
||||
prefixToIgnore = originalPath.toFSPathString().indexOf(appResourcePath) + appResourcePath.length();
|
||||
prefixToIgnore = origFsPath.indexOf(appResourcePath) + appResourcePath.length();
|
||||
}
|
||||
}
|
||||
|
||||
if (prefixToIgnore == -1
|
||||
&& checkPath(originalPath, origLength, fileHandler, directoryHandler)) {
|
||||
return handleSuccess(originalPath, {originalPath}, origLength,
|
||||
"in project directory");
|
||||
return handleSuccess(originalPath, {originalPath}, origLength, "in project directory");
|
||||
}
|
||||
}
|
||||
|
||||
qCDebug(finderLog) << "FileInProjectFinder:"
|
||||
<< "checking stripped paths in project directory ...";
|
||||
qCDebug(finderLog) << "FileInProjectFinder: checking stripped paths in project directory ...";
|
||||
|
||||
// Strip directories one by one from the beginning of the path,
|
||||
// and see if the new relative path exists in the build directory.
|
||||
if (prefixToIgnore < 0) {
|
||||
if (!originalPath.isAbsolutePath()
|
||||
&& !originalPath.startsWith(separator)) {
|
||||
if (!originalPath.isAbsolutePath() && !originalPath.startsWith(separator)) {
|
||||
prefixToIgnore = 0;
|
||||
} else {
|
||||
prefixToIgnore = originalPath.toFSPathString().indexOf(separator);
|
||||
prefixToIgnore = origFsPath.indexOf(separator);
|
||||
}
|
||||
}
|
||||
|
||||
// Repeatedly strip directories from the front
|
||||
while (prefixToIgnore != -1) {
|
||||
QString candidateString = originalPath.toFSPathString();
|
||||
QString candidateString = origFsPath;
|
||||
candidateString.remove(0, prefixToIgnore);
|
||||
candidateString.prepend(m_projectDir.toUrlishString());
|
||||
const FilePath candidate = FilePath::fromString(candidateString);
|
||||
const int matchLength = origLength - prefixToIgnore;
|
||||
// FIXME: This might be a worse match than what we find later.
|
||||
if (checkPath(candidate, matchLength, fileHandler, directoryHandler)) {
|
||||
return handleSuccess(originalPath, {candidate}, matchLength,
|
||||
"in project directory");
|
||||
return handleSuccess(originalPath, {candidate}, matchLength, "in project directory");
|
||||
}
|
||||
prefixToIgnore = originalPath.toUrlishString().indexOf(separator, prefixToIgnore + 1);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// find best matching file path in project files
|
||||
bool FileInProjectFinder::checkProjectFiles(const FilePath &originalPath,
|
||||
FileHandler fileHandler,
|
||||
DirectoryHandler directoryHandler) const
|
||||
{
|
||||
qCDebug(finderLog) << "FileInProjectFinder: checking project files ...";
|
||||
|
||||
QStringList matches;
|
||||
const QString lastSegment = originalPath.fileName();
|
||||
QStringList matches;
|
||||
if (fileHandler)
|
||||
matches.append(filesWithSameFileName(lastSegment));
|
||||
if (directoryHandler)
|
||||
matches.append(pathSegmentsWithSameName(lastSegment));
|
||||
|
||||
const QStringList matchedFilePaths = bestMatches(matches, originalPath.toUrlishString());
|
||||
if (!matchedFilePaths.empty()) {
|
||||
if (matchedFilePaths.isEmpty())
|
||||
return false;
|
||||
|
||||
const int matchLength = commonPostFixLength(matchedFilePaths.first(), originalPath.toUrlishString());
|
||||
FilePaths hits;
|
||||
for (const QString &matchedFilePath : matchedFilePaths) {
|
||||
if (checkPath(FilePath::fromString(matchedFilePath), matchLength, fileHandler, directoryHandler))
|
||||
hits.append(FilePath::fromString(matchedFilePath));
|
||||
}
|
||||
if (!hits.empty())
|
||||
return handleSuccess(originalPath, hits, matchLength, "when matching project files");
|
||||
}
|
||||
if (hits.isEmpty())
|
||||
return false;
|
||||
|
||||
CacheEntry foundPath = findInSearchPaths(originalPath, fileHandler, directoryHandler);
|
||||
if (!foundPath.paths.isEmpty()) {
|
||||
return handleSuccess(originalPath, foundPath.paths, foundPath.matchLength,
|
||||
return handleSuccess(originalPath, hits, matchLength, "when matching project files");
|
||||
}
|
||||
|
||||
bool FileInProjectFinder::checkSearchPaths(const FilePath &originalPath,
|
||||
FileHandler fileHandler,
|
||||
DirectoryHandler directoryHandler) const
|
||||
{
|
||||
for (const FilePath &dirPath : m_searchDirectories) {
|
||||
const CacheEntry found = findInSearchPath(dirPath, originalPath,
|
||||
fileHandler, directoryHandler);
|
||||
|
||||
if (!found.paths.isEmpty()) {
|
||||
return handleSuccess(originalPath, found.paths, found.matchLength,
|
||||
"in search path");
|
||||
}
|
||||
|
||||
qCDebug(finderLog) << "FileInProjectFinder: checking absolute path in sysroot ...";
|
||||
|
||||
// check if absolute path is found in sysroot
|
||||
if (!m_sysroot.isEmpty()) {
|
||||
const FilePath sysrootPath = m_sysroot.pathAppended(originalPath.toUrlishString());
|
||||
if (checkPath(sysrootPath, origLength, fileHandler, directoryHandler)) {
|
||||
return handleSuccess(originalPath, {sysrootPath}, origLength, "in sysroot");
|
||||
}
|
||||
}
|
||||
|
||||
qCDebug(finderLog) << "FileInProjectFinder: couldn't find file!";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
FileInProjectFinder::CacheEntry FileInProjectFinder::findInSearchPaths(
|
||||
const FilePath &filePath, FileHandler fileHandler, DirectoryHandler directoryHandler) const
|
||||
bool FileInProjectFinder::checkSysroot(const FilePath &originalPath,
|
||||
FileHandler fileHandler,
|
||||
DirectoryHandler directoryHandler) const
|
||||
{
|
||||
for (const FilePath &dirPath : m_searchDirectories) {
|
||||
const CacheEntry found = findInSearchPath(dirPath, filePath,
|
||||
fileHandler, directoryHandler);
|
||||
if (!found.paths.isEmpty())
|
||||
return found;
|
||||
qCDebug(finderLog) << "FileInProjectFinder: checking absolute path in sysroot ...";
|
||||
|
||||
if (m_sysroot.isEmpty())
|
||||
return false;
|
||||
|
||||
const int origLength = originalPath.toFSPathString().length();
|
||||
const FilePath sysrootPath = m_sysroot.pathAppended(originalPath.toUrlishString());
|
||||
|
||||
if (!checkPath(sysrootPath, origLength, fileHandler, directoryHandler))
|
||||
return false;
|
||||
|
||||
return handleSuccess(originalPath, {sysrootPath}, origLength, "in sysroot");
|
||||
}
|
||||
|
||||
bool FileInProjectFinder::findFileOrDirectory(const FilePath &originalPath,
|
||||
FileHandler fileHandler,
|
||||
DirectoryHandler directoryHandler) const
|
||||
{
|
||||
if (originalPath.isEmpty()) {
|
||||
qCDebug(finderLog) << "FileInProjectFinder: malformed original path, returning";
|
||||
return false;
|
||||
}
|
||||
|
||||
return CacheEntry();
|
||||
if (checkRootDirectory(originalPath, directoryHandler))
|
||||
return true;
|
||||
|
||||
if (checkMappedPath(originalPath, fileHandler, directoryHandler))
|
||||
return true;
|
||||
|
||||
if (checkCache(originalPath, fileHandler, directoryHandler))
|
||||
return true;
|
||||
|
||||
if (checkProjectDirectory(originalPath, fileHandler, directoryHandler))
|
||||
return true;
|
||||
|
||||
if (checkProjectFiles(originalPath, fileHandler, directoryHandler))
|
||||
return true;
|
||||
|
||||
if (checkSearchPaths(originalPath, fileHandler, directoryHandler))
|
||||
return true;
|
||||
|
||||
if (checkSysroot(originalPath, fileHandler, directoryHandler))
|
||||
return true;
|
||||
|
||||
qCDebug(finderLog) << "FileInProjectFinder: couldn't find file!";
|
||||
return false;
|
||||
}
|
||||
|
||||
static QString chopFirstDir(const QString &dirPath)
|
||||
|
@@ -62,13 +62,30 @@ private:
|
||||
mutable QHash<FilePath, std::shared_ptr<QrcParser>> m_parserCache;
|
||||
};
|
||||
|
||||
CacheEntry findInSearchPaths(const FilePath &filePath, FileHandler fileHandler,
|
||||
DirectoryHandler directoryHandler) const;
|
||||
static CacheEntry findInSearchPath(const FilePath &searchPath, const FilePath &filePath,
|
||||
FileHandler fileHandler, DirectoryHandler directoryHandler);
|
||||
QStringList filesWithSameFileName(const QString &fileName) const;
|
||||
QStringList pathSegmentsWithSameName(const QString &path) const;
|
||||
|
||||
bool checkRootDirectory(const FilePath &originalPath, DirectoryHandler directoryHandler) const;
|
||||
bool checkMappedPath(const FilePath &originalPath,
|
||||
FileHandler fileHandler,
|
||||
DirectoryHandler directoryHandler) const;
|
||||
bool checkCache(const FilePath &originalPath,
|
||||
FileHandler fileHandler,
|
||||
DirectoryHandler directoryHandler) const;
|
||||
bool checkProjectDirectory(const FilePath &originalPath,
|
||||
FileHandler fileHandler,
|
||||
DirectoryHandler directoryHandler) const;
|
||||
bool checkProjectFiles(const FilePath &originalPath,
|
||||
FileHandler fileHandler,
|
||||
DirectoryHandler directoryHandler) const;
|
||||
bool checkSearchPaths(const FilePath &originalPath,
|
||||
FileHandler fileHandler,
|
||||
DirectoryHandler directoryHandler) const;
|
||||
bool checkSysroot(const FilePath &originalPath,
|
||||
FileHandler fileHandler,
|
||||
DirectoryHandler directoryHandler) const;
|
||||
bool handleSuccess(const FilePath &originalPath, const FilePaths &found, int confidence,
|
||||
const char *where) const;
|
||||
|
||||
|
Reference in New Issue
Block a user