Resolve ambiguous results of searches for relative file paths

Qt Creator extracts file names from the output of external processes in
various places, for instance from compilers during the build. It often
happens that such file names are not absolute, so they cannot be
directly opened in an editor when the user clicks on their
representation in some widget. That's why they are processed by the
FileInProjectFinder facility first.
This patch enhances the FileInProjectFinder to be able to return more
than one candidate for a relative file path, and allows the user to
choose between these candidates where possible. This way, we won't open
a random file anymore when a project contains more than one file with
the same name.

Fixes: QTCREATORBUG-13623
Change-Id: Id19c9eace3e6b3dbde89f6528e6d02b55872d747
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Christian Kandeler
2019-02-25 17:45:39 +01:00
parent b0e125ac11
commit d0db212575
13 changed files with 133 additions and 79 deletions

View File

@@ -31,11 +31,13 @@
#include "qrcparser.h" #include "qrcparser.h"
#include "qtcassert.h" #include "qtcassert.h"
#include <QCursor>
#include <QDebug> #include <QDebug>
#include <QDir>
#include <QFileInfo> #include <QFileInfo>
#include <QLoggingCategory> #include <QLoggingCategory>
#include <QMenu>
#include <QUrl> #include <QUrl>
#include <QDir>
#include <algorithm> #include <algorithm>
@@ -140,12 +142,12 @@ void FileInProjectFinder::addMappedPath(const FileName &localFilePath, const QSt
folder specified. Third, we walk the list of project files, and search for a file name match folder specified. Third, we walk the list of project files, and search for a file name match
there. If all fails, it returns the original path from the file URL. there. If all fails, it returns the original path from the file URL.
*/ */
QString FileInProjectFinder::findFile(const QUrl &fileUrl, bool *success) const FileNameList FileInProjectFinder::findFile(const QUrl &fileUrl, bool *success) const
{ {
qCDebug(finderLog) << "FileInProjectFinder: trying to find file" << fileUrl.toString() << "..."; qCDebug(finderLog) << "FileInProjectFinder: trying to find file" << fileUrl.toString() << "...";
if (fileUrl.scheme() == "qrc" || fileUrl.toString().startsWith(':')) { if (fileUrl.scheme() == "qrc" || fileUrl.toString().startsWith(':')) {
const QString result = m_qrcUrlFinder.find(fileUrl); const FileNameList result = m_qrcUrlFinder.find(fileUrl);
if (!result.isEmpty()) { if (!result.isEmpty()) {
if (success) if (success)
*success = true; *success = true;
@@ -157,10 +159,12 @@ QString FileInProjectFinder::findFile(const QUrl &fileUrl, bool *success) const
if (originalPath.isEmpty()) // e.g. qrc:// if (originalPath.isEmpty()) // e.g. qrc://
originalPath = fileUrl.path(); originalPath = fileUrl.path();
QString result = originalPath; FileNameList result;
bool found = findFileOrDirectory(originalPath, [&](const QString &fileName, int) { bool found = findFileOrDirectory(originalPath, [&](const QString &fileName, int) {
result = fileName; result << FileName::fromString(fileName);
}); });
if (!found)
result << FileName::fromString(originalPath);
if (success) if (success)
*success = found; *success = found;
@@ -168,12 +172,12 @@ QString FileInProjectFinder::findFile(const QUrl &fileUrl, bool *success) const
return result; return result;
} }
bool FileInProjectFinder::handleSuccess(const QString &originalPath, const QString &found, bool FileInProjectFinder::handleSuccess(const QString &originalPath, const QStringList &found,
int matchLength, const char *where) const int matchLength, const char *where) const
{ {
qCDebug(finderLog) << "FileInProjectFinder: found" << found << where; qCDebug(finderLog) << "FileInProjectFinder: found" << found << where;
CacheEntry entry; CacheEntry entry;
entry.path = found; entry.paths = found;
entry.matchLength = matchLength; entry.matchLength = matchLength;
m_cache.insert(originalPath, entry); m_cache.insert(originalPath, entry);
return true; return true;
@@ -202,8 +206,10 @@ bool FileInProjectFinder::findFileOrDirectory(const QString &originalPath, FileH
if (node) { if (node) {
if (!node->localPath.isEmpty()) { if (!node->localPath.isEmpty()) {
const QString localPath = node->localPath.toString(); const QString localPath = node->localPath.toString();
if (checkPath(localPath, origLength, fileHandler, directoryHandler)) if (checkPath(localPath, origLength, fileHandler, directoryHandler)) {
return handleSuccess(originalPath, localPath, origLength, "in mapped paths"); return handleSuccess(originalPath, QStringList(localPath), origLength,
"in mapped paths");
}
} else if (directoryHandler) { } else if (directoryHandler) {
directoryHandler(node->children.keys(), origLength); directoryHandler(node->children.keys(), origLength);
qCDebug(finderLog) << "FileInProjectFinder: found virtual directory" << originalPath qCDebug(finderLog) << "FileInProjectFinder: found virtual directory" << originalPath
@@ -216,14 +222,19 @@ bool FileInProjectFinder::findFileOrDirectory(const QString &originalPath, FileH
if (it != m_cache.end()) { if (it != m_cache.end()) {
qCDebug(finderLog) << "FileInProjectFinder: checking cache ..."; qCDebug(finderLog) << "FileInProjectFinder: checking cache ...";
// check if cached path is still there // check if cached path is still there
const CacheEntry &candidate = it.value(); CacheEntry &candidate = it.value();
if (checkPath(candidate.path, candidate.matchLength, fileHandler, directoryHandler)) { for (auto pathIt = candidate.paths.begin(); pathIt != candidate.paths.end();) {
qCDebug(finderLog) << "FileInProjectFinder: found" << candidate.path << "in the cache"; if (checkPath(*pathIt, candidate.matchLength, fileHandler, directoryHandler)) {
return true; qCDebug(finderLog) << "FileInProjectFinder: found" << *pathIt << "in the cache";
++pathIt;
} else { } else {
m_cache.erase(it); pathIt = candidate.paths.erase(pathIt);
} }
} }
if (!candidate.paths.empty())
return true;
m_cache.erase(it);
}
if (!m_projectDir.isEmpty()) { if (!m_projectDir.isEmpty()) {
qCDebug(finderLog) << "FileInProjectFinder: checking project directory ..."; qCDebug(finderLog) << "FileInProjectFinder: checking project directory ...";
@@ -244,7 +255,7 @@ bool FileInProjectFinder::findFileOrDirectory(const QString &originalPath, FileH
if (prefixToIgnore == -1 if (prefixToIgnore == -1
&& checkPath(originalPath, origLength, fileHandler, directoryHandler)) { && checkPath(originalPath, origLength, fileHandler, directoryHandler)) {
return handleSuccess(originalPath, originalPath, origLength, return handleSuccess(originalPath, QStringList(originalPath), origLength,
"in project directory"); "in project directory");
} }
} }
@@ -267,8 +278,11 @@ bool FileInProjectFinder::findFileOrDirectory(const QString &originalPath, FileH
candidate.remove(0, prefixToIgnore); candidate.remove(0, prefixToIgnore);
candidate.prepend(m_projectDir.toString()); candidate.prepend(m_projectDir.toString());
const int matchLength = origLength - prefixToIgnore; const int matchLength = origLength - prefixToIgnore;
if (checkPath(candidate, matchLength, fileHandler, directoryHandler)) // FIXME: This might be a worse match than what we find later.
return handleSuccess(originalPath, candidate, matchLength, "in project directory"); if (checkPath(candidate, matchLength, fileHandler, directoryHandler)) {
return handleSuccess(originalPath, QStringList(candidate), matchLength,
"in project directory");
}
prefixToIgnore = originalPath.indexOf(separator, prefixToIgnore + 1); prefixToIgnore = originalPath.indexOf(separator, prefixToIgnore + 1);
} }
} }
@@ -282,17 +296,23 @@ bool FileInProjectFinder::findFileOrDirectory(const QString &originalPath, FileH
matches.append(filesWithSameFileName(lastSegment)); matches.append(filesWithSameFileName(lastSegment));
if (directoryHandler) if (directoryHandler)
matches.append(pathSegmentsWithSameName(lastSegment)); matches.append(pathSegmentsWithSameName(lastSegment));
const QString matchedFilePath = bestMatch(matches, originalPath); const QStringList matchedFilePaths = bestMatches(matches, originalPath);
const int matchLength = commonPostFixLength(matchedFilePath, originalPath); if (!matchedFilePaths.empty()) {
if (!matchedFilePath.isEmpty() const int matchLength = commonPostFixLength(matchedFilePaths.first(), originalPath);
&& checkPath(matchedFilePath, matchLength, fileHandler, directoryHandler)) { QStringList hits;
return handleSuccess(originalPath, matchedFilePath, matchLength, for (const QString &matchedFilePath : matchedFilePaths) {
"when matching project files"); if (checkPath(matchedFilePath, matchLength, fileHandler, directoryHandler))
hits << matchedFilePath;
}
if (!hits.empty())
return handleSuccess(originalPath, hits, matchLength, "when matching project files");
} }
CacheEntry foundPath = findInSearchPaths(originalPath, fileHandler, directoryHandler); CacheEntry foundPath = findInSearchPaths(originalPath, fileHandler, directoryHandler);
if (!foundPath.path.isEmpty()) if (!foundPath.paths.isEmpty()) {
return handleSuccess(originalPath, foundPath.path, foundPath.matchLength, "in search path"); return handleSuccess(originalPath, foundPath.paths, foundPath.matchLength,
"in search path");
}
qCDebug(finderLog) << "FileInProjectFinder: checking absolute path in sysroot ..."; qCDebug(finderLog) << "FileInProjectFinder: checking absolute path in sysroot ...";
@@ -300,8 +320,10 @@ bool FileInProjectFinder::findFileOrDirectory(const QString &originalPath, FileH
if (!m_sysroot.isEmpty()) { if (!m_sysroot.isEmpty()) {
FileName sysrootPath = m_sysroot; FileName sysrootPath = m_sysroot;
sysrootPath.appendPath(originalPath); sysrootPath.appendPath(originalPath);
if (checkPath(sysrootPath.toString(), origLength, fileHandler, directoryHandler)) if (checkPath(sysrootPath.toString(), origLength, fileHandler, directoryHandler)) {
return handleSuccess(originalPath, sysrootPath.toString(), origLength, "in sysroot"); return handleSuccess(originalPath, QStringList(sysrootPath.toString()), origLength,
"in sysroot");
}
} }
qCDebug(finderLog) << "FileInProjectFinder: couldn't find file!"; qCDebug(finderLog) << "FileInProjectFinder: couldn't find file!";
@@ -315,7 +337,7 @@ FileInProjectFinder::CacheEntry FileInProjectFinder::findInSearchPaths(
for (const FileName &dirPath : m_searchDirectories) { for (const FileName &dirPath : m_searchDirectories) {
const CacheEntry found = findInSearchPath(dirPath.toString(), filePath, const CacheEntry found = findInSearchPath(dirPath.toString(), filePath,
fileHandler, directoryHandler); fileHandler, directoryHandler);
if (!found.path.isEmpty()) if (!found.paths.isEmpty())
return found; return found;
} }
@@ -340,17 +362,17 @@ FileInProjectFinder::CacheEntry FileInProjectFinder::findInSearchPath(
QString s = filePath; QString s = filePath;
while (!s.isEmpty()) { while (!s.isEmpty()) {
CacheEntry result; CacheEntry result;
result.path = searchPath + QLatin1Char('/') + s; result.paths << searchPath + '/' + s;
result.matchLength = s.length() + 1; result.matchLength = s.length() + 1;
qCDebug(finderLog) << "FileInProjectFinder: trying" << result.path; qCDebug(finderLog) << "FileInProjectFinder: trying" << result.paths.first();
if (checkPath(result.path, result.matchLength, fileHandler, directoryHandler)) if (checkPath(result.paths.first(), result.matchLength, fileHandler, directoryHandler))
return result; return result;
QString next = chopFirstDir(s); QString next = chopFirstDir(s);
if (next.isEmpty()) { if (next.isEmpty()) {
if (directoryHandler && QFileInfo(searchPath).fileName() == s) { if (directoryHandler && QFileInfo(searchPath).fileName() == s) {
result.path = searchPath; result.paths = QStringList{searchPath};
directoryHandler(QDir(searchPath).entryList(), result.matchLength); directoryHandler(QDir(searchPath).entryList(), result.matchLength);
return result; return result;
} }
@@ -399,24 +421,30 @@ int FileInProjectFinder::commonPostFixLength(const QString &candidatePath,
return rank; return rank;
} }
QString FileInProjectFinder::bestMatch(const QStringList &filePaths, const QString &filePathToFind) QStringList FileInProjectFinder::bestMatches(const QStringList &filePaths,
const QString &filePathToFind)
{ {
if (filePaths.isEmpty()) if (filePaths.isEmpty())
return QString(); return {};
if (filePaths.length() == 1) { if (filePaths.length() == 1) {
qCDebug(finderLog) << "FileInProjectFinder: found" << filePaths.first() qCDebug(finderLog) << "FileInProjectFinder: found" << filePaths.first()
<< "in project files"; << "in project files";
return filePaths.first(); return filePaths;
} }
auto it = std::max_element(filePaths.constBegin(), filePaths.constEnd(), int bestRank = -1;
[&filePathToFind] (const QString &a, const QString &b) -> bool { QStringList bestFilePaths;
return commonPostFixLength(a, filePathToFind) < commonPostFixLength(b, filePathToFind); for (const QString &fp : filePaths) {
}); const int currentRank = commonPostFixLength(fp, filePathToFind);
if (it != filePaths.cend()) { if (currentRank < bestRank)
qCDebug(finderLog) << "FileInProjectFinder: found best match" << *it << "in project files"; continue;
return *it; if (currentRank > bestRank) {
bestRank = currentRank;
bestFilePaths.clear();
} }
return QString(); bestFilePaths << fp;
}
QTC_CHECK(!bestFilePaths.empty());
return bestFilePaths;
} }
FileNameList FileInProjectFinder::searchDirectories() const FileNameList FileInProjectFinder::searchDirectories() const
@@ -434,9 +462,9 @@ FileInProjectFinder::PathMappingNode::~PathMappingNode()
qDeleteAll(children); qDeleteAll(children);
} }
QString FileInProjectFinder::QrcUrlFinder::find(const QUrl &fileUrl) const FileNameList FileInProjectFinder::QrcUrlFinder::find(const QUrl &fileUrl) const
{ {
QString result; FileNameList result;
const auto fileIt = m_fileCache.constFind(fileUrl); const auto fileIt = m_fileCache.constFind(fileUrl);
if (fileIt != m_fileCache.cend()) if (fileIt != m_fileCache.cend())
return fileIt.value(); return fileIt.value();
@@ -448,10 +476,7 @@ QString FileInProjectFinder::QrcUrlFinder::find(const QUrl &fileUrl) const
continue; continue;
QStringList hits; QStringList hits;
qrcParser->collectFilesAtPath(QrcParser::normalizedQrcFilePath(fileUrl.toString()), &hits); qrcParser->collectFilesAtPath(QrcParser::normalizedQrcFilePath(fileUrl.toString()), &hits);
if (!hits.empty()) { result = transform(hits, [](const QString &fp) { return FileName::fromString(fp); });
result = hits.first();
break;
}
} }
m_fileCache.insert(fileUrl, result); m_fileCache.insert(fileUrl, result);
return result; return result;
@@ -464,4 +489,16 @@ void FileInProjectFinder::QrcUrlFinder::setProjectFiles(const FileNameList &proj
m_parserCache.clear(); m_parserCache.clear();
} }
FileName chooseFileFromList(const FileNameList &candidates)
{
if (candidates.length() == 1)
return candidates.first();
QMenu filesMenu;
for (const FileName &candidate : candidates)
filesMenu.addAction(candidate.toUserOutput());
if (const QAction * const action = filesMenu.exec(QCursor::pos()))
return FileName::fromUserInput(action->text());
return FileName();
}
} // namespace Utils } // namespace Utils

View File

@@ -55,7 +55,7 @@ public:
void addMappedPath(const FileName &localFilePath, const QString &remoteFilePath); void addMappedPath(const FileName &localFilePath, const QString &remoteFilePath);
QString findFile(const QUrl &fileUrl, bool *success = nullptr) const; FileNameList findFile(const QUrl &fileUrl, bool *success = nullptr) const;
bool findFileOrDirectory(const QString &originalPath, FileHandler fileHandler = nullptr, bool findFileOrDirectory(const QString &originalPath, FileHandler fileHandler = nullptr,
DirectoryHandler directoryHandler = nullptr) const; DirectoryHandler directoryHandler = nullptr) const;
@@ -71,17 +71,17 @@ private:
}; };
struct CacheEntry { struct CacheEntry {
QString path; QStringList paths;
int matchLength = 0; int matchLength = 0;
}; };
class QrcUrlFinder { class QrcUrlFinder {
public: public:
QString find(const QUrl &fileUrl) const; FileNameList find(const QUrl &fileUrl) const;
void setProjectFiles(const FileNameList &projectFiles); void setProjectFiles(const FileNameList &projectFiles);
private: private:
FileNameList m_allQrcFiles; FileNameList m_allQrcFiles;
mutable QHash<QUrl, QString> m_fileCache; mutable QHash<QUrl, FileNameList> m_fileCache;
mutable QHash<FileName, QSharedPointer<QrcParser>> m_parserCache; mutable QHash<FileName, QSharedPointer<QrcParser>> m_parserCache;
}; };
@@ -92,11 +92,11 @@ private:
QStringList filesWithSameFileName(const QString &fileName) const; QStringList filesWithSameFileName(const QString &fileName) const;
QStringList pathSegmentsWithSameName(const QString &path) const; QStringList pathSegmentsWithSameName(const QString &path) const;
bool handleSuccess(const QString &originalPath, const QString &found, int confidence, bool handleSuccess(const QString &originalPath, const QStringList &found, int confidence,
const char *where) const; const char *where) const;
static int commonPostFixLength(const QString &candidatePath, const QString &filePathToFind); static int commonPostFixLength(const QString &candidatePath, const QString &filePathToFind);
static QString bestMatch(const QStringList &filePaths, const QString &filePathToFind); static QStringList bestMatches(const QStringList &filePaths, const QString &filePathToFind);
FileName m_projectDir; FileName m_projectDir;
FileName m_sysroot; FileName m_sysroot;
@@ -108,4 +108,6 @@ private:
QrcUrlFinder m_qrcUrlFinder; QrcUrlFinder m_qrcUrlFinder;
}; };
QTCREATOR_UTILS_EXPORT FileName chooseFileFromList(const FileNameList &candidates);
} // namespace Utils } // namespace Utils

View File

@@ -218,7 +218,8 @@ void ConsoleView::onRowActivated(const QModelIndex &index)
if (!index.isValid()) if (!index.isValid())
return; return;
const QFileInfo fi(m_finder.findFile(model()->data(index, ConsoleItem::FileRole).toString())); const QFileInfo fi = m_finder.findFile(model()->data(index, ConsoleItem::FileRole).toString())
.first().toFileInfo();
if (fi.exists() && fi.isFile() && fi.isReadable()) { if (fi.exists() && fi.isFile() && fi.isReadable()) {
Core::EditorManager::openEditorAt(fi.canonicalFilePath(), Core::EditorManager::openEditorAt(fi.canonicalFilePath(),
model()->data(index, ConsoleItem::LineRole).toInt()); model()->data(index, ConsoleItem::LineRole).toInt());

View File

@@ -1828,7 +1828,7 @@ QString DebuggerEngine::toFileInProject(const QUrl &fileUrl)
d->m_fileFinder.setAdditionalSearchDirectories(rp.additionalSearchDirectories); d->m_fileFinder.setAdditionalSearchDirectories(rp.additionalSearchDirectories);
d->m_fileFinder.setSysroot(rp.sysRoot); d->m_fileFinder.setSysroot(rp.sysRoot);
return d->m_fileFinder.findFile(fileUrl); return d->m_fileFinder.findFile(fileUrl).first().toString();
} }
QString DebuggerEngine::expand(const QString &string) const QString DebuggerEngine::expand(const QString &string) const

View File

@@ -540,7 +540,7 @@ void PerfProfilerTool::gotoSourceLocation(QString filePath, int lineNumber, int
QFileInfo fi(filePath); QFileInfo fi(filePath);
if (!fi.isAbsolute() || !fi.exists() || !fi.isReadable()) { if (!fi.isAbsolute() || !fi.exists() || !fi.isReadable()) {
fi.setFile(m_fileFinder.findFile(filePath)); fi.setFile(m_fileFinder.findFile(filePath).first().toString());
if (!fi.exists() || !fi.isReadable()) if (!fi.exists() || !fi.isReadable())
return; return;
} }

View File

@@ -29,7 +29,6 @@
#include "session.h" #include "session.h"
#include <utils/fileinprojectfinder.h> #include <utils/fileinprojectfinder.h>
#include <utils/fileutils.h>
#include <QUrl> #include <QUrl>
@@ -43,7 +42,7 @@ class FileInSessionFinder : public QObject
public: public:
FileInSessionFinder(); FileInSessionFinder();
FileName doFindFile(const FileName &filePath); FileNameList doFindFile(const FileName &filePath);
void invalidateFinder() { m_finderIsUpToDate = false; } void invalidateFinder() { m_finderIsUpToDate = false; }
private: private:
@@ -65,7 +64,7 @@ FileInSessionFinder::FileInSessionFinder()
}); });
} }
FileName FileInSessionFinder::doFindFile(const FileName &filePath) FileNameList FileInSessionFinder::doFindFile(const FileName &filePath)
{ {
if (!m_finderIsUpToDate) { if (!m_finderIsUpToDate) {
m_finder.setProjectDirectory(SessionManager::startupProject() m_finder.setProjectDirectory(SessionManager::startupProject()
@@ -77,10 +76,10 @@ FileName FileInSessionFinder::doFindFile(const FileName &filePath)
m_finder.setProjectFiles(allFiles); m_finder.setProjectFiles(allFiles);
m_finderIsUpToDate = true; m_finderIsUpToDate = true;
} }
return FileName::fromString(m_finder.findFile(QUrl::fromLocalFile(filePath.toString()))); return m_finder.findFile(QUrl::fromLocalFile(filePath.toString()));
} }
FileName findFileInSession(const FileName &filePath) FileNameList findFileInSession(const FileName &filePath)
{ {
static FileInSessionFinder finder; static FileInSessionFinder finder;
return finder.doFindFile(filePath); return finder.doFindFile(filePath);

View File

@@ -25,12 +25,12 @@
#pragma once #pragma once
namespace Utils { class FileName; } #include <utils/fileutils.h>
namespace ProjectExplorer { namespace ProjectExplorer {
namespace Internal { namespace Internal {
Utils::FileName findFileInSession(const Utils::FileName &filePath); Utils::FileNameList findFileInSession(const Utils::FileName &filePath);
} // namespace Internal } // namespace Internal
} // namespace ProjectExplorer } // namespace ProjectExplorer

View File

@@ -25,6 +25,7 @@
#include "task.h" #include "task.h"
#include "fileinsessionfinder.h"
#include "projectexplorerconstants.h" #include "projectexplorerconstants.h"
#include <app/app_version.h> #include <app/app_version.h>
@@ -34,6 +35,7 @@
#include <utils/utilsicons.h> #include <utils/utilsicons.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QFileInfo>
#include <QTextStream> #include <QTextStream>
namespace ProjectExplorer namespace ProjectExplorer
@@ -67,6 +69,13 @@ Task::Task(TaskType type_, const QString &description_,
icon(icon.isNull() ? taskTypeIcon(type_) : icon) icon(icon.isNull() ? taskTypeIcon(type_) : icon)
{ {
++s_nextId; ++s_nextId;
if (!file.isEmpty() && !file.toFileInfo().isAbsolute()) {
Utils::FileNameList possiblePaths = Internal::findFileInSession(file);
if (possiblePaths.length() == 1)
file = possiblePaths.first();
else
fileCandidates = possiblePaths;
}
} }
Task Task::compilerMissingTask() Task Task::compilerMissingTask()

View File

@@ -76,6 +76,7 @@ public:
Options options = AddTextMark | FlashWorthy; Options options = AddTextMark | FlashWorthy;
QString description; QString description;
Utils::FileName file; Utils::FileName file;
Utils::FileNameList fileCandidates;
int line = -1; int line = -1;
int movedLine = -1; // contains a line number if the line was moved in the editor int movedLine = -1; // contains a line number if the line was moved in the editor
Core::Id category; Core::Id category;

View File

@@ -104,14 +104,8 @@ bool sortById(const Task &task, unsigned int id)
return task.taskId < id; return task.taskId < id;
} }
void TaskModel::addTask(const Task &t) void TaskModel::addTask(const Task &task)
{ {
Task task = t;
if (!task.file.isEmpty() && !task.file.toFileInfo().isAbsolute()) {
const Utils::FileName fullFilePath = findFileInSession(task.file);
if (!fullFilePath.isEmpty())
task.file = fullFilePath;
}
Q_ASSERT(m_categories.keys().contains(task.category)); Q_ASSERT(m_categories.keys().contains(task.category));
CategoryData &data = m_categories[task.category]; CategoryData &data = m_categories[task.category];
CategoryData &global = m_categories[Core::Id()]; CategoryData &global = m_categories[Core::Id()];

View File

@@ -38,6 +38,7 @@
#include <coreplugin/icontext.h> #include <coreplugin/icontext.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/fileinprojectfinder.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/itemviews.h> #include <utils/itemviews.h>
#include <utils/utilsicons.h> #include <utils/utilsicons.h>
@@ -498,6 +499,15 @@ void TaskWindow::triggerDefaultHandler(const QModelIndex &index)
if (task.isNull()) if (task.isNull())
return; return;
if (!task.file.isEmpty() && !task.file.toFileInfo().isAbsolute()
&& !task.fileCandidates.empty()) {
const Utils::FileName userChoice = Utils::chooseFileFromList(task.fileCandidates);
if (!userChoice.isEmpty()) {
task.file = userChoice;
updatedTaskFileName(task.taskId, task.file.toString());
}
}
if (d->m_defaultHandler->canHandle(task)) { if (d->m_defaultHandler->canHandle(task)) {
d->m_defaultHandler->handle(task); d->m_defaultHandler->handle(task);
} else { } else {

View File

@@ -112,7 +112,7 @@ void QmlProfilerDetailsRewriter::requestDetailsForLocation(int typeId,
QString QmlProfilerDetailsRewriter::getLocalFile(const QString &remoteFile) QString QmlProfilerDetailsRewriter::getLocalFile(const QString &remoteFile)
{ {
const QString localFile = m_projectFinder.findFile(remoteFile); const QString localFile = m_projectFinder.findFile(remoteFile).first().toString();
const QFileInfo fileInfo(localFile); const QFileInfo fileInfo(localFile);
if (!fileInfo.exists() || !fileInfo.isReadable()) if (!fileInfo.exists() || !fileInfo.isReadable())
return QString(); return QString();

View File

@@ -211,13 +211,14 @@ void QtOutputFormatter::handleLink(const QString &href)
":(\\d+)$"); // column ":(\\d+)$"); // column
const QRegularExpressionMatch qmlLineColumnMatch = qmlLineColumnLink.match(href); const QRegularExpressionMatch qmlLineColumnMatch = qmlLineColumnLink.match(href);
const auto getFileToOpen = [this](const QUrl &fileUrl) {
return chooseFileFromList(d->projectFinder.findFile(fileUrl)).toString();
};
if (qmlLineColumnMatch.hasMatch()) { if (qmlLineColumnMatch.hasMatch()) {
const QUrl fileUrl = QUrl(qmlLineColumnMatch.captured(1)); const QUrl fileUrl = QUrl(qmlLineColumnMatch.captured(1));
const int line = qmlLineColumnMatch.captured(2).toInt(); const int line = qmlLineColumnMatch.captured(2).toInt();
const int column = qmlLineColumnMatch.captured(3).toInt(); const int column = qmlLineColumnMatch.captured(3).toInt();
openEditor(getFileToOpen(fileUrl), line, column - 1);
openEditor(d->projectFinder.findFile(fileUrl), line, column - 1);
return; return;
} }
@@ -228,7 +229,7 @@ void QtOutputFormatter::handleLink(const QString &href)
if (qmlLineMatch.hasMatch()) { if (qmlLineMatch.hasMatch()) {
const QUrl fileUrl = QUrl(qmlLineMatch.captured(1)); const QUrl fileUrl = QUrl(qmlLineMatch.captured(1));
const int line = qmlLineMatch.captured(2).toInt(); const int line = qmlLineMatch.captured(2).toInt();
openEditor(d->projectFinder.findFile(fileUrl), line); openEditor(getFileToOpen(fileUrl), line);
return; return;
} }
@@ -257,7 +258,7 @@ void QtOutputFormatter::handleLink(const QString &href)
} }
if (!fileName.isEmpty()) { if (!fileName.isEmpty()) {
fileName = d->projectFinder.findFile(QUrl::fromLocalFile(fileName)); fileName = getFileToOpen(QUrl::fromLocalFile(fileName));
openEditor(fileName, line); openEditor(fileName, line);
return; return;
} }