From 7331f651c1c16217a31f3cdec700f014057b7268 Mon Sep 17 00:00:00 2001 From: Fawzi Mohamed Date: Mon, 9 Aug 2021 12:20:35 +0200 Subject: [PATCH] qmldom: pass optional fileType to loadFile If filetype is given use it to specify the type of the file to load (otherwise guess it from the file extension). Can be used to load qmltypes files as "plain" qml files (for reformatting). Ths enables the reformatting of .qmltypes (for API comparison) Change-Id: Ib65647c2a8dc8b37b7e955acb3aec2193d36666d Pick-to: 6.2 Reviewed-by: Maximilian Goldstein Reviewed-by: Fabian Kosmale --- src/qmldom/qqmldomitem.cpp | 16 ++-- src/qmldom/qqmldomitem_p.h | 8 +- src/qmldom/qqmldomtop.cpp | 147 +++++++++++++++++++----------------- src/qmldom/qqmldomtop_p.h | 13 +++- tools/qmldom/qmldomtool.cpp | 32 ++++---- 5 files changed, 120 insertions(+), 96 deletions(-) diff --git a/src/qmldom/qqmldomitem.cpp b/src/qmldom/qqmldomitem.cpp index e11761c1e1..49fc3fabda 100644 --- a/src/qmldom/qqmldomitem.cpp +++ b/src/qmldom/qqmldomitem.cpp @@ -2288,21 +2288,23 @@ DomItem::DomItem(std::shared_ptr universePtr): } void DomItem::loadFile(QString canonicalFilePath, QString logicalPath, QString code, - QDateTime codeDate, DomTop::Callback callback, LoadOptions loadOptions) + QDateTime codeDate, DomTop::Callback callback, LoadOptions loadOptions, + std::optional fileType) { DomItem topEl = top(); if (topEl.internalKind() == DomType::DomEnvironment || topEl.internalKind() == DomType::DomUniverse) { if (auto univ = topEl.ownerAs()) univ->loadFile(*this, canonicalFilePath, logicalPath, code, codeDate, callback, - loadOptions); + loadOptions, fileType); else if (auto env = topEl.ownerAs()) { if (env->options() & DomEnvironment::Option::NoDependencies) env->loadFile(topEl, canonicalFilePath, logicalPath, code, codeDate, callback, - DomTop::Callback(), DomTop::Callback(), loadOptions); + DomTop::Callback(), DomTop::Callback(), loadOptions, fileType); else env->loadFile(topEl, canonicalFilePath, logicalPath, code, codeDate, - DomTop::Callback(), DomTop::Callback(), callback, loadOptions); + DomTop::Callback(), DomTop::Callback(), callback, loadOptions, + fileType); } else Q_ASSERT(false && "expected either DomUniverse or DomEnvironment cast to succeed"); } else { @@ -2312,7 +2314,7 @@ void DomItem::loadFile(QString canonicalFilePath, QString logicalPath, QString c } void DomItem::loadFile(QString filePath, QString logicalPath, DomTop::Callback callback, - LoadOptions loadOptions) + LoadOptions loadOptions, std::optional fileType) { DomItem topEl = top(); if (topEl.internalKind() == DomType::DomEnvironment @@ -2322,10 +2324,10 @@ void DomItem::loadFile(QString filePath, QString logicalPath, DomTop::Callback c else if (auto env = topEl.ownerAs()) { if (env->options() & DomEnvironment::Option::NoDependencies) env->loadFile(topEl, filePath, logicalPath, callback, DomTop::Callback(), - DomTop::Callback(), loadOptions); + DomTop::Callback(), loadOptions, fileType); else env->loadFile(topEl, filePath, logicalPath, DomTop::Callback(), DomTop::Callback(), - callback, loadOptions); + callback, loadOptions, fileType); } else Q_ASSERT(false && "expected either DomUniverse or DomEnvironment cast to succeed"); } else { diff --git a/src/qmldom/qqmldomitem_p.h b/src/qmldom/qqmldomitem_p.h index 52a19b71c9..c3720d74ea 100644 --- a/src/qmldom/qqmldomitem_p.h +++ b/src/qmldom/qqmldomitem_p.h @@ -1036,11 +1036,11 @@ public: DomItem(std::shared_ptr); void loadFile(QString filePath, QString logicalPath, - std::function callback, - LoadOptions loadOptions); + std::function callback, LoadOptions loadOptions, + std::optional fileType = std::optional()); void loadFile(QString canonicalFilePath, QString logicalPath, QString code, QDateTime codeDate, - std::function callback, - LoadOptions loadOptions); + std::function callback, LoadOptions loadOptions, + std::optional fileType = std::optional()); void loadModuleDependency(QString uri, Version v, std::function callback = nullptr, ErrorHandler = nullptr); diff --git a/src/qmldom/qqmldomtop.cpp b/src/qmldom/qqmldomtop.cpp index e42506d632..5df34eedad 100644 --- a/src/qmldom/qqmldomtop.cpp +++ b/src/qmldom/qqmldomtop.cpp @@ -249,56 +249,55 @@ std::shared_ptr DomUniverse::doCopy(DomItem &) const } void DomUniverse::loadFile(DomItem &self, QString filePath, QString logicalPath, Callback callback, - LoadOptions loadOptions) + LoadOptions loadOptions, std::optional fileType) { - loadFile(self, filePath, logicalPath, QString(), QDateTime::fromMSecsSinceEpoch(0), callback, loadOptions); + loadFile(self, filePath, logicalPath, QString(), QDateTime::fromMSecsSinceEpoch(0), callback, + loadOptions, fileType); +} + +static DomType fileTypeForPath(DomItem &self, QString canonicalFilePath) +{ + if (canonicalFilePath.endsWith(u".qml", Qt::CaseInsensitive) + || canonicalFilePath.endsWith(u".qmlannotation", Qt::CaseInsensitive)) { + return DomType::QmlFile; + } else if (canonicalFilePath.endsWith(u".qmltypes")) { + return DomType::QmltypesFile; + } else if (QStringView(u"qmldir").compare(QFileInfo(canonicalFilePath).fileName(), + Qt::CaseInsensitive) + == 0) { + return DomType::QmltypesFile; + } else if (QFileInfo(canonicalFilePath).isDir()) { + return DomType::QmlDirectory; + } else { + self.addError(DomUniverse::myErrors() + .error(QCoreApplication::translate("Dom::filteTypeForPath", + "Could not detect type of file %1") + .arg(canonicalFilePath)) + .handle()); + } + return DomType::Empty; } void DomUniverse::loadFile(DomItem &self, QString canonicalFilePath, QString logicalPath, QString code, QDateTime codeDate, Callback callback, - LoadOptions loadOptions) + LoadOptions loadOptions, std::optional fileType) { - if (canonicalFilePath.endsWith(u".qml", Qt::CaseInsensitive) || - canonicalFilePath.endsWith(u".qmlannotation", Qt::CaseInsensitive) || - canonicalFilePath.endsWith(u".ui", Qt::CaseInsensitive)) { - m_queue.enqueue(ParsingTask{ - QDateTime::currentDateTime(), - loadOptions, - DomType::QmlFile, - canonicalFilePath, - logicalPath, - code, - codeDate, - self.ownerAs(), - callback}); - } else if (canonicalFilePath.endsWith(u".qmltypes")) { - m_queue.enqueue(ParsingTask{ - QDateTime::currentDateTime(), - loadOptions, - DomType::QmltypesFile, - canonicalFilePath, - logicalPath, - code, - codeDate, - self.ownerAs(), - callback}); - } else if (QStringView(u"qmldir").compare(QFileInfo(canonicalFilePath).fileName(), Qt::CaseInsensitive) == 0) { - m_queue.enqueue(ParsingTask{ - QDateTime::currentDateTime(), - loadOptions, - DomType::QmldirFile, - canonicalFilePath, - logicalPath, - code, - codeDate, - self.ownerAs(), - callback}); - } else if (QFileInfo(canonicalFilePath).isDir()) { - m_queue.enqueue(ParsingTask { QDateTime::currentDateTime(), loadOptions, - DomType::QmlDirectory, canonicalFilePath, logicalPath, code, - codeDate, self.ownerAs(), callback }); - } else { - self.addError(myErrors().error(tr("Ignoring request to load file of unknown type %1, calling callback immediately").arg(canonicalFilePath)).handle()); + DomType fType = (bool(fileType) ? (*fileType) : fileTypeForPath(self, canonicalFilePath)); + switch (fType) { + case DomType::QmlFile: + case DomType::QmltypesFile: + case DomType::QmldirFile: + case DomType::QmlDirectory: + m_queue.enqueue(ParsingTask { QDateTime::currentDateTime(), loadOptions, fType, + canonicalFilePath, logicalPath, code, codeDate, + self.ownerAs(), callback }); + break; + default: + self.addError(myErrors() + .error(tr("Ignoring request to load file %1 of unexpected type %2, " + "calling callback immediately") + .arg(canonicalFilePath, domTypeToString(fType))) + .handle()); Q_ASSERT(false && "loading non supported file type"); callback(Path(), DomItem::empty, DomItem::empty); return; @@ -629,7 +628,8 @@ void LoadInfo::advanceLoad(DomItem &self) [this, self, dep](Path, DomItem &, DomItem &) mutable { finishedLoadingDep(self, dep); }, - nullptr, nullptr, LoadOption::DefaultLoad, self.errorHandler()); + nullptr, nullptr, LoadOption::DefaultLoad, dep.fileType, + self.errorHandler()); else Q_ASSERT(false && "missing environment"); } else { @@ -749,12 +749,13 @@ void LoadInfo::doAddDependencies(DomItem &self) DomItem import = currentImports.index(i); if (const Import *importPtr = import.as()) { if (!importPtr->filePath().isEmpty()) { - addDependency( - self, - Dependency { QString(), importPtr->version, importPtr->filePath() }); + addDependency(self, + Dependency { QString(), importPtr->version, importPtr->filePath(), + DomType::Empty }); } else { addDependency(self, - Dependency { importPtr->uri, importPtr->version, QString() }); + Dependency { importPtr->uri, importPtr->version, QString(), + DomType::ModuleIndex }); } } } @@ -766,7 +767,8 @@ void LoadInfo::doAddDependencies(DomItem &self) Path canonicalPath = ref->referredObjectPath[2]; if (canonicalPath && !canonicalPath.headName().isEmpty()) addDependency(self, - Dependency { QString(), Version(), canonicalPath.headName() }); + Dependency { QString(), Version(), canonicalPath.headName(), + DomType::QmltypesFile }); } } DomItem currentQmlFiles = el.field(Fields::currentItem).field(Fields::qmlFiles); @@ -775,9 +777,9 @@ void LoadInfo::doAddDependencies(DomItem &self) if (const Reference *ref = el.as()) { Path canonicalPath = ref->referredObjectPath[2]; if (canonicalPath && !canonicalPath.headName().isEmpty()) - addDependency( - self, - Dependency { QString(), Version(), canonicalPath.headName() }); + addDependency(self, + Dependency { QString(), Version(), canonicalPath.headName(), + DomType::QmlFile }); } return true; }); @@ -786,7 +788,9 @@ void LoadInfo::doAddDependencies(DomItem &self) for (Path qmldirPath : elPtr->qmldirsToLoad(el)) { Path canonicalPath = qmldirPath[2]; if (canonicalPath && !canonicalPath.headName().isEmpty()) - addDependency(self, Dependency { QString(), Version(), canonicalPath.headName() }); + addDependency(self, + Dependency { QString(), Version(), canonicalPath.headName(), + DomType::QmldirFile }); } } else if (!el) { self.addError(DomEnvironment::myErrors().error( @@ -1150,10 +1154,11 @@ std::shared_ptr DomEnvironment::makeCopy(DomItem &self) const void DomEnvironment::loadFile(DomItem &self, QString filePath, QString logicalPath, DomTop::Callback loadCallback, DomTop::Callback directDepsCallback, - DomTop::Callback endCallback, LoadOptions loadOptions, ErrorHandler h) + DomTop::Callback endCallback, LoadOptions loadOptions, + std::optional fileType, ErrorHandler h) { loadFile(self, filePath, logicalPath, QString(), QDateTime::fromMSecsSinceEpoch(0), - loadCallback, directDepsCallback, endCallback, loadOptions, h); + loadCallback, directDepsCallback, endCallback, loadOptions, fileType, h); } std::shared_ptr DomEnvironment::doCopy(DomItem &) const @@ -1170,11 +1175,10 @@ std::shared_ptr DomEnvironment::doCopy(DomItem &) const void DomEnvironment::loadFile(DomItem &self, QString filePath, QString logicalPath, QString code, QDateTime codeDate, Callback loadCallback, Callback directDepsCallback, Callback endCallback, - LoadOptions loadOptions, ErrorHandler h) + LoadOptions loadOptions, std::optional fileType, + ErrorHandler h) { QFileInfo fileInfo(filePath); - bool isDir = fileInfo.isDir(); - QString ext = fileInfo.suffix(); QString canonicalFilePath = fileInfo.canonicalFilePath(); if (canonicalFilePath.isEmpty()) { if (code.isNull()) { @@ -1193,7 +1197,9 @@ void DomEnvironment::loadFile(DomItem &self, QString filePath, QString logicalPa } } shared_ptr oldValue, newValue; - if (isDir) { + DomType fType = (bool(fileType) ? (*fileType) : fileTypeForPath(self, canonicalFilePath)); + switch (fType) { + case DomType::QmlDirectory: { { QMutexLocker l(mutex()); auto it = m_qmlDirectoryWithPath.find(canonicalFilePath); @@ -1220,10 +1226,11 @@ void DomEnvironment::loadFile(DomItem &self, QString filePath, QString logicalPa self.universe().loadFile( canonicalFilePath, logicalPath, code, codeDate, callbackForQmlDirectory(self, loadCallback, directDepsCallback, endCallback), - loadOptions); + loadOptions, fType); return; } - } else if (ext == u"qml" || ext == u"ui" || ext == u"qmlannotation") { + } break; + case DomType::QmlFile: { { QMutexLocker l(mutex()); auto it = m_qmlFileWithPath.find(canonicalFilePath); @@ -1249,10 +1256,11 @@ void DomEnvironment::loadFile(DomItem &self, QString filePath, QString logicalPa self.universe().loadFile( canonicalFilePath, logicalPath, code, codeDate, callbackForQmlFile(self, loadCallback, directDepsCallback, endCallback), - loadOptions); + loadOptions, fType); return; } - } else if (ext == u"qmltypes") { + } break; + case DomType::QmltypesFile: { { QMutexLocker l(mutex()); auto it = m_qmltypesFileWithPath.find(canonicalFilePath); @@ -1279,10 +1287,11 @@ void DomEnvironment::loadFile(DomItem &self, QString filePath, QString logicalPa self.universe().loadFile( canonicalFilePath, logicalPath, code, codeDate, callbackForQmltypesFile(self, loadCallback, directDepsCallback, endCallback), - loadOptions); + loadOptions, fType); return; } - } else if (fileInfo.fileName() == u"qmldir") { + } break; + case DomType::QmldirFile: { { QMutexLocker l(mutex()); auto it = m_qmldirFileWithPath.find(canonicalFilePath); @@ -1308,10 +1317,11 @@ void DomEnvironment::loadFile(DomItem &self, QString filePath, QString logicalPa self.universe().loadFile( canonicalFilePath, logicalPath, code, codeDate, callbackForQmldirFile(self, loadCallback, directDepsCallback, endCallback), - loadOptions); + loadOptions, fType); return; } - } else { + } break; + default: { myErrors().error(tr("Unexpected file to load: '%1'").arg(filePath)).handle(h); if (loadCallback) loadCallback(self.canonicalPath(), DomItem::empty, DomItem::empty); @@ -1320,6 +1330,7 @@ void DomEnvironment::loadFile(DomItem &self, QString filePath, QString logicalPa if (endCallback) endCallback(self.canonicalPath(), DomItem::empty, DomItem::empty); return; + } break; } Path p = self.copy(newValue).canonicalPath(); std::shared_ptr lInfo = loadInfo(p); diff --git a/src/qmldom/qqmldomtop_p.h b/src/qmldom/qqmldomtop_p.h index 4c905991af..eeb0038d09 100644 --- a/src/qmldom/qqmldomtop_p.h +++ b/src/qmldom/qqmldomtop_p.h @@ -61,6 +61,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -253,9 +254,11 @@ public: } void loadFile(DomItem &self, QString filePath, QString logicalPath, Callback callback, - LoadOptions loadOptions); + LoadOptions loadOptions, + std::optional fileType = std::optional()); void loadFile(DomItem &self, QString canonicalFilePath, QString logicalPath, QString code, - QDateTime codeDate, Callback callback, LoadOptions loadOptions); + QDateTime codeDate, Callback callback, LoadOptions loadOptions, + std::optional fileType = std::optional()); void execQueue(); std::shared_ptr> globalScopeWithName(QString name) const @@ -517,6 +520,7 @@ public: QString uri; // either dotted uri or file:, http: https: uri Version version; QString filePath; // for file deps + DomType fileType; }; class QMLDOM_EXPORT LoadInfo final : public OwningItem @@ -683,10 +687,13 @@ public: void loadFile(DomItem &self, QString filePath, QString logicalPath, Callback loadCallback, Callback directDepsCallback, Callback endCallback, LoadOptions loadOptions, + std::optional fileType = std::optional(), ErrorHandler h = nullptr); void loadFile(DomItem &self, QString canonicalFilePath, QString logicalPath, QString code, QDateTime codeDate, Callback loadCallback, Callback directDepsCallback, - Callback endCallback, LoadOptions loadOptions, ErrorHandler h = nullptr); + Callback endCallback, LoadOptions loadOptions, + std::optional fileType = std::optional(), + ErrorHandler h = nullptr); void loadModuleDependency(DomItem &self, QString uri, Version v, Callback loadCallback = nullptr, Callback endCallback = nullptr, ErrorHandler = nullptr); diff --git a/tools/qmldom/qmldomtool.cpp b/tools/qmldom/qmldomtool.cpp index 8efa652082..c70b77b520 100644 --- a/tools/qmldom/qmldomtool.cpp +++ b/tools/qmldom/qmldomtool.cpp @@ -41,6 +41,7 @@ #include #include +#include #if QT_CONFIG(commandlineparser) # include @@ -152,6 +153,10 @@ int main(int argc, char *argv[]) } } + std::optional fileType; + if (parser.isSet(reformatOption)) + fileType = DomType::QmlFile; + Dependencies dep = Dependencies::None; for (QString depName : parser.values(dependenciesOption)) { QMetaEnum metaEnum = QMetaEnum::fromType(); @@ -230,15 +235,22 @@ int main(int argc, char *argv[]) if (dep != Dependencies::None) env.loadBuiltins(); foreach (QString s, positionalArguments) { - env.loadFile(s, QString(), nullptr, LoadOption::DefaultLoad); + env.loadFile(s, QString(), nullptr, LoadOption::DefaultLoad, fileType); } envPtr->loadPendingDependencies(env); + bool hadFailures = false; + const qsizetype largestFileSizeToCheck = 32000; if (parser.isSet(reformatOption)) { for (auto s : positionalArguments) { - DomItem qmlFile = env.path(Paths::qmldirFilePath(s)); + DomItem qmlFile = env.path(Paths::qmlFilePath(QFileInfo(s).canonicalFilePath())); if (qmlFile) { qDebug() << "reformatting" << s; FileWriter fw; + LineWriterOptions lwOptions; + WriteOutChecks checks = WriteOutCheck::Default; + if (std::shared_ptr qmlFilePtr = qmlFile.ownerAs()) + if (qmlFilePtr->code().size() > largestFileSizeToCheck) + checks = WriteOutCheck::None; QString target = s; QString rDir = parser.value(reformatDirOption); if (!rDir.isEmpty()) { @@ -246,16 +258,8 @@ int main(int argc, char *argv[]) QDir d(rDir); target = d.filePath(f.fileName()); } - switch (fw.write( - target, - [&qmlFile, target](QTextStream &ts) { - LineWriter lw([&ts](QStringView s) { ts << s; }, target); - OutWriter ow(lw); - qmlFile.writeOut(ow); - ow.eof(); - return true; - }, - nBackups)) { + MutableDomItem res = qmlFile.writeOut(target, nBackups, lwOptions, &fw, checks); + switch (fw.status) { case FileWriter::Status::ShouldWrite: case FileWriter::Status::SkippedDueToFailure: qWarning() << "failure reformatting " << s; @@ -266,10 +270,10 @@ int main(int argc, char *argv[]) case FileWriter::Status::SkippedEqual: qDebug() << "no change"; } + hadFailures = hadFailures || !bool(res); } } - } - if (parser.isSet(dumpOption) || !parser.isSet(reformatOption)) { + } else if (parser.isSet(dumpOption) || !parser.isSet(reformatOption)) { qDebug() << "will dump\n"; QTextStream ts(stdout); auto sink = [&ts](QStringView v) {