diff --git a/src/libs/utils/fileinprojectfinder.cpp b/src/libs/utils/fileinprojectfinder.cpp index 1450b7bef69..a4170bbbf38 100644 --- a/src/libs/utils/fileinprojectfinder.cpp +++ b/src/libs/utils/fileinprojectfinder.cpp @@ -36,6 +36,8 @@ #include #include +#include + enum { debug = false }; namespace Utils { @@ -212,20 +214,19 @@ QString FileInProjectFinder::findFile(const QUrl &fileUrl, bool *success) const } } - // find (solely by filename) in project files + // find best matching file path in project files if (debug) qDebug() << "FileInProjectFinder: checking project files ..."; - const QString fileName = FileName::fromString(originalPath).fileName(); - foreach (const QString &f, m_projectFiles) { - if (FileName::fromString(f).fileName() == fileName) { - m_cache.insert(originalPath, f); - if (success) - *success = true; - if (debug) - qDebug() << "FileInProjectFinder: found" << f << "in project files"; - return f; - } + const QString matchedFilePath + = bestMatch( + filesWithSameFileName(FileName::fromString(originalPath).fileName()), + originalPath); + if (!matchedFilePath.isEmpty()) { + m_cache.insert(originalPath, matchedFilePath); + if (success) + *success = true; + return matchedFilePath; } if (debug) @@ -252,4 +253,44 @@ QString FileInProjectFinder::findFile(const QUrl &fileUrl, bool *success) const return originalPath; } +QStringList FileInProjectFinder::filesWithSameFileName(const QString &fileName) const +{ + QStringList result; + foreach (const QString &f, m_projectFiles) { + if (FileName::fromString(f).fileName() == fileName) + result << f; + } + return result; +} + +int FileInProjectFinder::rankFilePath(const QString &candidatePath, const QString &filePathToFind) +{ + int rank = 0; + for (int a = candidatePath.length(), b = filePathToFind.length(); + --a >= 0 && --b >= 0 && candidatePath.at(a) == filePathToFind.at(b);) + rank++; + return rank; +} + +QString FileInProjectFinder::bestMatch(const QStringList &filePaths, const QString &filePathToFind) +{ + if (filePaths.isEmpty()) + return QString(); + if (filePaths.length() == 1) { + if (debug) + qDebug() << "FileInProjectFinder: found" << filePaths.first() << "in project files"; + return filePaths.first(); + } + auto it = std::max_element(filePaths.constBegin(), filePaths.constEnd(), + [&filePathToFind] (const QString &a, const QString &b) -> bool { + return rankFilePath(a, filePathToFind) < rankFilePath(b, filePathToFind); + }); + if (it != filePaths.cend()) { + if (debug) + qDebug() << "FileInProjectFinder: found best match" << *it << "in project files"; + return *it; + } + return QString(); +} + } // namespace Utils diff --git a/src/libs/utils/fileinprojectfinder.h b/src/libs/utils/fileinprojectfinder.h index dd4072584fe..6c2ce9fcec4 100644 --- a/src/libs/utils/fileinprojectfinder.h +++ b/src/libs/utils/fileinprojectfinder.h @@ -54,6 +54,10 @@ public: QString findFile(const QUrl &fileUrl, bool *success = 0) const; private: + QStringList filesWithSameFileName(const QString &fileName) const; + static int rankFilePath(const QString &candidatePath, const QString &filePathToFind); + static QString bestMatch(const QStringList &filePaths, const QString &filePathToFind); + QString m_projectDir; QString m_sysroot; QStringList m_projectFiles;