QQmlCodeModel::addFileWatches: don't warn for already watched files

Don't emit a warning for files that are already watched in
QQmlCodeModel::addFileWatches, add a parameter to
findFilePathsFromFileNames and findFilePathFromFileName to filter out
unwanted filePaths from the result.

Change-Id: Ic71229723952852437ea01d0d7e5c2ae1c53ac1c
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
Sami Shalayel 2025-08-22 14:15:24 +02:00
parent e0e4b12250
commit 7232c76aeb
11 changed files with 118 additions and 29 deletions

View File

@ -347,7 +347,8 @@ return all the found file paths.
This is an overapproximation and might find unrelated files with the same name.
*/
QStringList QQmlCodeModel::findFilePathsFromFileNames(const QStringList &_fileNamesToSearch)
QStringList QQmlCodeModel::findFilePathsFromFileNames(const QStringList &_fileNamesToSearch,
const QSet<QString> &ignoredFilePaths)
{
QStringList fileNamesToSearch{ _fileNamesToSearch };
@ -364,9 +365,8 @@ QStringList QQmlCodeModel::findFilePathsFromFileNames(const QStringList &_fileNa
const QString rootDir = QUrl(QString::fromUtf8(m_rootUrl)).toLocalFile();
qCDebug(codeModelLog) << "Searching for files to watch in workspace folder" << rootDir;
const QStringList result =
QQmlLSUtils::findFilePathsFromFileNames(rootDir, fileNamesToSearch);
QQmlLSUtils::findFilePathsFromFileNames(rootDir, fileNamesToSearch, ignoredFilePaths);
QMutexLocker guard(&m_mutex);
for (const auto &fileName : fileNamesToSearch) {
@ -423,7 +423,13 @@ are modified.
void QQmlCodeModel::addFileWatches(const DomItem &qmlFile)
{
const auto filesToWatch = fileNamesToWatch(qmlFile);
const QStringList filepathsToWatch = findFilePathsFromFileNames(filesToWatch);
// remove already watched files to avoid a warning later on
const QStringList alreadyWatchedFiles = m_cppFileWatcher.files();
const QSet<QString> alreadyWatchedFilesSet(alreadyWatchedFiles.begin(),
alreadyWatchedFiles.end());
QStringList filepathsToWatch = findFilePathsFromFileNames(filesToWatch, alreadyWatchedFilesSet);
if (filepathsToWatch.isEmpty())
return;

View File

@ -125,7 +125,8 @@ public:
QStringList importPaths() const;
void setImportPaths(const QStringList &paths);
QQmlToolingSharedSettings *settings() const { return m_settings; }
QStringList findFilePathsFromFileNames(const QStringList &fileNames);
QStringList findFilePathsFromFileNames(const QStringList &fileNames,
const QSet<QString> &alreadyWatchedFiles);
static QStringList fileNamesToWatch(const QQmlJS::Dom::DomItem &qmlFile);
void disableCMakeCalls();

View File

@ -1994,7 +1994,7 @@ static std::optional<Location> createCppTypeLocation(const QQmlJSScope::ConstPtr
const QStringList &headerLocations,
const QQmlJS::SourceLocation &location)
{
const QString filePath = findFilePathFromFileName(headerLocations, type->filePath());
const QString filePath = findFilePathFromFileName(headerLocations, type->filePath(), {});
if (filePath.isEmpty()) {
qCWarning(QQmlLSUtilsLog) << "Couldn't find the C++ file '%1'."_L1.arg(type->filePath());
return {};
@ -2553,7 +2553,8 @@ RenameUsages::RenameUsages(const QList<Edit> &renamesInFile,
enum SearchOption { FindFirst, FindAll };
static QStringList findFilePathsFromFileNamesImpl(const QStringList &rootDirs,
const QStringList &fileNamesToSearch,
SearchOption option)
SearchOption option,
const QSet<QString> &ignoredFilePaths)
{
if (fileNamesToSearch.isEmpty() || rootDirs.isEmpty())
return {};
@ -2594,25 +2595,31 @@ static QStringList findFilePathsFromFileNamesImpl(const QStringList &rootDirs,
if (!fileNamesToSearch.contains(entry.fileName()))
continue;
result << entry.absoluteFilePath();
if (ignoredFilePaths.contains(entry.absoluteFilePath()))
continue;
if (option == FindFirst)
return result;
return { entry.absoluteFilePath() };
result << entry.absoluteFilePath();
}
}
return result;
}
QStringList findFilePathsFromFileNames(const QString &rootDir,
const QStringList &fileNamesToSearch)
QStringList findFilePathsFromFileNames(const QString &rootDir, const QStringList &fileNamesToSearch,
const QSet<QString> &ignoredFilePaths)
{
return findFilePathsFromFileNamesImpl({ rootDir }, fileNamesToSearch, FindAll);
return findFilePathsFromFileNamesImpl({ rootDir }, fileNamesToSearch, FindAll,
ignoredFilePaths);
}
QString findFilePathFromFileName(const QStringList &rootDirs, const QString &fileNameToSearch)
QString findFilePathFromFileName(const QStringList &rootDirs, const QString &fileNameToSearch,
const QSet<QString> &ignoredFilePaths)
{
const QStringList result =
findFilePathsFromFileNamesImpl(rootDirs, { fileNameToSearch }, FindFirst);
const QStringList result = findFilePathsFromFileNamesImpl(rootDirs, { fileNameToSearch },
FindFirst, ignoredFilePaths);
return result.isEmpty() ? QString{} : result.front();
}

View File

@ -296,9 +296,10 @@ QQmlJSScope::ConstPtr findDefiningScopeForEnumeration(const QQmlJSScope::ConstPt
const QString &nameToCheck);
QQmlJSScope::ConstPtr findDefiningScopeForEnumerationKey(const QQmlJSScope::ConstPtr &referrerScope,
const QString &nameToCheck);
QStringList findFilePathsFromFileNames(const QString &rootDir,
const QStringList &fileNamesToSearch);
QString findFilePathFromFileName(const QStringList &rootDirs, const QString &fileNameToSearch);
QStringList findFilePathsFromFileNames(const QString &rootDir, const QStringList &fileNamesToSearch,
const QSet<QString> &ignoredPaths);
QString findFilePathFromFileName(const QStringList &rootDirs, const QString &fileNameToSearch,
const QSet<QString> &ignoredPaths);
} // namespace QQmlLSUtils
QT_END_NAMESPACE

View File

@ -75,26 +75,33 @@ void tst_qmlls_qqmlcodemodel::findFilePathsFromFileNames_data()
QTest::addColumn<QStringList>("fileNames");
QTest::addColumn<QStringList>("expectedPaths");
QTest::addColumn<QSet<QString>>("missingFiles");
QTest::addColumn<QSet<QString>>("alreadyWatchedFiles");
const QString folder = testFile("sourceFolder");
const QString subfolder = testFile("sourceFolder/subSourceFolder/subsubSourceFolder");
const QSet<QString> noMissingFiles;
const QSet<QString> noAlreadyWatchedFiles;
QTest::addRow("notExistingFile") << QStringList{ u"notExistingFile.h"_s } << QStringList{}
<< QSet<QString>{ u"notExistingFile.h"_s };
QTest::addRow("notExistingFile")
<< QStringList{ u"notExistingFile.h"_s } << QStringList{}
<< QSet<QString>{ u"notExistingFile.h"_s } << noAlreadyWatchedFiles;
QTest::addRow("myqmlelement") << QStringList{ u"myqmlelement.h"_s }
<< QStringList{ folder + u"/myqmlelement.h"_s,
subfolder + u"/myqmlelement.h"_s }
<< noMissingFiles;
<< noMissingFiles << noAlreadyWatchedFiles;
QTest::addRow("myqmlelement2")
<< QStringList{ u"myqmlelement2.hpp"_s }
<< QStringList{ folder + u"/myqmlelement2.hpp"_s } << noMissingFiles;
QTest::addRow("myqmlelementAlreadyWatched")
<< QStringList{ u"myqmlelement.h"_s } << QStringList{ folder + u"/myqmlelement.h"_s }
<< noMissingFiles << QSet<QString>{ subfolder + u"/myqmlelement.h"_s };
QTest::addRow("anotherqmlelement")
<< QStringList{ u"anotherqmlelement.cpp"_s }
<< QStringList{ subfolder + u"/anotherqmlelement.cpp"_s } << noMissingFiles;
QTest::addRow("myqmlelement2") << QStringList{ u"myqmlelement2.hpp"_s }
<< QStringList{ folder + u"/myqmlelement2.hpp"_s }
<< noMissingFiles << noAlreadyWatchedFiles;
QTest::addRow("anotherqmlelement") << QStringList{ u"anotherqmlelement.cpp"_s }
<< QStringList{ subfolder + u"/anotherqmlelement.cpp"_s }
<< noMissingFiles << noAlreadyWatchedFiles;
}
void tst_qmlls_qqmlcodemodel::findFilePathsFromFileNames()
@ -102,10 +109,11 @@ void tst_qmlls_qqmlcodemodel::findFilePathsFromFileNames()
QFETCH(QStringList, fileNames);
QFETCH(QStringList, expectedPaths);
QFETCH(QSet<QString>, missingFiles);
QFETCH(QSet<QString>, alreadyWatchedFiles);
QmlLsp::QQmlCodeModel model(testFileUrl(u"sourceFolder"_s).toEncoded());
auto result = model.findFilePathsFromFileNames(fileNames);
auto result = model.findFilePathsFromFileNames(fileNames, alreadyWatchedFiles);
// the order only is required for the QCOMPARE
std::sort(result.begin(), result.end());

View File

@ -4629,7 +4629,68 @@ void tst_qmlls_utils::maxFilesToSearch()
"\" after reaching QMLLS_MAX_FILES_TO_SEARCH (currently set to 1111). Set "
"the environment variable \"QMLLS_MAX_FILES_TO_SEARCH\" to a higher value "
"to spend more time on searching.");
QQmlLSUtils::findFilePathsFromFileNames(QT_QMLLS_BIG_FOLDER ""_L1, { "qt"_L1, "qwer"_L1 });
QQmlLSUtils::findFilePathsFromFileNames(QT_QMLLS_BIG_FOLDER ""_L1, { "qt"_L1, "qwer"_L1 }, {});
}
void tst_qmlls_utils::findFilePathsFromFileNames_data()
{
QTest::addColumn<QSet<QString>>("ignored");
QTest::addColumn<QStringList>("expected");
QTest::addRow("all") << QSet<QString>()
<< QStringList{
testFile("findFilePathsFromFileNames/HelloWorld.txt"_L1),
testFile("findFilePathsFromFileNames/a/HelloWorld.txt"_L1),
testFile("findFilePathsFromFileNames/a/b/HelloWorld.txt"_L1),
testFile("findFilePathsFromFileNames/a/b/c/HelloWorld.txt"_L1),
};
QTest::addRow("ignore3")
<< QSet<QString> {
testFile("findFilePathsFromFileNames/a/HelloWorld.txt"_L1),
testFile("findFilePathsFromFileNames/a/b/HelloWorld.txt"_L1),
}
<< QStringList{
testFile("findFilePathsFromFileNames/HelloWorld.txt"_L1),
testFile("findFilePathsFromFileNames/a/b/c/HelloWorld.txt"_L1),
};
}
void tst_qmlls_utils::findFilePathsFromFileNames()
{
QFETCH(QSet<QString>, ignored);
QFETCH(QStringList, expected);
QStringList filePaths = QQmlLSUtils::findFilePathsFromFileNames(
testFile("findFilePathsFromFileNames"_L1), { "HelloWorld.txt"_L1 }, ignored);
std::sort(filePaths.begin(), filePaths.end());
std::sort(expected.begin(), expected.end());
QCOMPARE(filePaths, expected);
}
void tst_qmlls_utils::findFilePathFromFileName_data()
{
QTest::addColumn<QSet<QString>>("ignored");
QTest::addColumn<QString>("expected");
QTest::addRow("withoutIgnore")
<< QSet<QString>() << testFile("findFilePathsFromFileNames/HelloWorld.txt"_L1);
QTest::addRow("withIgnore") << QSet<QString>{
testFile("findFilePathsFromFileNames/HelloWorld.txt"_L1),
testFile("findFilePathsFromFileNames/a/HelloWorld.txt"_L1),
testFile("findFilePathsFromFileNames/a/b/HelloWorld.txt"_L1),
} << testFile("findFilePathsFromFileNames/a/b/c/HelloWorld.txt"_L1);
}
void tst_qmlls_utils::findFilePathFromFileName()
{
QFETCH(QSet<QString>, ignored);
QFETCH(QString, expected);
QString filePaths = QQmlLSUtils::findFilePathFromFileName(
{ testFile("findFilePathsFromFileNames"_L1) }, { "HelloWorld.txt"_L1 }, ignored);
QCOMPARE(filePaths, expected);
}
QTEST_MAIN(tst_qmlls_utils)

View File

@ -81,6 +81,11 @@ private slots:
void cmakeBuildCommand();
void maxFilesToSearch();
void findFilePathsFromFileNames_data();
void findFilePathsFromFileNames();
void findFilePathFromFileName_data();
void findFilePathFromFileName();
private:
using EnvironmentAndFile = std::tuple<QQmlJS::Dom::DomItem, QQmlJS::Dom::DomItem>;