2022-05-13 13:12:05 +00:00
|
|
|
// Copyright (C) 2021 The Qt Company Ltd.
|
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
Suppress GCC11 warning about maybe-uninitialized data access
I don't *think* the compiler is correct. It's complaining that the
copy-construction of PathComponent in the lambda here:
bool dvReference(DirectVisitor visitor, const PathEls::PathComponent &c, Path referencedObject)
{
return dvItem(visitor, c, [c, this, referencedObject]() {
return this->subReferenceItem(c, referencedObject);
});
}
which was created as a temporary in dvReferenceField:
return dvReference(visitor, PathEls::Field(f), referencedObject);
could be copying garbage. Note that the warning is about copying a
PathComponent::Data of kind Key, whereas this inline sequence is of
Field.
Of course, the whole PathComponent::Data is a major ill-advised disaster
waiting to happen...
In copy constructor ‘QArrayDataPointer<T>::QArrayDataPointer(const QArrayDataPointer<T>&) [with T = char16_t]’,
inlined from ‘QString::QString(const QString&)’ at qstring.h:1232:58,
inlined from ‘QQmlJS::Dom::PathEls::Key::Key(const QQmlJS::Dom::PathEls::Key&)’ at src/qmldom/qqmldompath_p.h:164:7,
inlined from ‘QQmlJS::Dom::PathEls::PathComponent::Data::Data(const QQmlJS::Dom::PathEls::PathComponent::Data&)’ at src/qmldom/qqmldompath_p.h:369:37,
inlined from ‘QQmlJS::Dom::PathEls::PathComponent::PathComponent(const QQmlJS::Dom::PathEls::PathComponent&)’ at src/qmldom/qqmldompath_p.h:311:7,
inlined from ‘bool QQmlJS::Dom::DomItem::dvReference(QQmlJS::Dom::DirectVisitor, const QQmlJS::Dom::PathEls::PathComponent&, QQmlJS::Dom::Path)’ at src/qmldom/qqmldomitem_p.h:981:22,
inlined from ‘bool QQmlJS::Dom::DomItem::dvReferenceField(QQmlJS::Dom::DirectVisitor, QStringView, QQmlJS::Dom::Path)’ at src/qmldom/qqmldomitem_p.h:991:27:
qarraydatapointer.h:69:50: error: ‘*(const QArrayDataPointer<char16_t>*)((char*)&<unnamed> + offsetof(const QQmlJS::Dom::PathEls::PathComponent, QQmlJS::Dom::PathEls::PathComponent::data) + 8).QArrayDataPointer<char16_t>::size’ may be used uninitialized [-Werror=maybe-uninitialized]
69 | : d(other.d), ptr(other.ptr), size(other.size)
| ~~~~~~^~~~
In file included from src/qmldom/qqmldomelements_p.h:52,
from src/qmldom/qqmldomelements.cpp:38:
src/qmldom/qqmldomitem_p.h: In member function ‘bool QQmlJS::Dom::DomItem::dvReferenceField(QQmlJS::Dom::DirectVisitor, QStringView, QQmlJS::Dom::Path)’:
src/qmldom/qqmldomitem_p.h:991:27: note: ‘<anonymous>’ declared here
991 | return dvReference(visitor, PathEls::Field(f), referencedObject);
| ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Change-Id: Iddb933f281024939b6acfffd1689d2fdea0adc61
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
2021-06-18 23:58:21 +00:00
|
|
|
// Suppress GCC 11 warning about maybe-uninitialized copy of
|
|
|
|
// another Data. We're not sure if the compiler is actually right,
|
|
|
|
// but in this type of warning, it often isn't.
|
|
|
|
//#if defined(Q_CC_GNU) && Q_CC_GNU >= 1100
|
|
|
|
//QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized")
|
2023-09-29 13:32:33 +00:00
|
|
|
#include "qqmldomconstants_p.h"
|
2023-04-05 14:43:50 +00:00
|
|
|
#include "qqmldompath_p.h"
|
Suppress GCC11 warning about maybe-uninitialized data access
I don't *think* the compiler is correct. It's complaining that the
copy-construction of PathComponent in the lambda here:
bool dvReference(DirectVisitor visitor, const PathEls::PathComponent &c, Path referencedObject)
{
return dvItem(visitor, c, [c, this, referencedObject]() {
return this->subReferenceItem(c, referencedObject);
});
}
which was created as a temporary in dvReferenceField:
return dvReference(visitor, PathEls::Field(f), referencedObject);
could be copying garbage. Note that the warning is about copying a
PathComponent::Data of kind Key, whereas this inline sequence is of
Field.
Of course, the whole PathComponent::Data is a major ill-advised disaster
waiting to happen...
In copy constructor ‘QArrayDataPointer<T>::QArrayDataPointer(const QArrayDataPointer<T>&) [with T = char16_t]’,
inlined from ‘QString::QString(const QString&)’ at qstring.h:1232:58,
inlined from ‘QQmlJS::Dom::PathEls::Key::Key(const QQmlJS::Dom::PathEls::Key&)’ at src/qmldom/qqmldompath_p.h:164:7,
inlined from ‘QQmlJS::Dom::PathEls::PathComponent::Data::Data(const QQmlJS::Dom::PathEls::PathComponent::Data&)’ at src/qmldom/qqmldompath_p.h:369:37,
inlined from ‘QQmlJS::Dom::PathEls::PathComponent::PathComponent(const QQmlJS::Dom::PathEls::PathComponent&)’ at src/qmldom/qqmldompath_p.h:311:7,
inlined from ‘bool QQmlJS::Dom::DomItem::dvReference(QQmlJS::Dom::DirectVisitor, const QQmlJS::Dom::PathEls::PathComponent&, QQmlJS::Dom::Path)’ at src/qmldom/qqmldomitem_p.h:981:22,
inlined from ‘bool QQmlJS::Dom::DomItem::dvReferenceField(QQmlJS::Dom::DirectVisitor, QStringView, QQmlJS::Dom::Path)’ at src/qmldom/qqmldomitem_p.h:991:27:
qarraydatapointer.h:69:50: error: ‘*(const QArrayDataPointer<char16_t>*)((char*)&<unnamed> + offsetof(const QQmlJS::Dom::PathEls::PathComponent, QQmlJS::Dom::PathEls::PathComponent::data) + 8).QArrayDataPointer<char16_t>::size’ may be used uninitialized [-Werror=maybe-uninitialized]
69 | : d(other.d), ptr(other.ptr), size(other.size)
| ~~~~~~^~~~
In file included from src/qmldom/qqmldomelements_p.h:52,
from src/qmldom/qqmldomelements.cpp:38:
src/qmldom/qqmldomitem_p.h: In member function ‘bool QQmlJS::Dom::DomItem::dvReferenceField(QQmlJS::Dom::DirectVisitor, QStringView, QQmlJS::Dom::Path)’:
src/qmldom/qqmldomitem_p.h:991:27: note: ‘<anonymous>’ declared here
991 | return dvReference(visitor, PathEls::Field(f), referencedObject);
| ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Change-Id: Iddb933f281024939b6acfffd1689d2fdea0adc61
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
2021-06-18 23:58:21 +00:00
|
|
|
#if defined(__GNUC__) && __GNUC__ >= 11
|
|
|
|
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
|
|
|
#endif
|
|
|
|
|
2021-03-23 10:02:18 +00:00
|
|
|
#include "qqmldomelements_p.h"
|
|
|
|
#include "qqmldomcomments_p.h"
|
|
|
|
#include "qqmldomastdumper_p.h"
|
|
|
|
#include "qqmldommock_p.h"
|
2021-03-23 14:37:32 +00:00
|
|
|
#include "qqmldomreformatter_p.h"
|
|
|
|
#include "qqmldomoutwriter_p.h"
|
|
|
|
#include "qqmldomlinewriter_p.h"
|
2021-03-23 10:02:18 +00:00
|
|
|
#include "qqmldomtop_p.h"
|
|
|
|
#include "qqmldomexternalitems_p.h"
|
|
|
|
|
|
|
|
#include <QtQml/private/qqmljslexer_p.h>
|
|
|
|
#include <QtQml/private/qqmljsparser_p.h>
|
|
|
|
#include <QtQml/private/qqmljsengine_p.h>
|
|
|
|
#include <QtQml/private/qqmljsastvisitor_p.h>
|
|
|
|
#include <QtQml/private/qqmljsast_p.h>
|
|
|
|
|
|
|
|
#include <QtCore/QScopeGuard>
|
|
|
|
#include <QtCore/QRegularExpression>
|
|
|
|
#include <QtCore/QDir>
|
|
|
|
#include <QtCore/QBasicMutex>
|
2021-12-06 21:18:28 +00:00
|
|
|
#include <QtCore/QUrl>
|
2021-03-23 10:02:18 +00:00
|
|
|
|
|
|
|
#include <optional>
|
2021-09-03 09:13:07 +00:00
|
|
|
#include <limits>
|
2021-03-23 10:02:18 +00:00
|
|
|
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
using namespace Qt::StringLiterals;
|
|
|
|
|
2021-03-23 10:02:18 +00:00
|
|
|
namespace QQmlJS {
|
|
|
|
namespace Dom {
|
|
|
|
|
|
|
|
namespace Paths {
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
Path moduleIndexPath(const QString &uri, int majorVersion, const ErrorHandler &errorHandler)
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
QString version = QString::number(majorVersion);
|
|
|
|
if (majorVersion == Version::Latest)
|
|
|
|
version = QLatin1String("Latest");
|
|
|
|
else if (majorVersion == Version::Undefined)
|
|
|
|
version = QString();
|
2021-12-06 21:18:28 +00:00
|
|
|
QRegularExpression moduleRe(QLatin1String(R"(\A\w+(?:\.\w+)*\Z)"));
|
|
|
|
auto m = moduleRe.match(uri);
|
|
|
|
if (!m.isValid())
|
|
|
|
Path::myErrors()
|
|
|
|
.error(Path::tr("Invalid module name in import %1").arg(uri))
|
|
|
|
.handle(errorHandler);
|
2021-03-23 10:02:18 +00:00
|
|
|
return Path::Root(PathRoot::Env).field(Fields::moduleIndexWithUri).key(uri).key(version);
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
Path moduleScopePath(const QString &uri, Version version, const ErrorHandler &)
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
return Path::Root(PathRoot::Env)
|
|
|
|
.field(Fields::moduleIndexWithUri)
|
|
|
|
.key(uri)
|
|
|
|
.key(version.majorSymbolicString())
|
|
|
|
.field(Fields::moduleScope)
|
|
|
|
.key(version.minorString());
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
Path moduleScopePath(const QString &uri, const QString &version, const ErrorHandler &errorHandler)
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
Version v = Version::fromString(version);
|
|
|
|
if (!version.isEmpty() && !(v.isValid() || v.isLatest()))
|
|
|
|
Path::myErrors().error(Path::tr("Invalid Version %1").arg(version)).handle(errorHandler);
|
|
|
|
return moduleScopePath(uri, v, errorHandler);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // end namespace Paths
|
|
|
|
|
|
|
|
static ErrorGroups domParsingErrors()
|
|
|
|
{
|
|
|
|
static ErrorGroups res = { { DomItem::domErrorGroup, NewErrorGroup("Parsing") } };
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
bool CommentableDomElement::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
bool cont = true;
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::comments, m_comments);
|
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
void Component::updatePathFromOwner(const Path &newPath)
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
DomElement::updatePathFromOwner(newPath);
|
|
|
|
updatePathFromOwnerMultiMap(m_enumerations, newPath.field(Fields::enumerations));
|
|
|
|
updatePathFromOwnerQList(m_objects, newPath.field(Fields::objects));
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
Component::Component(const QString &name) : CommentableDomElement(Path()), m_name(name) { }
|
2021-03-23 10:02:18 +00:00
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
Component::Component(const Path &pathFromOwner) : CommentableDomElement(pathFromOwner) { }
|
2021-03-23 10:02:18 +00:00
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
bool Component::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
bool cont = CommentableDomElement::iterateDirectSubpaths(self, visitor);
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::name, name());
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::enumerations, m_enumerations);
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::objects, m_objects);
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::isSingleton, isSingleton());
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::isCreatable, isCreatable());
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::isComposite, isComposite());
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::attachedTypeName, attachedTypeName());
|
|
|
|
cont = cont && self.dvReferenceField(visitor, Fields::attachedType, attachedTypePath(self));
|
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
DomItem Component::field(const DomItem &self, QStringView name) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
2024-01-02 14:56:03 +00:00
|
|
|
if (name == Fields::name)
|
|
|
|
return self.wrapField(Fields::name, m_name);
|
|
|
|
if (name == Fields::objects)
|
|
|
|
return self.wrapField(Fields::objects, m_objects);
|
|
|
|
|
2021-03-23 10:02:18 +00:00
|
|
|
return DomBase::field(self, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
Path Component::addObject(const QmlObject &object, QmlObject **oPtr)
|
|
|
|
{
|
|
|
|
return appendUpdatableElementInQList(pathFromOwner().field(Fields::objects), m_objects, object,
|
|
|
|
oPtr);
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
bool QmlComponent::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
bool cont = Component::iterateDirectSubpaths(self, visitor);
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::ids, m_ids);
|
|
|
|
cont = cont && self.dvValueLazyField(visitor, Fields::subComponents, [this, &self]() {
|
|
|
|
return this->subComponents(self);
|
|
|
|
});
|
2024-01-19 17:31:07 +00:00
|
|
|
if (m_nameIdentifiers) {
|
|
|
|
cont = cont && self.dvItemField(visitor, Fields::nameIdentifiers, [this, &self]() {
|
|
|
|
return self.subScriptElementWrapperItem(m_nameIdentifiers);
|
|
|
|
});
|
|
|
|
}
|
2021-03-23 10:02:18 +00:00
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
void QmlComponent::updatePathFromOwner(const Path &newPath)
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
Component::updatePathFromOwner(newPath);
|
|
|
|
updatePathFromOwnerMultiMap(m_ids, newPath.field(Fields::annotations));
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
void QmlComponent::writeOut(const DomItem &self, OutWriter &lw) const
|
2021-03-23 14:37:32 +00:00
|
|
|
{
|
|
|
|
if (name().contains(QLatin1Char('.'))) {
|
|
|
|
// inline component
|
|
|
|
lw.ensureNewline()
|
2023-09-29 13:32:33 +00:00
|
|
|
.writeRegion(ComponentKeywordRegion)
|
2021-03-23 14:37:32 +00:00
|
|
|
.space()
|
2023-09-29 13:32:33 +00:00
|
|
|
.writeRegion(IdentifierRegion, name().split(QLatin1Char('.')).last())
|
|
|
|
.writeRegion(ColonTokenRegion)
|
2021-03-23 14:37:32 +00:00
|
|
|
.space();
|
|
|
|
}
|
|
|
|
self.field(Fields::objects).index(0).writeOut(lw);
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
QList<QString> QmlComponent::subComponentsNames(const DomItem &self) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
DomItem components = self.owner().field(Fields::components);
|
2023-09-13 15:36:59 +00:00
|
|
|
const QSet<QString> cNames = components.keys();
|
2021-03-23 10:02:18 +00:00
|
|
|
QString myNameDot = self.pathFromOwner()[1].headName();
|
|
|
|
if (!myNameDot.isEmpty())
|
|
|
|
myNameDot += QLatin1Char('.');
|
|
|
|
QList<QString> subNames;
|
2023-09-13 15:36:59 +00:00
|
|
|
for (const QString &cName : cNames)
|
2021-03-23 10:02:18 +00:00
|
|
|
if (cName.startsWith(myNameDot)
|
2022-10-05 05:29:16 +00:00
|
|
|
&& !QStringView(cName).mid(myNameDot.size()).contains(QLatin1Char('.'))
|
2021-03-23 10:02:18 +00:00
|
|
|
&& !cName.isEmpty())
|
|
|
|
subNames.append(cName);
|
|
|
|
std::sort(subNames.begin(), subNames.end());
|
|
|
|
return subNames;
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
QList<DomItem> QmlComponent::subComponents(const DomItem &self) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
DomItem components = self.owner().field(Fields::components);
|
|
|
|
QList<DomItem> res;
|
2023-09-13 15:36:59 +00:00
|
|
|
for (const QString &cName : subComponentsNames(self))
|
|
|
|
for (const DomItem &comp : components.key(cName).values())
|
2021-03-23 10:02:18 +00:00
|
|
|
res.append(comp);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
Version Version::fromString(QStringView v)
|
|
|
|
{
|
|
|
|
if (v.isEmpty())
|
|
|
|
return Version(Latest, Latest);
|
|
|
|
QRegularExpression r(
|
|
|
|
QRegularExpression::anchoredPattern(QStringLiteral(uR"(([0-9]*)(?:\.([0-9]*))?)")));
|
2022-08-01 09:03:27 +00:00
|
|
|
auto m = r.matchView(v);
|
2021-03-23 10:02:18 +00:00
|
|
|
if (m.hasMatch()) {
|
|
|
|
bool ok;
|
2022-08-01 09:03:27 +00:00
|
|
|
int majorV = m.capturedView(1).toInt(&ok);
|
2021-03-23 10:02:18 +00:00
|
|
|
if (!ok)
|
|
|
|
majorV = Version::Undefined;
|
2022-08-01 09:03:27 +00:00
|
|
|
int minorV = m.capturedView(2).toInt(&ok);
|
2021-03-23 10:02:18 +00:00
|
|
|
if (!ok)
|
|
|
|
minorV = Version::Undefined;
|
|
|
|
return Version(majorV, minorV);
|
|
|
|
}
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
Version::Version(qint32 majorV, qint32 minorV) : majorVersion(majorV), minorVersion(minorV) { }
|
|
|
|
|
|
|
|
bool Version::isLatest() const
|
|
|
|
{
|
|
|
|
return majorVersion == Latest && minorVersion == Latest;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Version::isValid() const
|
|
|
|
{
|
|
|
|
return majorVersion >= 0 && minorVersion >= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString Version::stringValue() const
|
|
|
|
{
|
|
|
|
if (isLatest())
|
|
|
|
return QString();
|
|
|
|
if (minorVersion < 0) {
|
|
|
|
if (majorVersion < 0)
|
|
|
|
return QLatin1String(".");
|
|
|
|
else
|
|
|
|
return QString::number(majorVersion);
|
|
|
|
}
|
|
|
|
if (majorVersion < 0)
|
|
|
|
return QLatin1String(".") + QString::number(minorVersion);
|
|
|
|
return QString::number(majorVersion) + QChar::fromLatin1('.') + QString::number(minorVersion);
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
bool Version::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
bool cont = true;
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::majorVersion, majorVersion);
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::minorVersion, minorVersion);
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::isLatest, isLatest());
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::isValid, isValid());
|
|
|
|
cont = cont && self.dvValueLazyField(visitor, Fields::stringValue, [this]() {
|
|
|
|
return this->stringValue();
|
|
|
|
});
|
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
|
|
|
QRegularExpression Import::importRe()
|
|
|
|
{
|
|
|
|
static QRegularExpression res(QRegularExpression::anchoredPattern(QStringLiteral(
|
|
|
|
uR"((?<uri>\w+(?:\.\w+)*)(?:\W+(?<version>[0-9]+(?:\.[0-9]*)?))?(?:\W+as\W+(?<id>\w+))?$)")));
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
Import Import::fromUriString(
|
|
|
|
const QString &importStr, Version v, const QString &importId, const ErrorHandler &handler)
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
2021-12-06 21:18:28 +00:00
|
|
|
auto m = importRe().match(importStr);
|
|
|
|
if (m.hasMatch()) {
|
|
|
|
if (v.majorVersion == Version::Undefined && v.minorVersion == Version::Undefined)
|
|
|
|
v = Version::fromString(m.captured(2));
|
|
|
|
else if (!m.captured(u"version").isEmpty())
|
|
|
|
domParsingErrors()
|
|
|
|
.warning(tr("Version %1 in import string '%2' overridden by explicit "
|
|
|
|
"version %3")
|
|
|
|
.arg(m.captured(2), importStr, v.stringValue()))
|
|
|
|
.handle(handler);
|
2023-12-13 14:24:34 +00:00
|
|
|
QString resolvedImportId;
|
|
|
|
if (importId.isEmpty()) {
|
|
|
|
resolvedImportId = m.captured(u"importId");
|
|
|
|
} else {
|
|
|
|
if (!m.captured(u"importId").isEmpty()) {
|
|
|
|
domParsingErrors()
|
|
|
|
.warning(tr("namespace %1 in import string '%2' overridden by explicit "
|
|
|
|
"importId %3")
|
|
|
|
.arg(m.captured(u"importId"), importStr, importId))
|
|
|
|
.handle(handler);
|
|
|
|
}
|
|
|
|
resolvedImportId = importId;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Import(QmlUri::fromUriString(m.captured(u"uri").trimmed()), v, resolvedImportId);
|
2021-03-23 10:02:18 +00:00
|
|
|
}
|
2021-12-06 21:18:28 +00:00
|
|
|
domParsingErrors()
|
|
|
|
.error(tr("Unexpected URI format in import '%1'").arg(importStr))
|
|
|
|
.handle(handler);
|
|
|
|
return Import();
|
2021-03-23 10:02:18 +00:00
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
Import Import::fromFileString(
|
|
|
|
const QString &importStr, const QString &importId, const ErrorHandler &)
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
2021-12-06 21:18:28 +00:00
|
|
|
return Import(QmlUri::fromDirectoryString(importStr), Version(), importId);
|
2021-03-23 10:02:18 +00:00
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
bool Import::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
bool cont = true;
|
2021-12-06 21:18:28 +00:00
|
|
|
cont = cont && self.dvValueField(visitor, Fields::uri, uri.toString());
|
2021-03-23 10:02:18 +00:00
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::version, version);
|
|
|
|
if (!importId.isEmpty())
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::importId, importId);
|
|
|
|
if (implicit)
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::implicit, implicit);
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::comments, comments);
|
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
2023-09-13 18:21:24 +00:00
|
|
|
void Import::writeOut(const DomItem &self, OutWriter &ow) const
|
2021-03-23 14:37:32 +00:00
|
|
|
{
|
|
|
|
if (implicit)
|
|
|
|
return;
|
2023-09-13 18:21:24 +00:00
|
|
|
|
|
|
|
QString code;
|
|
|
|
const DomItem owner = self.owner();
|
|
|
|
if (std::shared_ptr<QmlFile> qmlFilePtr = self.ownerAs<QmlFile>())
|
|
|
|
code = qmlFilePtr->code();
|
|
|
|
|
|
|
|
// check for an empty line before the import, and preserve it
|
|
|
|
int preNewlines = 0;
|
|
|
|
|
|
|
|
const FileLocations::Tree elLoc = FileLocations::findAttachedInfo(self).foundTree;
|
|
|
|
|
|
|
|
quint32 start = elLoc->info().fullRegion.offset;
|
|
|
|
if (size_t(code.size()) >= start) {
|
|
|
|
while (start != 0) {
|
|
|
|
QChar c = code.at(--start);
|
|
|
|
if (c == u'\n') {
|
|
|
|
if (++preNewlines == 2)
|
|
|
|
break;
|
|
|
|
} else if (!c.isSpace())
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (preNewlines == 0)
|
|
|
|
++preNewlines;
|
|
|
|
|
|
|
|
ow.ensureNewline(preNewlines);
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(ImportTokenRegion).space();
|
|
|
|
ow.writeRegion(ImportUriRegion, uri.toString());
|
2021-12-06 21:18:28 +00:00
|
|
|
if (uri.isModule()) {
|
2021-03-23 14:37:32 +00:00
|
|
|
QString vString = version.stringValue();
|
|
|
|
if (!vString.isEmpty())
|
|
|
|
ow.space().write(vString);
|
|
|
|
}
|
|
|
|
if (!importId.isEmpty())
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.space().writeRegion(AsTokenRegion).space().writeRegion(IdNameRegion, importId);
|
2021-03-23 14:37:32 +00:00
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
Id::Id(const QString &idName, const Path &referredObject) : name(idName), referredObjectPath(referredObject) { }
|
2021-03-23 10:02:18 +00:00
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
bool Id::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
bool cont = true;
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::name, name);
|
|
|
|
cont = cont && self.dvReferenceField(visitor, Fields::referredObject, referredObjectPath);
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::comments, comments);
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::annotations, annotations);
|
2023-05-04 13:17:58 +00:00
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::value, value);
|
2021-03-23 10:02:18 +00:00
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
void Id::updatePathFromOwner(const Path &newPath)
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
updatePathFromOwnerQList(annotations, newPath.field(Fields::annotations));
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
Path Id::addAnnotation(const Path &selfPathFromOwner, const QmlObject &annotation, QmlObject **aPtr)
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
return appendUpdatableElementInQList(selfPathFromOwner.field(Fields::annotations), annotations,
|
|
|
|
annotation, aPtr);
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
QmlObject::QmlObject(const Path &pathFromOwner) : CommentableDomElement(pathFromOwner) { }
|
2021-03-23 10:02:18 +00:00
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
bool QmlObject::iterateBaseDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
bool cont = CommentableDomElement::iterateDirectSubpaths(self, visitor);
|
|
|
|
if (!idStr().isEmpty())
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::idStr, idStr());
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::name, name());
|
|
|
|
if (!prototypePaths().isEmpty())
|
|
|
|
cont = cont && self.dvReferencesField(visitor, Fields::prototypes, m_prototypePaths);
|
|
|
|
if (nextScopePath())
|
|
|
|
cont = cont && self.dvReferenceField(visitor, Fields::nextScope, nextScopePath());
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::propertyDefs, m_propertyDefs);
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::bindings, m_bindings);
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::methods, m_methods);
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::children, m_children);
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::annotations, m_annotations);
|
|
|
|
cont = cont && self.dvItemField(visitor, Fields::propertyInfos, [this, &self]() {
|
|
|
|
return self.subMapItem(Map(
|
|
|
|
pathFromOwner().field(Fields::propertyInfos),
|
2023-12-13 14:24:34 +00:00
|
|
|
[&self](const DomItem &map, const QString &k) {
|
2021-03-23 10:02:18 +00:00
|
|
|
auto pInfo = self.propertyInfoWithName(k);
|
|
|
|
return map.wrap(PathEls::Key(k), pInfo);
|
|
|
|
},
|
2023-09-13 13:05:12 +00:00
|
|
|
[&self](const DomItem &) { return self.propertyInfoNames(); },
|
2021-03-23 10:02:18 +00:00
|
|
|
QLatin1String("PropertyInfo")));
|
|
|
|
});
|
qmldom: make type a FieldMemberExpression
This commit prepares the Dom to be able to provide correct
completions on binding scripts ending with a `.`.
In addition to saving qualified types as a string, like `QQ.Item` for
example, save them also as a FieldMemberExpression. Do this for
QmlObjects, like `QQ.Item {}` for example, and type annotations, like
`function f(): QQ.Item {}` for example.
This will allow qmlls to suggest completions after `root.` in cases
like
```
x: root.
SomeQualifiedModule.Item {}
```
for example, or after `QQ.` in cases like
```
(x as QQ.Item)
```
for example. The latter magically makes the asCompletion test work
(which was previously QEXPECT_FAIL'd).
Prior to this commit, the Dom did not contain enough information to
know where exactly the completion gets requested inside of
`root.SomeQualifiedModule.Item` and therefore could not suggest any
meaningful suggestion.
Basically reuses a44f21f19462cc79f82080404515c4322b7728ee to model the
nameIdentifiers, a FieldMemberExpression that contains the current type
of the QmlObject.
Adapt existing tests propertyDefinitionBinding and
ignoreNonRelatedTypesForpropertyDefinitionBinding to the changes in the
Dom: the qml object type in a binding, for example `Item` in
`myBinding: Item {}`, is now part of the QmlObject. It was part of the
Binding prior to this commit.
Adapt the qmllsutils method to the change in structure.
Pick-to: 6.7
Task-number: QTBUG-119839
Change-Id: Ie7bc7692f731a01467392dc1dffdf7e67c4d7c46
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2023-12-19 11:05:42 +00:00
|
|
|
if (m_nameIdentifiers) {
|
|
|
|
cont = cont && self.dvItemField(visitor, Fields::nameIdentifiers, [this, &self]() {
|
|
|
|
return self.subScriptElementWrapperItem(m_nameIdentifiers);
|
|
|
|
});
|
|
|
|
}
|
2021-03-23 10:02:18 +00:00
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
|
|
|
QList<QString> QmlObject::fields() const
|
|
|
|
{
|
|
|
|
static QList<QString> myFields(
|
|
|
|
{ QString::fromUtf16(Fields::comments), QString::fromUtf16(Fields::idStr),
|
|
|
|
QString::fromUtf16(Fields::name), QString::fromUtf16(Fields::prototypes),
|
|
|
|
QString::fromUtf16(Fields::nextScope), QString::fromUtf16(Fields::propertyDefs),
|
|
|
|
QString::fromUtf16(Fields::bindings), QString::fromUtf16(Fields::methods),
|
|
|
|
QString::fromUtf16(Fields::children), QString::fromUtf16(Fields::annotations),
|
|
|
|
QString::fromUtf16(Fields::propertyInfos) });
|
|
|
|
return myFields;
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
bool QmlObject::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
bool cont = iterateBaseDirectSubpaths(self, visitor);
|
|
|
|
cont = cont && self.dvValueLazyField(visitor, Fields::defaultPropertyName, [this, &self]() {
|
|
|
|
return defaultPropertyName(self);
|
|
|
|
});
|
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
DomItem QmlObject::field(const DomItem &self, QStringView name) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
2024-01-02 14:56:03 +00:00
|
|
|
if (name == Fields::name)
|
|
|
|
return self.subDataItem(PathEls::Field(Fields::name), this->name());
|
|
|
|
if (name == Fields::idStr) {
|
|
|
|
if (idStr().isEmpty())
|
|
|
|
return DomItem();
|
|
|
|
return self.subDataItem(PathEls::Field(Fields::idStr), idStr());
|
|
|
|
}
|
|
|
|
if (name == Fields::methods)
|
|
|
|
return self.wrapField(Fields::methods, m_methods);
|
|
|
|
if (name == Fields::bindings)
|
|
|
|
return self.wrapField(Fields::bindings, m_bindings);
|
|
|
|
if (name == Fields::comments)
|
|
|
|
return CommentableDomElement::field(self, name);
|
|
|
|
if (name == Fields::children)
|
|
|
|
return self.wrapField(Fields::children, m_children);
|
|
|
|
|
|
|
|
if (name == Fields::nextScope) {
|
|
|
|
if (nextScopePath())
|
|
|
|
return self.subReferenceItem(PathEls::Field(Fields::nextScope), nextScopePath());
|
|
|
|
else
|
|
|
|
return DomItem();
|
|
|
|
}
|
|
|
|
if (name == Fields::prototypes) {
|
|
|
|
if (prototypePaths().isEmpty())
|
|
|
|
return DomItem();
|
|
|
|
return self.subReferencesItem(PathEls::Field(Fields::prototypes), m_prototypePaths);
|
|
|
|
}
|
|
|
|
if (name == Fields::annotations)
|
|
|
|
return self.wrapField(Fields::annotations, m_annotations);
|
|
|
|
if (name == Fields::propertyDefs)
|
2021-03-23 10:02:18 +00:00
|
|
|
return self.wrapField(Fields::propertyDefs, m_propertyDefs);
|
2024-01-02 14:56:03 +00:00
|
|
|
if (name == Fields::propertyInfos) {
|
|
|
|
// Need to explicitly copy self here since we might store this and call it later.
|
|
|
|
return self.subMapItem(Map(
|
|
|
|
pathFromOwner().field(Fields::propertyInfos),
|
|
|
|
[copiedSelf = self](const DomItem &map, const QString &k) {
|
|
|
|
return map.wrap(PathEls::Key(k), copiedSelf.propertyInfoWithName(k));
|
|
|
|
},
|
|
|
|
[copiedSelf = self](const DomItem &) { return copiedSelf.propertyInfoNames(); },
|
|
|
|
QLatin1String("PropertyInfo")));
|
|
|
|
}
|
|
|
|
if (name == Fields::nameIdentifiers && m_nameIdentifiers) {
|
|
|
|
return self.subScriptElementWrapperItem(m_nameIdentifiers);
|
|
|
|
}
|
|
|
|
if (name == Fields::defaultPropertyName) {
|
|
|
|
return self.subDataItem(PathEls::Field(Fields::defaultPropertyName),
|
|
|
|
defaultPropertyName(self));
|
2021-03-23 10:02:18 +00:00
|
|
|
}
|
|
|
|
static QStringList knownLookups({ QString::fromUtf16(Fields::fileLocationsTree) });
|
2024-01-02 14:56:03 +00:00
|
|
|
if (!knownLookups.contains(name)) {
|
2021-03-23 10:02:18 +00:00
|
|
|
qCWarning(domLog()) << "Asked non existing field " << name << " in QmlObject "
|
|
|
|
<< pathFromOwner();
|
2024-01-02 14:56:03 +00:00
|
|
|
}
|
2021-03-23 10:02:18 +00:00
|
|
|
return DomItem();
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
void QmlObject::updatePathFromOwner(const Path &newPath)
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
DomElement::updatePathFromOwner(newPath);
|
|
|
|
updatePathFromOwnerMultiMap(m_propertyDefs, newPath.field(Fields::propertyDefs));
|
|
|
|
updatePathFromOwnerMultiMap(m_bindings, newPath.field(Fields::bindings));
|
|
|
|
updatePathFromOwnerMultiMap(m_methods, newPath.field(Fields::methods));
|
|
|
|
updatePathFromOwnerQList(m_children, newPath.field(Fields::children));
|
|
|
|
updatePathFromOwnerQList(m_annotations, newPath.field(Fields::annotations));
|
|
|
|
}
|
|
|
|
|
|
|
|
QString QmlObject::localDefaultPropertyName() const
|
|
|
|
{
|
|
|
|
if (!m_defaultPropertyName.isEmpty())
|
|
|
|
return m_defaultPropertyName;
|
|
|
|
for (const PropertyDefinition &pDef : m_propertyDefs)
|
|
|
|
if (pDef.isDefaultMember)
|
|
|
|
return pDef.name;
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
QString QmlObject::defaultPropertyName(const DomItem &self) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
QString dProp = localDefaultPropertyName();
|
|
|
|
if (!dProp.isEmpty())
|
|
|
|
return dProp;
|
|
|
|
QString res = QStringLiteral(u"data");
|
|
|
|
self.visitPrototypeChain(
|
2023-09-13 13:05:12 +00:00
|
|
|
[&res](const DomItem &obj) {
|
2021-03-23 10:02:18 +00:00
|
|
|
if (const QmlObject *objPtr = obj.as<QmlObject>()) {
|
|
|
|
QString dProp = objPtr->localDefaultPropertyName();
|
|
|
|
if (!dProp.isEmpty()) {
|
|
|
|
res = dProp;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
VisitPrototypesOption::SkipFirst);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
bool QmlObject::iterateSubOwners(const DomItem &self, function_ref<bool(const DomItem &)> visitor) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
2023-12-13 14:24:34 +00:00
|
|
|
bool cont = self.field(Fields::bindings).visitKeys([visitor](const QString &, const DomItem &bs) {
|
2023-09-13 13:05:12 +00:00
|
|
|
return bs.visitIndexes([visitor](const DomItem &b) {
|
2021-03-23 10:02:18 +00:00
|
|
|
DomItem v = b.field(Fields::value);
|
|
|
|
if (std::shared_ptr<ScriptExpression> vPtr = v.ownerAs<ScriptExpression>()) {
|
|
|
|
if (!visitor(v))
|
|
|
|
return false;
|
|
|
|
return v.iterateSubOwners(visitor); // currently not needed, avoid?
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
});
|
2023-09-13 13:05:12 +00:00
|
|
|
cont = cont && self.field(Fields::children).visitIndexes([visitor](const DomItem &qmlObj) {
|
2021-03-23 10:02:18 +00:00
|
|
|
if (const QmlObject *qmlObjPtr = qmlObj.as<QmlObject>()) {
|
|
|
|
return qmlObjPtr->iterateSubOwners(qmlObj, visitor);
|
|
|
|
}
|
|
|
|
Q_ASSERT(false);
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
static QStringList dotExpressionToList(const std::shared_ptr<ScriptExpression> &expr)
|
2022-01-20 10:01:54 +00:00
|
|
|
{
|
|
|
|
QStringList res;
|
|
|
|
AST::Node *node = (expr ? expr->ast() : nullptr);
|
|
|
|
while (node) {
|
|
|
|
switch (node->kind) {
|
|
|
|
case AST::Node::Kind_IdentifierExpression: {
|
|
|
|
AST::IdentifierExpression *id = AST::cast<AST::IdentifierExpression *>(node);
|
|
|
|
res.prepend(id->name.toString());
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
case AST::Node::Kind_FieldMemberExpression: {
|
|
|
|
AST::FieldMemberExpression *id = AST::cast<AST::FieldMemberExpression *>(node);
|
|
|
|
res.prepend(id->name.toString());
|
|
|
|
node = id->base;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
qCDebug(writeOutLog).noquote() << "Could not convert dot expression to list for:\n"
|
|
|
|
<< expr->astRelocatableDump();
|
|
|
|
return QStringList();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
LocallyResolvedAlias QmlObject::resolveAlias(const DomItem &self,
|
2022-01-20 10:01:54 +00:00
|
|
|
std::shared_ptr<ScriptExpression> accessSequence) const
|
|
|
|
{
|
|
|
|
QStringList accessSequenceList = dotExpressionToList(accessSequence);
|
|
|
|
return resolveAlias(self, accessSequenceList);
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
LocallyResolvedAlias QmlObject::resolveAlias(const DomItem &self, const QStringList &accessSequence) const
|
2022-01-20 10:01:54 +00:00
|
|
|
{
|
|
|
|
LocallyResolvedAlias res;
|
|
|
|
QSet<QString> visitedAlias;
|
|
|
|
if (accessSequence.isEmpty()) {
|
|
|
|
return res;
|
|
|
|
} else if (accessSequence.size() > 3) {
|
|
|
|
res.status = LocallyResolvedAlias::Status::TooDeep;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
QString idName = accessSequence.first();
|
|
|
|
DomItem idTarget = self.component()
|
|
|
|
.field(Fields::ids)
|
|
|
|
.key(idName)
|
|
|
|
.index(0)
|
|
|
|
.field(Fields::referredObject)
|
|
|
|
.get();
|
|
|
|
if (!idTarget)
|
|
|
|
return res;
|
|
|
|
res.baseObject = idTarget;
|
|
|
|
res.accessedPath = accessSequence.mid(1);
|
|
|
|
res.typeName = idTarget.name();
|
|
|
|
res.status = LocallyResolvedAlias::Status::ResolvedObject;
|
|
|
|
// check if it refers to locally defined props/objs
|
|
|
|
while (!res.accessedPath.isEmpty()) {
|
|
|
|
QString pNow = res.accessedPath.first();
|
|
|
|
DomItem defNow = res.baseObject.propertyDefs().key(pNow).index(0);
|
|
|
|
if (const PropertyDefinition *defNowPtr = defNow.as<PropertyDefinition>()) {
|
|
|
|
if (defNowPtr->isAlias()) {
|
|
|
|
res.typeName = QString();
|
|
|
|
++res.nAliases;
|
|
|
|
QString aliasPath = defNow.canonicalPath().toString();
|
|
|
|
if (visitedAlias.contains(aliasPath)) {
|
|
|
|
res.status = LocallyResolvedAlias::Status::Loop;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
visitedAlias.insert(aliasPath);
|
|
|
|
DomItem valNow = res.baseObject.bindings().key(pNow).index(0);
|
|
|
|
if (std::shared_ptr<ScriptExpression> exp =
|
|
|
|
valNow.field(Fields::value).ownerAs<ScriptExpression>()) {
|
|
|
|
QStringList expList = dotExpressionToList(exp);
|
|
|
|
if (expList.isEmpty()) {
|
|
|
|
res.status = LocallyResolvedAlias::Status::Invalid;
|
|
|
|
return res;
|
|
|
|
} else if (expList.size() > 3) {
|
|
|
|
res.status = LocallyResolvedAlias::Status::TooDeep;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
idName = expList.first();
|
|
|
|
idTarget = self.component()
|
|
|
|
.field(Fields::ids)
|
|
|
|
.key(idName)
|
|
|
|
.index(0)
|
|
|
|
.field(Fields::referredObject)
|
|
|
|
.get();
|
|
|
|
res.baseObject = idTarget;
|
|
|
|
res.accessedPath = expList.mid(1) + res.accessedPath.mid(1);
|
|
|
|
if (!idTarget) {
|
|
|
|
res.status = LocallyResolvedAlias::Status::Invalid;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
res.status = LocallyResolvedAlias::Status::ResolvedObject;
|
|
|
|
res.typeName = idTarget.name();
|
|
|
|
} else {
|
|
|
|
res.status = LocallyResolvedAlias::Status::Invalid;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
res.localPropertyDef = defNow;
|
|
|
|
res.typeName = defNowPtr->typeName;
|
|
|
|
res.accessedPath = res.accessedPath.mid(1);
|
|
|
|
DomItem valNow = res.baseObject.bindings().key(pNow).index(0).field(Fields::value);
|
|
|
|
if (valNow.internalKind() == DomType::QmlObject) {
|
|
|
|
res.baseObject = valNow;
|
|
|
|
res.typeName = valNow.name();
|
|
|
|
res.status = LocallyResolvedAlias::Status::ResolvedObject;
|
|
|
|
} else {
|
|
|
|
res.status = LocallyResolvedAlias::Status::ResolvedProperty;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2023-09-13 15:36:59 +00:00
|
|
|
MutableDomItem QmlObject::addPropertyDef(
|
|
|
|
MutableDomItem &self, const PropertyDefinition &propertyDef, AddOption option)
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
Path p = addPropertyDef(propertyDef, option);
|
|
|
|
if (p.last().headIndex(0) > 1)
|
|
|
|
self.owningItemPtr()->addErrorLocal(domParsingErrors().error(
|
|
|
|
tr("Repeated PropertyDefinition with name %1").arg(propertyDef.name)));
|
|
|
|
return self.owner().path(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
MutableDomItem QmlObject::addBinding(MutableDomItem &self, Binding binding, AddOption option)
|
|
|
|
{
|
|
|
|
Path p = addBinding(binding, option);
|
|
|
|
if (p && p.last().headIndex(0) > 1)
|
|
|
|
self.owningItemPtr()->addErrorLocal(
|
|
|
|
domParsingErrors().error(tr("Repeated binding with name %1").arg(binding.name())));
|
|
|
|
return self.owner().path(p);
|
|
|
|
}
|
|
|
|
|
2023-09-13 15:36:59 +00:00
|
|
|
MutableDomItem QmlObject::addMethod(
|
|
|
|
MutableDomItem &self, const MethodInfo &functionDef, AddOption option)
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
Path p = addMethod(functionDef, option);
|
|
|
|
if (p.last().headIndex(0) > 1)
|
|
|
|
self.owningItemPtr()->addErrorLocal(
|
|
|
|
domParsingErrors().error(tr("Repeated Method with name %1").arg(functionDef.name)));
|
|
|
|
return self.owner().path(p);
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
void QmlObject::writeOut(const DomItem &self, OutWriter &ow, const QString &onTarget) const
|
2021-03-23 14:37:32 +00:00
|
|
|
{
|
2021-09-03 09:13:07 +00:00
|
|
|
const quint32 posOfNewElements = std::numeric_limits<quint32>::max();
|
2021-03-23 14:37:32 +00:00
|
|
|
bool isRootObject = pathFromOwner().length() == 5
|
|
|
|
&& pathFromOwner()[0] == Path::Field(Fields::components)
|
|
|
|
&& pathFromOwner()[3] == Path::Field(Fields::objects);
|
2021-09-03 09:13:07 +00:00
|
|
|
QString code;
|
|
|
|
DomItem owner = self.owner();
|
|
|
|
if (std::shared_ptr<QmlFile> qmlFilePtr = self.ownerAs<QmlFile>())
|
|
|
|
code = qmlFilePtr->code();
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(IdentifierRegion, name());
|
2021-03-23 14:37:32 +00:00
|
|
|
if (!onTarget.isEmpty())
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.space().writeRegion(OnTokenRegion).space().writeRegion(OnTargetRegion, onTarget);
|
2023-09-10 18:17:44 +00:00
|
|
|
ow.writeRegion(LeftBraceRegion, u" {");
|
2021-03-23 14:37:32 +00:00
|
|
|
int baseIndent = ow.increaseIndent();
|
|
|
|
int spacerId = 0;
|
|
|
|
if (!idStr().isEmpty()) { // *always* put id first
|
|
|
|
DomItem myId = self.component().field(Fields::ids).key(idStr()).index(0);
|
|
|
|
if (myId)
|
|
|
|
myId.writeOutPre(ow);
|
|
|
|
ow.ensureNewline()
|
2023-09-29 13:32:33 +00:00
|
|
|
.writeRegion(IdTokenRegion)
|
|
|
|
.writeRegion(IdColonTokenRegion)
|
2021-03-23 14:37:32 +00:00
|
|
|
.space()
|
2023-09-29 13:32:33 +00:00
|
|
|
.writeRegion(IdNameRegion, idStr());
|
2022-11-06 19:42:07 +00:00
|
|
|
if (ow.lineWriter.options().attributesSequence
|
|
|
|
== LineWriterOptions::AttributesSequence::Normalize) {
|
|
|
|
ow.ensureNewline(2);
|
|
|
|
}
|
2023-09-10 18:17:44 +00:00
|
|
|
if (myId) {
|
2021-03-23 14:37:32 +00:00
|
|
|
myId.writeOutPost(ow);
|
2023-09-10 18:17:44 +00:00
|
|
|
ow.ensureNewline(1);
|
|
|
|
}
|
2021-03-23 14:37:32 +00:00
|
|
|
}
|
|
|
|
quint32 counter = ow.counter();
|
|
|
|
DomItem component;
|
|
|
|
if (isRootObject)
|
|
|
|
component = self.containingObject();
|
2023-12-13 14:24:34 +00:00
|
|
|
auto startLoc = [&](const FileLocations::Tree &l) {
|
2021-03-23 14:37:32 +00:00
|
|
|
if (l)
|
|
|
|
return l->info().fullRegion;
|
2021-09-03 09:13:07 +00:00
|
|
|
return SourceLocation(posOfNewElements, 0, 0, 0);
|
2021-03-23 14:37:32 +00:00
|
|
|
};
|
|
|
|
if (ow.lineWriter.options().attributesSequence
|
|
|
|
== LineWriterOptions::AttributesSequence::Preserve) {
|
|
|
|
QList<QPair<SourceLocation, DomItem>> attribs;
|
|
|
|
AttachedInfoLookupResult<FileLocations::Tree> objLoc =
|
|
|
|
FileLocations::findAttachedInfo(self);
|
|
|
|
FileLocations::Tree componentLoc;
|
|
|
|
if (isRootObject && objLoc.foundTree)
|
|
|
|
componentLoc = objLoc.foundTree->parent()->parent();
|
2023-12-13 14:24:34 +00:00
|
|
|
auto addMMap
|
|
|
|
= [&attribs, &startLoc](const DomItem &base, const FileLocations::Tree &baseLoc) {
|
2021-03-23 14:37:32 +00:00
|
|
|
if (!base)
|
|
|
|
return;
|
2023-09-13 15:36:59 +00:00
|
|
|
const auto values = base.values();
|
|
|
|
for (const auto &els : values) {
|
2021-03-23 14:37:32 +00:00
|
|
|
FileLocations::Tree elsLoc =
|
|
|
|
FileLocations::find(baseLoc, els.pathFromOwner().last());
|
2023-09-18 09:10:51 +00:00
|
|
|
const auto elsValues = els.values();
|
|
|
|
for (const auto &el : elsValues) {
|
2021-03-23 14:37:32 +00:00
|
|
|
FileLocations::Tree elLoc =
|
|
|
|
FileLocations::find(elsLoc, el.pathFromOwner().last());
|
|
|
|
attribs.append(std::make_pair(startLoc(elLoc), el));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
auto addMyMMap = [this, &objLoc, &self, &addMMap](QStringView fieldName) {
|
|
|
|
DomItem base = this->field(self, fieldName);
|
|
|
|
addMMap(base, FileLocations::find(objLoc.foundTree, base.pathFromOwner().last()));
|
|
|
|
};
|
2023-12-13 14:24:34 +00:00
|
|
|
auto addSingleLevel
|
|
|
|
= [&attribs, &startLoc](const DomItem &base, const FileLocations::Tree &baseLoc) {
|
2021-03-23 14:37:32 +00:00
|
|
|
if (!base)
|
|
|
|
return;
|
2023-09-18 09:10:51 +00:00
|
|
|
const auto baseValues = base.values();
|
|
|
|
for (const auto &el : baseValues) {
|
2021-03-23 14:37:32 +00:00
|
|
|
FileLocations::Tree elLoc = FileLocations::find(baseLoc, el.pathFromOwner().last());
|
|
|
|
attribs.append(std::make_pair(startLoc(elLoc), el));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if (isRootObject) {
|
|
|
|
DomItem enums = component.field(Fields::enumerations);
|
|
|
|
addMMap(enums, FileLocations::find(componentLoc, enums.pathFromOwner().last()));
|
|
|
|
}
|
|
|
|
addMyMMap(Fields::propertyDefs);
|
|
|
|
addMyMMap(Fields::bindings);
|
|
|
|
addMyMMap(Fields::methods);
|
|
|
|
DomItem children = field(self, Fields::children);
|
|
|
|
addSingleLevel(children,
|
|
|
|
FileLocations::find(objLoc.foundTree, children.pathFromOwner().last()));
|
|
|
|
if (isRootObject) {
|
|
|
|
DomItem subCs = component.field(Fields::subComponents);
|
2023-09-13 13:05:12 +00:00
|
|
|
for (const DomItem &c : subCs.values()) {
|
2021-03-23 14:37:32 +00:00
|
|
|
AttachedInfoLookupResult<FileLocations::Tree> subLoc =
|
|
|
|
FileLocations::findAttachedInfo(c);
|
|
|
|
Q_ASSERT(subLoc.foundTree);
|
|
|
|
attribs.append(std::make_pair(startLoc(subLoc.foundTree), c));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::stable_sort(attribs.begin(), attribs.end(),
|
|
|
|
[](const std::pair<SourceLocation, DomItem> &el1,
|
|
|
|
const std::pair<SourceLocation, DomItem> &el2) {
|
|
|
|
if (el1.first.offset < el2.first.offset)
|
|
|
|
return true;
|
|
|
|
if (el1.first.offset > el2.first.offset)
|
|
|
|
return false;
|
|
|
|
int i = int(el1.second.internalKind())
|
|
|
|
- int(el2.second.internalKind());
|
|
|
|
return i < 0;
|
|
|
|
});
|
|
|
|
qsizetype iAttr = 0;
|
|
|
|
while (iAttr != attribs.size()) {
|
|
|
|
auto &el = attribs[iAttr++];
|
2021-09-03 09:13:07 +00:00
|
|
|
// check for an empty line before the current element, and preserve it
|
|
|
|
int preNewlines = 0;
|
|
|
|
quint32 start = el.first.offset;
|
2022-05-05 05:36:57 +00:00
|
|
|
if (start != posOfNewElements && size_t(code.size()) >= start) {
|
2021-09-03 09:13:07 +00:00
|
|
|
while (start != 0) {
|
|
|
|
QChar c = code.at(--start);
|
|
|
|
if (c == u'\n') {
|
|
|
|
if (++preNewlines == 2)
|
|
|
|
break;
|
|
|
|
} else if (!c.isSpace())
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (preNewlines == 0)
|
|
|
|
++preNewlines;
|
|
|
|
ow.ensureNewline(preNewlines);
|
2021-03-23 14:37:32 +00:00
|
|
|
if (el.second.internalKind() == DomType::PropertyDefinition && iAttr != attribs.size()
|
|
|
|
&& el.first.offset != ~quint32(0)) {
|
|
|
|
DomItem b;
|
|
|
|
auto &bPair = attribs[iAttr];
|
|
|
|
if (bPair.second.internalKind() == DomType::Binding
|
|
|
|
&& bPair.first.begin() < el.first.end()
|
|
|
|
&& bPair.second.name() == el.second.name()) {
|
|
|
|
b = bPair.second;
|
|
|
|
++iAttr;
|
|
|
|
b.writeOutPre(ow);
|
|
|
|
}
|
|
|
|
el.second.writeOut(ow);
|
|
|
|
if (b) {
|
|
|
|
ow.write(u": ");
|
|
|
|
if (const Binding *bPtr = b.as<Binding>())
|
|
|
|
bPtr->writeOutValue(b, ow);
|
|
|
|
else {
|
|
|
|
qWarning() << "Internal error casting binding to Binding in"
|
|
|
|
<< b.canonicalPath();
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(LeftBraceRegion).writeRegion(RightBraceRegion);
|
2021-03-23 14:37:32 +00:00
|
|
|
}
|
|
|
|
b.writeOutPost(ow);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
el.second.writeOut(ow);
|
|
|
|
}
|
2023-09-10 18:17:44 +00:00
|
|
|
ow.ensureNewline();
|
2021-03-23 14:37:32 +00:00
|
|
|
}
|
|
|
|
ow.decreaseIndent(1, baseIndent);
|
2024-01-17 18:26:46 +00:00
|
|
|
ow.writeRegion(RightBraceRegion);
|
2021-03-23 14:37:32 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
DomItem bindings = field(self, Fields::bindings);
|
|
|
|
DomItem propertyDefs = field(self, Fields::propertyDefs);
|
|
|
|
|
|
|
|
if (isRootObject) {
|
2023-09-13 15:36:59 +00:00
|
|
|
const auto descs = component.field(Fields::enumerations).values();
|
|
|
|
for (const auto &enumDescs : descs) {
|
|
|
|
const auto values = enumDescs.values();
|
|
|
|
for (const auto &enumDesc : values) {
|
2021-03-23 14:37:32 +00:00
|
|
|
ow.ensureNewline(1);
|
|
|
|
enumDesc.writeOut(ow);
|
|
|
|
ow.ensureNewline(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-09-03 09:17:24 +00:00
|
|
|
if (counter != ow.counter() || !idStr().isEmpty())
|
2021-03-23 14:37:32 +00:00
|
|
|
spacerId = ow.addNewlinesAutospacerCallback(2);
|
2021-09-28 02:54:30 +00:00
|
|
|
QSet<QString> mergedDefBinding;
|
|
|
|
for (const QString &defName : propertyDefs.sortedKeys()) {
|
2023-09-13 15:36:59 +00:00
|
|
|
const auto pDefs = propertyDefs.key(defName).values();
|
|
|
|
for (const auto &pDef : pDefs) {
|
2021-09-28 02:54:30 +00:00
|
|
|
const PropertyDefinition *pDefPtr = pDef.as<PropertyDefinition>();
|
|
|
|
Q_ASSERT(pDefPtr);
|
2021-03-23 14:37:32 +00:00
|
|
|
DomItem b;
|
2022-10-05 05:29:16 +00:00
|
|
|
bool uniqueDeclarationWithThisName = pDefs.size() == 1;
|
2021-09-28 02:54:30 +00:00
|
|
|
if (uniqueDeclarationWithThisName && !pDefPtr->isRequired)
|
2023-09-13 13:05:12 +00:00
|
|
|
bindings.key(pDef.name()).visitIndexes([&b, pDefPtr](const DomItem &el) {
|
2021-09-28 02:54:30 +00:00
|
|
|
const Binding *elPtr = el.as<Binding>();
|
|
|
|
if (elPtr && elPtr->bindingType() == BindingType::Normal) {
|
|
|
|
switch (elPtr->valueKind()) {
|
|
|
|
case BindingValueKind::ScriptExpression:
|
|
|
|
b = el;
|
|
|
|
break;
|
|
|
|
case BindingValueKind::Array:
|
|
|
|
if (!pDefPtr->isDefaultMember
|
|
|
|
&& pDefPtr->isParametricType())
|
|
|
|
b = el;
|
|
|
|
break;
|
|
|
|
case BindingValueKind::Object:
|
|
|
|
if (!pDefPtr->isDefaultMember
|
|
|
|
&& !pDefPtr->isParametricType())
|
|
|
|
b = el;
|
|
|
|
break;
|
|
|
|
case BindingValueKind::Empty:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
if (b) {
|
|
|
|
mergedDefBinding.insert(defName);
|
2021-03-23 14:37:32 +00:00
|
|
|
b.writeOutPre(ow);
|
2021-09-28 02:54:30 +00:00
|
|
|
}
|
2021-03-23 14:37:32 +00:00
|
|
|
pDef.writeOut(ow);
|
|
|
|
if (b) {
|
|
|
|
ow.write(u": ");
|
|
|
|
if (const Binding *bPtr = b.as<Binding>())
|
|
|
|
bPtr->writeOutValue(b, ow);
|
|
|
|
else {
|
|
|
|
qWarning() << "Internal error casting binding to Binding in"
|
|
|
|
<< b.canonicalPath();
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(LeftBraceRegion).writeRegion(RightBraceRegion);
|
2021-03-23 14:37:32 +00:00
|
|
|
}
|
|
|
|
b.writeOutPost(ow);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ow.removeTextAddCallback(spacerId);
|
2021-09-03 09:17:24 +00:00
|
|
|
QList<DomItem> signalList, methodList;
|
2023-09-13 15:36:59 +00:00
|
|
|
const auto fields = field(self, Fields::methods).values();
|
|
|
|
for (const auto &ms : fields) {
|
|
|
|
const auto values = ms.values();
|
|
|
|
for (const auto &m : values) {
|
2021-09-03 09:17:24 +00:00
|
|
|
const MethodInfo *mPtr = m.as<MethodInfo>();
|
|
|
|
if (mPtr && mPtr->methodType == MethodInfo::MethodType::Signal)
|
|
|
|
signalList.append(m);
|
|
|
|
else
|
|
|
|
methodList.append(m);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (counter != ow.counter())
|
|
|
|
spacerId = ow.addNewlinesAutospacerCallback(2);
|
2023-09-18 09:10:51 +00:00
|
|
|
for (const auto &sig : std::as_const(signalList)) {
|
2021-09-03 09:17:24 +00:00
|
|
|
ow.ensureNewline();
|
|
|
|
sig.writeOut(ow);
|
|
|
|
ow.ensureNewline();
|
|
|
|
}
|
|
|
|
ow.removeTextAddCallback(spacerId);
|
|
|
|
if (counter != ow.counter())
|
|
|
|
spacerId = ow.addNewlinesAutospacerCallback(2);
|
2022-11-23 18:33:40 +00:00
|
|
|
bool first = true;
|
2023-09-18 09:10:51 +00:00
|
|
|
for (const auto &method : std::as_const(methodList)) {
|
2022-11-23 18:33:40 +00:00
|
|
|
if (!first && ow.lineWriter.options().functionsSpacing) {
|
|
|
|
ow.newline();
|
|
|
|
}
|
2021-09-03 09:17:24 +00:00
|
|
|
ow.ensureNewline();
|
2022-11-23 18:33:40 +00:00
|
|
|
first = false;
|
2021-09-03 09:17:24 +00:00
|
|
|
method.writeOut(ow);
|
|
|
|
ow.ensureNewline();
|
|
|
|
}
|
|
|
|
ow.removeTextAddCallback(spacerId);
|
2021-03-23 14:37:32 +00:00
|
|
|
QList<DomItem> normalBindings, signalHandlers, delayedBindings;
|
2023-09-13 15:36:59 +00:00
|
|
|
for (const auto &bName : bindings.sortedKeys()) {
|
2021-09-28 02:54:30 +00:00
|
|
|
bool skipFirstNormal = mergedDefBinding.contains(bName);
|
2023-09-13 15:36:59 +00:00
|
|
|
const auto values = bindings.key(bName).values();
|
|
|
|
for (const auto &b : values) {
|
2021-03-23 14:37:32 +00:00
|
|
|
const Binding *bPtr = b.as<Binding>();
|
|
|
|
if (skipFirstNormal) {
|
|
|
|
if (bPtr && bPtr->bindingType() == BindingType::Normal) {
|
|
|
|
skipFirstNormal = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (bPtr->valueKind() == BindingValueKind::Array
|
|
|
|
|| bPtr->valueKind() == BindingValueKind::Object)
|
|
|
|
delayedBindings.append(b);
|
|
|
|
else if (b.field(Fields::isSignalHandler).value().toBool(false))
|
|
|
|
signalHandlers.append(b);
|
|
|
|
else
|
|
|
|
normalBindings.append(b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (counter != ow.counter())
|
|
|
|
spacerId = ow.addNewlinesAutospacerCallback(2);
|
2023-09-18 09:10:51 +00:00
|
|
|
for (const auto &b : std::as_const(normalBindings))
|
2021-03-23 14:37:32 +00:00
|
|
|
b.writeOut(ow);
|
|
|
|
ow.removeTextAddCallback(spacerId);
|
|
|
|
if (counter != ow.counter())
|
|
|
|
spacerId = ow.addNewlinesAutospacerCallback(2);
|
2023-09-18 09:10:51 +00:00
|
|
|
for (const auto &b : std::as_const(delayedBindings))
|
2021-09-03 09:17:24 +00:00
|
|
|
b.writeOut(ow);
|
2021-03-23 14:37:32 +00:00
|
|
|
ow.removeTextAddCallback(spacerId);
|
|
|
|
if (counter != ow.counter())
|
|
|
|
spacerId = ow.addNewlinesAutospacerCallback(2);
|
2023-09-18 09:10:51 +00:00
|
|
|
for (const auto &b : std::as_const(signalHandlers))
|
2021-03-23 14:37:32 +00:00
|
|
|
b.writeOut(ow);
|
|
|
|
ow.removeTextAddCallback(spacerId);
|
|
|
|
if (counter != ow.counter())
|
|
|
|
spacerId = ow.addNewlinesAutospacerCallback(2);
|
2022-11-23 18:33:40 +00:00
|
|
|
first = true;
|
2023-09-13 15:36:59 +00:00
|
|
|
const auto values = field(self, Fields::children).values();
|
|
|
|
for (const auto &c : values) {
|
2022-11-06 20:40:50 +00:00
|
|
|
if (!first && ow.lineWriter.options().objectsSpacing) {
|
|
|
|
ow.newline().newline();
|
|
|
|
}
|
|
|
|
first = false;
|
2021-03-23 14:37:32 +00:00
|
|
|
ow.ensureNewline();
|
|
|
|
c.writeOut(ow);
|
|
|
|
}
|
|
|
|
ow.removeTextAddCallback(spacerId);
|
|
|
|
if (isRootObject) {
|
|
|
|
// we are a root object, possibly add components
|
|
|
|
DomItem subComps = component.field(Fields::subComponents);
|
|
|
|
if (counter != ow.counter())
|
|
|
|
spacerId = ow.addNewlinesAutospacerCallback(2);
|
2023-09-13 15:36:59 +00:00
|
|
|
const auto values = subComps.values();
|
|
|
|
for (const auto &subC : values) {
|
2021-03-23 14:37:32 +00:00
|
|
|
ow.ensureNewline();
|
|
|
|
subC.writeOut(ow);
|
|
|
|
}
|
|
|
|
ow.removeTextAddCallback(spacerId);
|
|
|
|
}
|
|
|
|
ow.decreaseIndent(1, baseIndent);
|
2024-01-17 18:26:46 +00:00
|
|
|
ow.ensureNewline().writeRegion(RightBraceRegion);
|
2021-03-23 14:37:32 +00:00
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
Binding::Binding(const QString &name, std::unique_ptr<BindingValue> value, BindingType bindingType)
|
2021-03-23 10:02:18 +00:00
|
|
|
: m_bindingType(bindingType), m_name(name), m_value(std::move(value))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
Binding::Binding(
|
|
|
|
const QString &name, const std::shared_ptr<ScriptExpression> &value,
|
|
|
|
BindingType bindingType)
|
2021-03-23 10:02:18 +00:00
|
|
|
: Binding(name, std::make_unique<BindingValue>(value), bindingType)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
Binding::Binding(const QString &name, const QString &scriptCode, BindingType bindingType)
|
2021-03-23 10:02:18 +00:00
|
|
|
: Binding(name,
|
2022-06-29 09:08:45 +00:00
|
|
|
std::make_unique<BindingValue>(std::make_shared<ScriptExpression>(
|
2022-03-17 12:51:27 +00:00
|
|
|
scriptCode, ScriptExpression::ExpressionType::BindingExpression, 0,
|
2022-06-29 09:08:45 +00:00
|
|
|
Binding::preCodeForName(name), Binding::postCodeForName(name))),
|
2021-03-23 10:02:18 +00:00
|
|
|
bindingType)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
Binding::Binding(const QString &name, const QmlObject &value, BindingType bindingType)
|
2021-03-23 10:02:18 +00:00
|
|
|
: Binding(name, std::make_unique<BindingValue>(value), bindingType)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
Binding::Binding(const QString &name, const QList<QmlObject> &value, BindingType bindingType)
|
2021-03-23 10:02:18 +00:00
|
|
|
: Binding(name, std::make_unique<BindingValue>(value), bindingType)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Binding::Binding(const Binding &o)
|
|
|
|
: m_bindingType(o.m_bindingType),
|
|
|
|
m_name(o.m_name),
|
|
|
|
m_annotations(o.m_annotations),
|
2023-10-18 20:10:13 +00:00
|
|
|
m_comments(o.m_comments),
|
|
|
|
m_bindingIdentifiers(o.m_bindingIdentifiers)
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
if (o.m_value) {
|
|
|
|
m_value = std::make_unique<BindingValue>(*o.m_value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Binding::~Binding() { }
|
|
|
|
|
|
|
|
Binding &Binding::operator=(const Binding &o)
|
|
|
|
{
|
|
|
|
m_name = o.m_name;
|
|
|
|
m_bindingType = o.m_bindingType;
|
|
|
|
m_annotations = o.m_annotations;
|
|
|
|
m_comments = o.m_comments;
|
2023-10-18 20:10:13 +00:00
|
|
|
m_bindingIdentifiers = o.m_bindingIdentifiers;
|
2021-03-23 10:02:18 +00:00
|
|
|
if (o.m_value) {
|
|
|
|
if (!m_value)
|
|
|
|
m_value = std::make_unique<BindingValue>(*o.m_value);
|
|
|
|
else
|
|
|
|
*m_value = *o.m_value;
|
|
|
|
} else {
|
|
|
|
m_value.reset();
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
bool Binding::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
bool cont = true;
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::name, m_name);
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::isSignalHandler, isSignalHandler());
|
|
|
|
if (!m_value)
|
|
|
|
cont = cont && visitor(PathEls::Field(Fields::value), []() { return DomItem(); });
|
|
|
|
else
|
|
|
|
cont = cont && self.dvItemField(visitor, Fields::value, [this, &self]() {
|
|
|
|
return m_value->value(self);
|
|
|
|
});
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::bindingType, int(m_bindingType));
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::comments, m_comments);
|
|
|
|
cont = cont && self.dvValueLazyField(visitor, Fields::preCode, [this]() {
|
|
|
|
return this->preCode();
|
|
|
|
});
|
|
|
|
cont = cont && self.dvValueLazyField(visitor, Fields::postCode, [this]() {
|
|
|
|
return this->postCode();
|
|
|
|
});
|
2023-10-18 20:10:13 +00:00
|
|
|
if (m_bindingIdentifiers) {
|
|
|
|
cont = cont && self.dvItemField(visitor, Fields::bindingIdentifiers, [this, &self]() {
|
|
|
|
return self.subScriptElementWrapperItem(m_bindingIdentifiers);
|
|
|
|
});
|
|
|
|
}
|
2021-03-23 10:02:18 +00:00
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::annotations, m_annotations);
|
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
DomItem Binding::valueItem(const DomItem &self) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
if (!m_value)
|
|
|
|
return DomItem();
|
|
|
|
return m_value->value(self);
|
|
|
|
}
|
|
|
|
|
|
|
|
BindingValueKind Binding::valueKind() const
|
|
|
|
{
|
|
|
|
if (!m_value)
|
|
|
|
return BindingValueKind::Empty;
|
|
|
|
return m_value->kind;
|
|
|
|
}
|
|
|
|
|
|
|
|
QmlObject const *Binding::objectValue() const
|
|
|
|
{
|
|
|
|
if (valueKind() == BindingValueKind::Object)
|
|
|
|
return &(m_value->object);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
QmlObject *Binding::objectValue()
|
|
|
|
{
|
|
|
|
if (valueKind() == BindingValueKind::Object)
|
|
|
|
return &(m_value->object);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
QList<QmlObject> const *Binding::arrayValue() const
|
|
|
|
{
|
|
|
|
if (valueKind() == BindingValueKind::Array)
|
|
|
|
return &(m_value->array);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
QList<QmlObject> *Binding::arrayValue()
|
|
|
|
{
|
|
|
|
if (valueKind() == BindingValueKind::Array)
|
|
|
|
return &(m_value->array);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<ScriptExpression> Binding::scriptExpressionValue() const
|
|
|
|
{
|
|
|
|
if (valueKind() == BindingValueKind::ScriptExpression)
|
|
|
|
return m_value->scriptExpression;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<ScriptExpression> Binding::scriptExpressionValue()
|
|
|
|
{
|
|
|
|
if (valueKind() == BindingValueKind::ScriptExpression)
|
|
|
|
return m_value->scriptExpression;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
Path Binding::addAnnotation(const Path &selfPathFromOwner, const QmlObject &annotation, QmlObject **aPtr)
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
return appendUpdatableElementInQList(selfPathFromOwner.field(Fields::annotations),
|
|
|
|
m_annotations, annotation, aPtr);
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
void Binding::updatePathFromOwner(const Path &newPath)
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
Path base = newPath.field(Fields::annotations);
|
|
|
|
if (m_value)
|
|
|
|
m_value->updatePathFromOwner(newPath.field(Fields::value));
|
|
|
|
updatePathFromOwnerQList(m_annotations, newPath.field(Fields::annotations));
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
void Binding::writeOut(const DomItem &self, OutWriter &lw) const
|
2021-03-23 14:37:32 +00:00
|
|
|
{
|
|
|
|
lw.ensureNewline();
|
|
|
|
if (m_bindingType == BindingType::Normal) {
|
2023-09-29 13:32:33 +00:00
|
|
|
lw.writeRegion(IdentifierRegion, name());
|
|
|
|
lw.writeRegion(ColonTokenRegion).space();
|
2021-03-23 14:37:32 +00:00
|
|
|
writeOutValue(self, lw);
|
|
|
|
} else {
|
|
|
|
DomItem v = valueItem(self);
|
|
|
|
if (const QmlObject *vPtr = v.as<QmlObject>()) {
|
|
|
|
v.writeOutPre(lw);
|
|
|
|
vPtr->writeOut(v, lw, name());
|
|
|
|
v.writeOutPost(lw);
|
|
|
|
} else {
|
|
|
|
qCWarning(writeOutLog()) << "On Binding requires an QmlObject Value, not "
|
|
|
|
<< v.internalKindStr() << " at " << self.canonicalPath();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
void Binding::writeOutValue(const DomItem &self, OutWriter &lw) const
|
2021-03-23 14:37:32 +00:00
|
|
|
{
|
|
|
|
DomItem v = valueItem(self);
|
|
|
|
switch (valueKind()) {
|
|
|
|
case BindingValueKind::Empty:
|
|
|
|
qCWarning(writeOutLog()) << "Writing of empty binding " << name();
|
|
|
|
lw.write(u"{}");
|
|
|
|
break;
|
|
|
|
case BindingValueKind::Array:
|
|
|
|
if (const List *vPtr = v.as<List>()) {
|
|
|
|
v.writeOutPre(lw);
|
|
|
|
vPtr->writeOut(v, lw, false);
|
|
|
|
v.writeOutPost(lw);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BindingValueKind::Object:
|
|
|
|
case BindingValueKind::ScriptExpression:
|
|
|
|
v.writeOut(lw);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
bool QmltypesComponent::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
bool cont = Component::iterateDirectSubpaths(self, visitor);
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::exports, m_exports);
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::metaRevisions, m_metaRevisions);
|
|
|
|
if (!fileName().isEmpty())
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::fileName, fileName()); // remove?
|
2021-06-26 22:56:14 +00:00
|
|
|
cont = cont && self.dvValueField(visitor, Fields::interfaceNames, m_interfaceNames);
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::hasCustomParser, m_hasCustomParser);
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::valueTypeName, m_valueTypeName);
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::extensionTypeName, m_extensionTypeName);
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::accessSemantics, int(m_accessSemantics));
|
2021-03-23 10:02:18 +00:00
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
Export Export::fromString(
|
|
|
|
const Path &source, QStringView exp, const Path &typePath, const ErrorHandler &h)
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
Export res;
|
|
|
|
res.exportSourcePath = source;
|
|
|
|
res.typePath = typePath;
|
|
|
|
int slashIdx = exp.indexOf(QLatin1Char('/'));
|
|
|
|
int spaceIdx = exp.indexOf(QLatin1Char(' '));
|
|
|
|
if (spaceIdx == -1)
|
2022-10-05 05:29:16 +00:00
|
|
|
spaceIdx = exp.size();
|
2021-03-23 10:02:18 +00:00
|
|
|
else
|
|
|
|
res.version = Version::fromString(exp.mid(spaceIdx + 1));
|
|
|
|
if (!res.version.isValid())
|
|
|
|
domParsingErrors()
|
|
|
|
.error(tr("Expected string literal to contain 'Package/Name major.minor' "
|
|
|
|
"or 'Name major.minor' not '%1'.")
|
|
|
|
.arg(exp))
|
|
|
|
.handle(h);
|
|
|
|
if (slashIdx != -1)
|
|
|
|
res.uri = exp.left(slashIdx).toString();
|
|
|
|
res.typeName = exp.mid(slashIdx + 1, spaceIdx - (slashIdx + 1)).toString();
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
bool AttributeInfo::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
bool cont = true;
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::name, name);
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::access, int(access));
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::typeName, typeName);
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::isReadonly, isReadonly);
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::isList, isList);
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::comments, comments);
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::annotations, annotations);
|
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
Path AttributeInfo::addAnnotation(const Path &selfPathFromOwner, const QmlObject &annotation,
|
2021-03-23 10:02:18 +00:00
|
|
|
QmlObject **aPtr)
|
|
|
|
{
|
|
|
|
return appendUpdatableElementInQList(selfPathFromOwner.field(Fields::annotations), annotations,
|
|
|
|
annotation, aPtr);
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
void AttributeInfo::updatePathFromOwner(const Path &newPath)
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
Path base = newPath.field(Fields::annotations);
|
|
|
|
updatePathFromOwnerQList(annotations, newPath.field(Fields::annotations));
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
bool EnumDecl::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
bool cont = CommentableDomElement::iterateDirectSubpaths(self, visitor);
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::name, name());
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::values, m_values);
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::annotations, m_annotations);
|
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
void EnumDecl::updatePathFromOwner(const Path &newPath)
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
DomElement::updatePathFromOwner(newPath);
|
|
|
|
updatePathFromOwnerQList(m_annotations, newPath.field(Fields::annotations));
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
void EnumDecl::setAnnotations(const QList<QmlObject> &annotations)
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
m_annotations = annotations;
|
|
|
|
}
|
|
|
|
|
|
|
|
Path EnumDecl::addAnnotation(const QmlObject &annotation, QmlObject **aPtr)
|
|
|
|
{
|
|
|
|
return appendUpdatableElementInQList(pathFromOwner().field(Fields::annotations), m_annotations,
|
|
|
|
annotation, aPtr);
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
void EnumDecl::writeOut(const DomItem &self, OutWriter &ow) const
|
2021-03-23 14:37:32 +00:00
|
|
|
{
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(EnumKeywordRegion)
|
2021-03-23 14:37:32 +00:00
|
|
|
.space()
|
2023-09-29 13:32:33 +00:00
|
|
|
.writeRegion(IdentifierRegion, name())
|
2021-03-23 14:37:32 +00:00
|
|
|
.space()
|
2023-09-29 13:32:33 +00:00
|
|
|
.writeRegion(LeftBraceRegion);
|
2021-03-23 14:37:32 +00:00
|
|
|
int iLevel = ow.increaseIndent(1);
|
2023-09-13 15:36:59 +00:00
|
|
|
const auto values = self.field(Fields::values).values();
|
|
|
|
for (const auto &value : values) {
|
2021-03-23 14:37:32 +00:00
|
|
|
ow.ensureNewline();
|
|
|
|
value.writeOut(ow);
|
|
|
|
}
|
|
|
|
ow.decreaseIndent(1, iLevel);
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.ensureNewline().writeRegion(RightBraceRegion);
|
2021-03-23 14:37:32 +00:00
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
QList<Path> ImportScope::allSources(const DomItem &self) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
2021-06-08 08:38:20 +00:00
|
|
|
DomItem top = self.top();
|
|
|
|
DomItem env = top.environment();
|
2021-03-23 10:02:18 +00:00
|
|
|
Path selfPath = self.canonicalPath().field(Fields::allSources);
|
2021-06-08 08:38:20 +00:00
|
|
|
RefCacheEntry cached = (env ? RefCacheEntry::forPath(env, selfPath) : RefCacheEntry());
|
2021-03-23 10:02:18 +00:00
|
|
|
if (cached.cached == RefCacheEntry::Cached::All)
|
|
|
|
return cached.canonicalPaths;
|
|
|
|
QList<Path> res;
|
|
|
|
QSet<Path> knownPaths;
|
|
|
|
QList<Path> toDo(m_importSourcePaths.rbegin(), m_importSourcePaths.rend());
|
|
|
|
while (!toDo.isEmpty()) {
|
|
|
|
Path pNow = toDo.takeLast();
|
|
|
|
if (knownPaths.contains(pNow))
|
|
|
|
continue;
|
|
|
|
knownPaths.insert(pNow);
|
|
|
|
res.append(pNow);
|
2021-06-08 08:38:20 +00:00
|
|
|
DomItem sourceBase = top.path(pNow);
|
2023-09-13 15:36:59 +00:00
|
|
|
for (const DomItem &autoExp : sourceBase.field(Fields::autoExports).values()) {
|
2021-03-23 10:02:18 +00:00
|
|
|
if (const ModuleAutoExport *autoExpPtr = autoExp.as<ModuleAutoExport>()) {
|
|
|
|
Path newSource;
|
|
|
|
if (autoExpPtr->inheritVersion) {
|
|
|
|
Version v = autoExpPtr->import.version;
|
|
|
|
DomItem sourceVersion = sourceBase.field(Fields::version);
|
|
|
|
if (const Version *sourceVersionPtr = sourceVersion.as<Version>()) {
|
|
|
|
if (v.majorVersion < 0)
|
|
|
|
v.majorVersion = sourceVersionPtr->majorVersion;
|
|
|
|
if (v.minorVersion < 0)
|
|
|
|
v.minorVersion = sourceVersionPtr->minorVersion;
|
|
|
|
} else {
|
|
|
|
qWarning() << "autoExport with inherited version " << autoExp
|
|
|
|
<< " but missing version in source" << pNow;
|
|
|
|
}
|
|
|
|
Import toImport(autoExpPtr->import.uri, v);
|
|
|
|
newSource = toImport.importedPath();
|
|
|
|
} else {
|
|
|
|
newSource = autoExpPtr->import.importedPath();
|
|
|
|
}
|
|
|
|
if (newSource && !knownPaths.contains(newSource))
|
|
|
|
toDo.append(newSource);
|
|
|
|
} else {
|
|
|
|
qWarning() << "expected ModuleAutoExport not " << autoExp.internalKindStr()
|
|
|
|
<< "looking up autoExports of" << sourceBase;
|
|
|
|
Q_ASSERT(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-06-08 08:38:20 +00:00
|
|
|
if (env)
|
|
|
|
RefCacheEntry::addForPath(env, selfPath, RefCacheEntry { RefCacheEntry::Cached::All, res });
|
2021-03-23 10:02:18 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
bool ImportScope::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
bool cont = true;
|
|
|
|
cont = cont && self.dvReferencesField(visitor, Fields::importSources, m_importSourcePaths);
|
|
|
|
cont = cont && self.dvItemField(visitor, Fields::allSources, [this, &self]() -> DomItem {
|
|
|
|
return self.subListItem(List::fromQList<Path>(
|
|
|
|
self.pathFromOwner().field(Fields::allSources), allSources(self),
|
2023-09-13 13:05:12 +00:00
|
|
|
[](const DomItem &list, const PathEls::PathComponent &p, const Path &el) {
|
2021-03-23 10:02:18 +00:00
|
|
|
return list.subDataItem(p, el.toString());
|
|
|
|
}));
|
|
|
|
});
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::qualifiedImports, m_subImports);
|
|
|
|
cont = cont && self.dvItemField(visitor, Fields::imported, [this, &self]() -> DomItem {
|
|
|
|
return self.subMapItem(Map(
|
|
|
|
self.pathFromOwner().field(Fields::imported),
|
2023-12-13 14:24:34 +00:00
|
|
|
[this, &self](const DomItem &map, const QString &key) {
|
2021-03-23 10:02:18 +00:00
|
|
|
return map.subListItem(List::fromQList<DomItem>(
|
|
|
|
map.pathFromOwner().key(key), importedItemsWithName(self, key),
|
2023-09-13 13:05:12 +00:00
|
|
|
[](const DomItem &, const PathEls::PathComponent &, const DomItem &el) {
|
2021-03-23 10:02:18 +00:00
|
|
|
return el;
|
|
|
|
}));
|
|
|
|
},
|
2023-09-13 13:05:12 +00:00
|
|
|
[this, &self](const DomItem &) { return this->importedNames(self); },
|
2021-03-23 10:02:18 +00:00
|
|
|
QLatin1String("List<Export>")));
|
|
|
|
});
|
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
bool PropertyInfo::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
bool cont = true;
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::propertyDefs, propertyDefs);
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::bindings, bindings);
|
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
|
|
|
BindingValue::BindingValue() : kind(BindingValueKind::Empty) { }
|
|
|
|
|
|
|
|
BindingValue::BindingValue(const QmlObject &o) : kind(BindingValueKind::Object)
|
|
|
|
{
|
|
|
|
new (&object) QmlObject(o);
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
BindingValue::BindingValue(const std::shared_ptr<ScriptExpression> &o)
|
2021-03-23 10:02:18 +00:00
|
|
|
: kind(BindingValueKind::ScriptExpression)
|
|
|
|
{
|
|
|
|
new (&scriptExpression) std::shared_ptr<ScriptExpression>(o);
|
|
|
|
}
|
|
|
|
|
|
|
|
BindingValue::BindingValue(const QList<QmlObject> &l) : kind(BindingValueKind::Array)
|
|
|
|
{
|
|
|
|
new (&array) QList<QmlObject>(l);
|
|
|
|
}
|
|
|
|
|
|
|
|
BindingValue::~BindingValue()
|
|
|
|
{
|
|
|
|
clearValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
BindingValue::BindingValue(const BindingValue &o) : kind(o.kind)
|
|
|
|
{
|
|
|
|
switch (o.kind) {
|
|
|
|
case BindingValueKind::Empty:
|
|
|
|
break;
|
|
|
|
case BindingValueKind::Object:
|
|
|
|
new (&object) QmlObject(o.object);
|
|
|
|
break;
|
|
|
|
case BindingValueKind::ScriptExpression:
|
|
|
|
new (&scriptExpression) std::shared_ptr<ScriptExpression>(o.scriptExpression);
|
|
|
|
break;
|
|
|
|
case BindingValueKind::Array:
|
|
|
|
new (&array) QList<QmlObject>(o.array);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BindingValue &BindingValue::operator=(const BindingValue &o)
|
|
|
|
{
|
|
|
|
clearValue();
|
|
|
|
kind = o.kind;
|
|
|
|
switch (o.kind) {
|
|
|
|
case BindingValueKind::Empty:
|
|
|
|
break;
|
|
|
|
case BindingValueKind::Object:
|
|
|
|
new (&object) QmlObject(o.object);
|
|
|
|
break;
|
|
|
|
case BindingValueKind::ScriptExpression:
|
|
|
|
new (&scriptExpression) std::shared_ptr<ScriptExpression>(o.scriptExpression);
|
|
|
|
break;
|
|
|
|
case BindingValueKind::Array:
|
|
|
|
new (&array) QList<QmlObject>(o.array);
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
DomItem BindingValue::value(const DomItem &binding) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
switch (kind) {
|
|
|
|
case BindingValueKind::Empty:
|
|
|
|
break;
|
|
|
|
case BindingValueKind::Object:
|
|
|
|
return binding.copy(&object);
|
|
|
|
case BindingValueKind::ScriptExpression:
|
|
|
|
return binding.subOwnerItem(PathEls::Field(Fields::value), scriptExpression);
|
|
|
|
case BindingValueKind::Array:
|
|
|
|
return binding.subListItem(List::fromQListRef<QmlObject>(
|
|
|
|
binding.pathFromOwner().field(u"value"), array,
|
2023-09-18 08:53:19 +00:00
|
|
|
[](const DomItem &self, const PathEls::PathComponent &, const QmlObject &obj) {
|
2021-03-23 10:02:18 +00:00
|
|
|
return self.copy(&obj);
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
return DomItem();
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
void BindingValue::updatePathFromOwner(const Path &newPath)
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
switch (kind) {
|
|
|
|
case BindingValueKind::Empty:
|
|
|
|
break;
|
|
|
|
case BindingValueKind::Object:
|
|
|
|
object.updatePathFromOwner(newPath);
|
|
|
|
break;
|
|
|
|
case BindingValueKind::ScriptExpression:
|
|
|
|
break;
|
|
|
|
case BindingValueKind::Array:
|
|
|
|
updatePathFromOwnerQList(array, newPath);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BindingValue::clearValue()
|
|
|
|
{
|
|
|
|
switch (kind) {
|
|
|
|
case BindingValueKind::Empty:
|
|
|
|
break;
|
|
|
|
case BindingValueKind::Object:
|
|
|
|
object.~QmlObject();
|
|
|
|
break;
|
|
|
|
case BindingValueKind::ScriptExpression:
|
|
|
|
scriptExpression.~shared_ptr();
|
|
|
|
break;
|
|
|
|
case BindingValueKind::Array:
|
|
|
|
array.~QList<QmlObject>();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
kind = BindingValueKind::Empty;
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
ScriptExpression::ScriptExpression(
|
|
|
|
QStringView code, const std::shared_ptr<QQmlJS::Engine> &engine, AST::Node *ast,
|
|
|
|
const std::shared_ptr<AstComments> &comments, ExpressionType expressionType,
|
|
|
|
SourceLocation localOffset, int derivedFrom, QStringView preCode, QStringView postCode)
|
2021-09-14 16:49:53 +00:00
|
|
|
: OwningItem(derivedFrom),
|
|
|
|
m_expressionType(expressionType),
|
|
|
|
m_code(code),
|
|
|
|
m_preCode(preCode),
|
|
|
|
m_postCode(postCode),
|
|
|
|
m_engine(engine),
|
|
|
|
m_ast(ast),
|
|
|
|
m_astComments(comments),
|
|
|
|
m_localOffset(localOffset)
|
|
|
|
{
|
|
|
|
if (m_expressionType == ExpressionType::BindingExpression)
|
|
|
|
if (AST::ExpressionStatement *exp = AST::cast<AST::ExpressionStatement *>(m_ast))
|
|
|
|
m_ast = exp->expression;
|
|
|
|
Q_ASSERT(m_astComments);
|
|
|
|
}
|
|
|
|
|
2021-03-23 10:02:18 +00:00
|
|
|
ScriptExpression::ScriptExpression(const ScriptExpression &e) : OwningItem(e)
|
|
|
|
{
|
|
|
|
QMutexLocker l(mutex());
|
|
|
|
m_expressionType = e.m_expressionType;
|
|
|
|
m_engine = e.m_engine;
|
|
|
|
m_ast = e.m_ast;
|
|
|
|
if (m_codeStr.isEmpty()) {
|
|
|
|
m_code = e.m_code;
|
|
|
|
} else {
|
|
|
|
m_codeStr = e.m_codeStr;
|
|
|
|
m_code = m_codeStr;
|
|
|
|
}
|
|
|
|
m_localOffset = e.m_localOffset;
|
|
|
|
m_astComments = e.m_astComments;
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
std::shared_ptr<ScriptExpression> ScriptExpression::copyWithUpdatedCode(
|
|
|
|
const DomItem &self, const QString &code) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
std::shared_ptr<ScriptExpression> copy = makeCopy(self);
|
|
|
|
DomItem container = self.containingObject();
|
|
|
|
QString preCodeStr = container.field(Fields::preCode).value().toString(m_preCode.toString());
|
|
|
|
QString postCodeStr = container.field(Fields::postCode).value().toString(m_postCode.toString());
|
|
|
|
copy->setCode(code, preCodeStr, postCodeStr);
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
bool ScriptExpression::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
bool cont = OwningItem::iterateDirectSubpaths(self, visitor);
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::code, code());
|
|
|
|
if (!preCode().isEmpty())
|
|
|
|
cont = cont
|
|
|
|
&& self.dvValueField(visitor, Fields::preCode, preCode(),
|
|
|
|
ConstantData::Options::MapIsMap);
|
|
|
|
if (!postCode().isEmpty())
|
|
|
|
cont = cont
|
|
|
|
&& self.dvValueField(visitor, Fields::postCode, postCode(),
|
|
|
|
ConstantData::Options::MapIsMap);
|
|
|
|
cont = cont
|
|
|
|
&& self.dvValueLazyField(
|
|
|
|
visitor, Fields::localOffset,
|
2023-09-29 13:32:33 +00:00
|
|
|
[this]() { return sourceLocationToQCborValue(localOffset()); },
|
2021-03-23 10:02:18 +00:00
|
|
|
ConstantData::Options::MapIsMap);
|
|
|
|
cont = cont && self.dvValueLazyField(visitor, Fields::astRelocatableDump, [this]() {
|
|
|
|
return astRelocatableDump();
|
|
|
|
});
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::expressionType, int(expressionType()));
|
2023-04-05 14:43:50 +00:00
|
|
|
if (m_element) {
|
|
|
|
cont = cont && self.dvItemField(visitor, Fields::scriptElement, [this, &self]() {
|
|
|
|
return self.subScriptElementWrapperItem(m_element);
|
|
|
|
});
|
|
|
|
}
|
2021-03-23 10:02:18 +00:00
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
|
|
|
class FirstNodeVisitor : public VisitAll
|
|
|
|
{
|
|
|
|
public:
|
2024-09-16 09:53:17 +00:00
|
|
|
qsizetype minStart = 0;
|
|
|
|
qsizetype maxEnd = std::numeric_limits<qint32>::max(); // see also Lexer::checkFileLength().
|
2021-03-23 10:02:18 +00:00
|
|
|
AST::Node *firstNodeInRange = nullptr;
|
|
|
|
|
2024-09-16 09:53:17 +00:00
|
|
|
FirstNodeVisitor(qsizetype minStart, qsizetype maxEnd) : minStart(minStart), maxEnd(maxEnd) { }
|
2021-03-23 10:02:18 +00:00
|
|
|
|
|
|
|
bool preVisit(AST::Node *n) override
|
|
|
|
{
|
|
|
|
if (!VisitAll::uiKinds().contains(n->kind)) {
|
2024-09-16 09:53:17 +00:00
|
|
|
qsizetype start = n->firstSourceLocation().begin();
|
|
|
|
qsizetype end = n->lastSourceLocation().end();
|
2021-03-23 10:02:18 +00:00
|
|
|
if (!firstNodeInRange && minStart <= start && end <= maxEnd && start < end)
|
|
|
|
firstNodeInRange = n;
|
|
|
|
}
|
|
|
|
return !firstNodeInRange;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-09-16 09:53:17 +00:00
|
|
|
AST::Node *firstNodeInRange(AST::Node *n, qsizetype minStart = 0, qsizetype maxEnd = std::numeric_limits<qint32>::max())
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
FirstNodeVisitor visitor(minStart, maxEnd);
|
|
|
|
AST::Node::accept(n, &visitor);
|
|
|
|
return visitor.firstNodeInRange;
|
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
void ScriptExpression::setCode(const QString &code, const QString &preCode, const QString &postCode)
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
2024-02-06 15:30:31 +00:00
|
|
|
// TODO QTBUG-121933
|
2021-03-23 10:02:18 +00:00
|
|
|
m_codeStr = code;
|
2023-12-13 14:24:34 +00:00
|
|
|
QString resolvedPreCode, resolvedPostCode;
|
2024-02-06 15:30:31 +00:00
|
|
|
if (m_expressionType == ExpressionType::BindingExpression && preCode.isEmpty()) {
|
2023-12-13 14:24:34 +00:00
|
|
|
resolvedPreCode = Binding::preCodeForName(u"binding");
|
|
|
|
resolvedPostCode = Binding::postCodeForName(u"binding");
|
|
|
|
} else {
|
|
|
|
resolvedPreCode = preCode;
|
|
|
|
resolvedPostCode = postCode;
|
2022-03-17 12:51:27 +00:00
|
|
|
}
|
2023-12-13 14:24:34 +00:00
|
|
|
if (!resolvedPreCode.isEmpty() || !resolvedPostCode.isEmpty())
|
|
|
|
m_codeStr = resolvedPreCode + code + resolvedPostCode;
|
|
|
|
m_code = QStringView(m_codeStr).mid(resolvedPreCode.size(), code.size());
|
|
|
|
m_preCode = QStringView(m_codeStr).mid(0, resolvedPreCode.size());
|
|
|
|
m_postCode = QStringView(m_codeStr).mid(
|
|
|
|
resolvedPreCode.size() + code.size(), resolvedPostCode.size());
|
2021-03-23 10:02:18 +00:00
|
|
|
m_engine = nullptr;
|
|
|
|
m_ast = nullptr;
|
|
|
|
m_localOffset = SourceLocation();
|
|
|
|
if (!m_code.isEmpty()) {
|
|
|
|
IndentInfo preChange(m_preCode, 4);
|
2022-10-05 05:29:16 +00:00
|
|
|
m_localOffset.offset = m_preCode.size();
|
|
|
|
m_localOffset.length = m_code.size();
|
|
|
|
m_localOffset.startColumn = preChange.trailingString.size();
|
2021-03-23 10:02:18 +00:00
|
|
|
m_localOffset.startLine = preChange.nNewlines;
|
2022-06-29 09:08:45 +00:00
|
|
|
m_engine = std::make_shared<QQmlJS::Engine>();
|
|
|
|
m_astComments = std::make_shared<AstComments>(m_engine);
|
2024-02-06 15:30:31 +00:00
|
|
|
m_ast = parse(resolveParseMode());
|
|
|
|
|
2021-03-23 10:02:18 +00:00
|
|
|
if (AST::Program *programPtr = AST::cast<AST::Program *>(m_ast)) {
|
|
|
|
m_ast = programPtr->statements;
|
|
|
|
}
|
|
|
|
if (!m_preCode.isEmpty())
|
2022-10-05 05:29:16 +00:00
|
|
|
m_ast = firstNodeInRange(m_ast, m_preCode.size(),
|
|
|
|
m_preCode.size() + m_code.size());
|
2023-09-06 15:07:21 +00:00
|
|
|
if (auto *sList = AST::cast<AST::FormalParameterList *>(m_ast)) {
|
|
|
|
m_ast = sList->element;
|
|
|
|
}
|
2021-03-23 10:02:18 +00:00
|
|
|
if (m_expressionType != ExpressionType::FunctionBody) {
|
|
|
|
if (AST::StatementList *sList = AST::cast<AST::StatementList *>(m_ast)) {
|
|
|
|
if (!sList->next)
|
|
|
|
m_ast = sList->statement;
|
|
|
|
}
|
|
|
|
}
|
2021-09-14 16:49:53 +00:00
|
|
|
if (m_expressionType == ExpressionType::BindingExpression)
|
|
|
|
if (AST::ExpressionStatement *exp = AST::cast<AST::ExpressionStatement *>(m_ast))
|
|
|
|
m_ast = exp->expression;
|
2024-01-15 20:36:22 +00:00
|
|
|
|
|
|
|
CommentCollector collector;
|
2024-02-06 15:30:31 +00:00
|
|
|
collector.collectComments(m_engine, m_ast, m_astComments);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AST::Node *ScriptExpression::parse(const ParseMode mode)
|
|
|
|
{
|
|
|
|
QQmlJS::Lexer lexer(m_engine.get());
|
|
|
|
lexer.setCode(m_codeStr, /*lineno = */ 1, /*qmlMode=*/mode == ParseMode::QML);
|
|
|
|
QQmlJS::Parser parser(m_engine.get());
|
|
|
|
const bool parserSucceeded = [mode, &parser]() {
|
|
|
|
switch (mode) {
|
|
|
|
case ParseMode::QML:
|
|
|
|
return parser.parse();
|
|
|
|
case ParseMode::JS:
|
|
|
|
return parser.parseScript();
|
2023-11-20 16:39:49 +00:00
|
|
|
case ParseMode::ESM:
|
2024-02-06 15:46:52 +00:00
|
|
|
return parser.parseModule();
|
2024-02-06 15:30:31 +00:00
|
|
|
default:
|
|
|
|
Q_UNREACHABLE_RETURN(false);
|
|
|
|
}
|
|
|
|
}();
|
|
|
|
if (!parserSucceeded) {
|
|
|
|
addErrorLocal(domParsingErrors().error(tr("Parsing of code failed")));
|
|
|
|
}
|
|
|
|
const auto messages = parser.diagnosticMessages();
|
|
|
|
for (const DiagnosticMessage &msg : messages) {
|
|
|
|
ErrorMessage err = domParsingErrors().errorMessage(msg);
|
|
|
|
err.location.offset -= m_localOffset.offset;
|
|
|
|
err.location.startLine -= m_localOffset.startLine;
|
|
|
|
if (err.location.startLine == 1)
|
|
|
|
err.location.startColumn -= m_localOffset.startColumn;
|
|
|
|
addErrorLocal(std::move(err));
|
2021-03-23 10:02:18 +00:00
|
|
|
}
|
2024-02-06 15:30:31 +00:00
|
|
|
return parser.rootNode();
|
2021-03-23 10:02:18 +00:00
|
|
|
}
|
|
|
|
|
2023-12-13 14:24:34 +00:00
|
|
|
void ScriptExpression::astDumper(const Sink &s, AstDumperOptions options) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
astNodeDumper(s, ast(), options, 1, 0, [this](SourceLocation astL) {
|
|
|
|
SourceLocation l = this->locationToLocal(astL);
|
|
|
|
return this->code().mid(l.offset, l.length);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
QString ScriptExpression::astRelocatableDump() const
|
|
|
|
{
|
2023-12-13 14:24:34 +00:00
|
|
|
return dumperToString([this](const Sink &s) {
|
2021-03-23 10:02:18 +00:00
|
|
|
this->astDumper(s, AstDumperOption::NoLocations | AstDumperOption::SloppyCompare);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
void ScriptExpression::writeOut(const DomItem &self, OutWriter &lw) const
|
2021-03-23 14:37:32 +00:00
|
|
|
{
|
|
|
|
OutWriter *ow = &lw;
|
|
|
|
|
|
|
|
std::optional<PendingSourceLocationId> codeLoc;
|
|
|
|
if (lw.lineWriter.options().updateOptions & LineWriterOptions::Update::Expressions)
|
|
|
|
codeLoc = lw.lineWriter.startSourceLocation([this, self, ow](SourceLocation myLoc) mutable {
|
|
|
|
QStringView reformattedCode =
|
|
|
|
QStringView(ow->writtenStr).mid(myLoc.offset, myLoc.length);
|
|
|
|
if (reformattedCode != code()) {
|
QQmlJS::Dom::OutWriter. Refactoring
The refactoring consists of:
- Changing writeOut & writeOutForFile API
to return boolean instead of MutableDomItem, which better reflects
the existing usecases improving consistency of the data model*
Moreover, previous API was exposing DomItem, which was not "committed
to base" (MutableDomItem.commitToBase()), meaning it was exposing the
"unmerged" Item alongside with the "temporary environment"
- Refactoring & renaming OutWriter::updatedFile
breaking it into smaller chunks preserving
only necessary functionality
- Adding some comments / documentation
Before this commit, the writeOut API was "exposing",so called,
"updatedFile", which is basically the copy of the original fileItem +
renewed scriptExpressions which were modified during the writeOut of
the original fileItem.
The idea behind the "mutating" Dom API is that one has to create a
MutableDomItem, do some changes to it and then "commit" them.
This process is also facilitated by the creation of separate Env.
(git analogy might be handy here:
We create a separate branch, where all the mutation will happen and then
we "merge" this branch)
However, in the writeOutForFile usecase this "updatedFile" was needed
only for the verifying of the consistency of the "writtenOut" DOM,
however the API was exposing it further back to the caller sites,
without "committing".
The potential issue here is inconsistency of the data Model.
On one side we have an original File Item owned by the Base Env,
on the other side we have an "updatedFile" which is owned by another Env.
Taking into account that there are no usecases requiring "exposing"
"updatedFile", but also no need for "committing" the changes,
It's arguably better to keep that temporary "updatedFile" locally,
not exposing it outside the writeOutForFile function. Thereby improving
consistency of the data model.
Change-Id: If45eca4b4d6d703e2a76d0580f124d0292af5ed8
Reviewed-by: Semih Yavuz <semih.yavuz@qt.io>
2023-12-05 09:42:23 +00:00
|
|
|
// If some reformatting of the expression took place,
|
|
|
|
// it will be saved as an intermediate step.
|
|
|
|
// then it will be used to restore writtenOut fileItem
|
|
|
|
// in the OutWriter::restoreWrittenFile
|
2023-11-20 11:57:54 +00:00
|
|
|
|
|
|
|
//Interestingly enough, this copyWithUpdatedCode will
|
|
|
|
//instantiate Engine and Parser and will parse "reformattedCode"
|
|
|
|
//because it calls ScriptExpression::setCode function
|
2021-03-23 14:37:32 +00:00
|
|
|
std::shared_ptr<ScriptExpression> copy =
|
|
|
|
copyWithUpdatedCode(self, reformattedCode.toString());
|
|
|
|
ow->addReformattedScriptExpression(self.canonicalPath(), copy);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
reformatAst(
|
|
|
|
lw, m_astComments,
|
|
|
|
[this](SourceLocation astL) {
|
|
|
|
SourceLocation l = this->locationToLocal(astL); // use engine->code() instead?
|
|
|
|
return this->code().mid(l.offset, l.length);
|
|
|
|
},
|
|
|
|
ast());
|
|
|
|
if (codeLoc)
|
|
|
|
lw.lineWriter.endSourceLocation(*codeLoc);
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
SourceLocation ScriptExpression::globalLocation(const DomItem &self) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
2023-09-29 13:32:33 +00:00
|
|
|
if (const FileLocations::Tree tree = FileLocations::treeOf(self)) {
|
|
|
|
return FileLocations::region(tree, MainRegion);
|
2021-03-23 10:02:18 +00:00
|
|
|
}
|
|
|
|
return SourceLocation();
|
|
|
|
}
|
|
|
|
|
2021-09-28 02:54:30 +00:00
|
|
|
bool PropertyDefinition::isParametricType() const
|
|
|
|
{
|
|
|
|
return typeName.contains(QChar(u'<'));
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
void PropertyDefinition::writeOut(const DomItem &, OutWriter &lw) const
|
2021-03-23 14:37:32 +00:00
|
|
|
{
|
|
|
|
lw.ensureNewline();
|
|
|
|
if (isDefaultMember)
|
2023-09-29 13:32:33 +00:00
|
|
|
lw.writeRegion(DefaultKeywordRegion).space();
|
2021-03-23 14:37:32 +00:00
|
|
|
if (isRequired)
|
2023-09-29 13:32:33 +00:00
|
|
|
lw.writeRegion(RequiredKeywordRegion).space();
|
2021-03-23 14:37:32 +00:00
|
|
|
if (isReadonly)
|
2023-09-29 13:32:33 +00:00
|
|
|
lw.writeRegion(ReadonlyKeywordRegion).space();
|
2021-03-23 14:37:32 +00:00
|
|
|
if (!typeName.isEmpty()) {
|
2023-09-29 13:32:33 +00:00
|
|
|
lw.writeRegion(PropertyKeywordRegion).space();
|
|
|
|
lw.writeRegion(TypeIdentifierRegion, typeName).space();
|
2021-03-23 14:37:32 +00:00
|
|
|
}
|
2023-09-29 13:32:33 +00:00
|
|
|
lw.writeRegion(IdentifierRegion, name);
|
2021-03-23 14:37:32 +00:00
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
bool MethodInfo::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
bool cont = AttributeInfo::iterateDirectSubpaths(self, visitor);
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::parameters, parameters);
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::methodType, int(methodType));
|
|
|
|
if (!typeName.isEmpty())
|
|
|
|
cont = cont && self.dvReferenceField(visitor, Fields::type, typePath(self));
|
|
|
|
if (methodType == MethodType::Method) {
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::preCode, preCode(self));
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::postCode, postCode(self));
|
2021-06-26 22:56:14 +00:00
|
|
|
cont = cont && self.dvValueField(visitor, Fields::isConstructor, isConstructor);
|
2021-03-23 10:02:18 +00:00
|
|
|
}
|
2023-05-30 14:04:01 +00:00
|
|
|
if (returnType)
|
|
|
|
cont = cont && self.dvItemField(visitor, Fields::returnType, [this, &self]() {
|
|
|
|
return self.subOwnerItem(PathEls::Field(Fields::returnType), returnType);
|
|
|
|
});
|
2021-03-23 10:02:18 +00:00
|
|
|
if (body)
|
2023-05-10 19:58:28 +00:00
|
|
|
cont = cont && self.dvItemField(visitor, Fields::body, [this, &self]() {
|
|
|
|
return self.subOwnerItem(PathEls::Field(Fields::body), body);
|
|
|
|
});
|
2021-03-23 10:02:18 +00:00
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
QString MethodInfo::preCode(const DomItem &self) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
2021-03-23 14:37:32 +00:00
|
|
|
QString res;
|
|
|
|
LineWriter lw([&res](QStringView s) { res.append(s); }, QLatin1String("*preCode*"));
|
|
|
|
OutWriter ow(lw);
|
|
|
|
ow.indentNextlines = true;
|
|
|
|
ow.skipComments = true;
|
|
|
|
MockObject standinObj(self.pathFromOwner());
|
|
|
|
DomItem standin = self.copy(&standinObj);
|
|
|
|
ow.itemStart(standin);
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(FunctionKeywordRegion).space().writeRegion(IdentifierRegion, name);
|
2021-03-23 14:37:32 +00:00
|
|
|
bool first = true;
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(LeftParenthesisRegion);
|
2021-03-23 14:37:32 +00:00
|
|
|
for (const MethodParameter &mp : parameters) {
|
|
|
|
if (first)
|
|
|
|
first = false;
|
|
|
|
else
|
|
|
|
ow.write(u", ");
|
2023-09-08 10:19:24 +00:00
|
|
|
ow.write(mp.value->code());
|
2021-03-23 14:37:32 +00:00
|
|
|
}
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(RightParenthesisRegion);
|
|
|
|
ow.ensureSpace().writeRegion(LeftBraceRegion);
|
2021-09-14 16:49:53 +00:00
|
|
|
ow.itemEnd(standin);
|
|
|
|
ow.eof();
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
QString MethodInfo::postCode(const DomItem &) const
|
2021-09-14 16:49:53 +00:00
|
|
|
{
|
|
|
|
return QLatin1String("\n}\n");
|
2021-03-23 14:37:32 +00:00
|
|
|
}
|
|
|
|
|
2024-09-10 11:39:09 +00:00
|
|
|
void MethodInfo::writeOutArguments(const DomItem &self, OutWriter &ow) const
|
|
|
|
{
|
2024-09-10 15:15:39 +00:00
|
|
|
if (parameters.isEmpty() && methodType == MethodType::Signal)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ow.writeRegion(LeftParenthesisRegion);
|
2024-09-10 11:39:09 +00:00
|
|
|
bool first = true;
|
|
|
|
for (const DomItem &arg : self.field(Fields::parameters).values()) {
|
|
|
|
if (first)
|
|
|
|
first = false;
|
|
|
|
else
|
|
|
|
ow.writeRegion(CommaTokenRegion).space();
|
|
|
|
arg.writeOut(ow);
|
|
|
|
}
|
2024-09-10 15:15:39 +00:00
|
|
|
ow.writeRegion(RightParenthesisRegion);
|
2024-09-10 11:39:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MethodInfo::writeOutReturnType(OutWriter &ow) const
|
|
|
|
{
|
|
|
|
if (typeName.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
ow.writeRegion(ColonTokenRegion);
|
|
|
|
ow.space();
|
|
|
|
ow.writeRegion(TypeIdentifierRegion, typeName);
|
|
|
|
}
|
|
|
|
|
2024-09-10 15:15:39 +00:00
|
|
|
void MethodInfo::writeOutBody(const DomItem &self, OutWriter &ow) const
|
2021-03-23 14:37:32 +00:00
|
|
|
{
|
2024-09-10 15:15:39 +00:00
|
|
|
ow.ensureSpace().writeRegion(LeftBraceRegion);
|
|
|
|
int baseIndent = ow.increaseIndent();
|
|
|
|
if (DomItem b = self.field(Fields::body)) {
|
|
|
|
ow.ensureNewline();
|
|
|
|
b.writeOut(ow);
|
|
|
|
}
|
|
|
|
ow.decreaseIndent(1, baseIndent);
|
|
|
|
ow.ensureNewline().writeRegion(RightBraceRegion);
|
|
|
|
}
|
2024-09-10 11:39:09 +00:00
|
|
|
|
2024-09-10 15:15:39 +00:00
|
|
|
void MethodInfo::writeOut(const DomItem &self, OutWriter &ow) const
|
|
|
|
{
|
|
|
|
if (methodType == MethodType::Signal) {
|
|
|
|
ow.writeRegion(SignalKeywordRegion).space();
|
|
|
|
} else {
|
|
|
|
ow.writeRegion(FunctionKeywordRegion).space();
|
|
|
|
}
|
|
|
|
ow.writeRegion(IdentifierRegion, name);
|
|
|
|
writeOutArguments(self, ow);
|
|
|
|
if (methodType == MethodType::Signal) {
|
|
|
|
// signal doesn't have returnType or body
|
2021-03-23 14:37:32 +00:00
|
|
|
return;
|
|
|
|
}
|
2024-09-10 15:15:39 +00:00
|
|
|
writeOutReturnType(ow);
|
|
|
|
writeOutBody(self, ow);
|
2021-03-23 14:37:32 +00:00
|
|
|
}
|
|
|
|
|
2024-09-10 11:39:09 +00:00
|
|
|
QString MethodInfo::signature(const DomItem &self) const
|
|
|
|
{
|
|
|
|
QString resultStr;
|
|
|
|
QTextStream res(&resultStr);
|
|
|
|
LineWriter lw([&res](QStringView s) { res << s; }, QLatin1String("*testStream*"));
|
|
|
|
OutWriter ow(lw);
|
|
|
|
ow.indentNextlines = true;
|
|
|
|
ow.skipComments = true;
|
|
|
|
|
|
|
|
ow.itemStart(self);
|
|
|
|
writeOutArguments(self, ow);
|
|
|
|
|
|
|
|
writeOutReturnType(ow);
|
|
|
|
|
|
|
|
ow.itemEnd(self);
|
|
|
|
lw.eof(false);
|
|
|
|
res.flush();
|
|
|
|
return resultStr.simplified();
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
bool MethodParameter::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
bool cont = true;
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::name, name);
|
|
|
|
if (!typeName.isEmpty()) {
|
|
|
|
cont = cont
|
2023-02-07 15:35:40 +00:00
|
|
|
&& self.dvReferenceField(visitor, Fields::type, Paths::lookupTypePath(typeName));
|
2021-03-23 10:02:18 +00:00
|
|
|
cont = cont && self.dvValueField(visitor, Fields::typeName, typeName);
|
|
|
|
}
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::isPointer, isPointer);
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::isReadonly, isReadonly);
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::isList, isList);
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::defaultValue, defaultValue);
|
2023-05-30 14:04:01 +00:00
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::value, value);
|
|
|
|
|
2023-09-06 15:07:21 +00:00
|
|
|
cont = cont && self.dvValueField(visitor, Fields::preCode, u"function f("_s);
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::postCode, u") {}"_s);
|
|
|
|
|
2021-03-23 10:02:18 +00:00
|
|
|
if (!annotations.isEmpty())
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::annotations, annotations);
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::comments, comments);
|
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
void MethodParameter::writeOut(const DomItem &self, OutWriter &ow) const
|
2021-03-23 14:37:32 +00:00
|
|
|
{
|
2024-09-10 11:39:09 +00:00
|
|
|
if (typeAnnotationStyle == MethodParameter::TypeAnnotationStyle::Prefix) {
|
|
|
|
writeOutSignal(self, ow);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-08-30 12:50:11 +00:00
|
|
|
if (!name.isEmpty()) {
|
2023-08-31 09:38:00 +00:00
|
|
|
if (isRestElement)
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(EllipsisTokenRegion);
|
|
|
|
ow.writeRegion(IdentifierRegion, name);
|
2023-08-30 12:50:11 +00:00
|
|
|
if (!typeName.isEmpty())
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(ColonTokenRegion).space().writeRegion(TypeIdentifierRegion, typeName);
|
2023-08-30 12:50:11 +00:00
|
|
|
if (defaultValue) {
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.space().writeRegion(EqualTokenRegion).space();
|
2023-08-30 12:50:11 +00:00
|
|
|
self.subOwnerItem(PathEls::Field(Fields::defaultValue), defaultValue).writeOut(ow);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (value) {
|
|
|
|
self.subOwnerItem(PathEls::Field(Fields::value), value).writeOut(ow);
|
|
|
|
}
|
2021-03-23 14:37:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
void MethodParameter::writeOutSignal(const DomItem &self, OutWriter &ow) const
|
2021-03-23 14:37:32 +00:00
|
|
|
{
|
|
|
|
self.writeOutPre(ow);
|
|
|
|
if (!typeName.isEmpty())
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(TypeIdentifierRegion, typeName).space();
|
|
|
|
ow.writeRegion(IdentifierRegion, name);
|
2021-03-23 14:37:32 +00:00
|
|
|
self.writeOutPost(ow);
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
void Pragma::writeOut(const DomItem &, OutWriter &ow) const
|
2021-03-23 14:37:32 +00:00
|
|
|
{
|
|
|
|
ow.ensureNewline();
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(PragmaKeywordRegion).space().writeRegion(IdentifierRegion, name);
|
2023-06-08 07:30:36 +00:00
|
|
|
|
|
|
|
bool isFirst = true;
|
|
|
|
for (const auto &value : values) {
|
|
|
|
if (isFirst) {
|
|
|
|
isFirst = false;
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(ColonTokenRegion).space();
|
|
|
|
ow.writeRegion(PragmaValuesRegion, value);
|
2023-06-08 07:30:36 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(CommaTokenRegion).space();
|
|
|
|
ow.writeRegion(PragmaValuesRegion, value);
|
2023-06-08 07:30:36 +00:00
|
|
|
}
|
2021-03-23 14:37:32 +00:00
|
|
|
ow.ensureNewline();
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
bool EnumItem::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
|
2021-03-23 10:02:18 +00:00
|
|
|
{
|
|
|
|
bool cont = true;
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::name, name());
|
|
|
|
cont = cont && self.dvValueField(visitor, Fields::value, value());
|
|
|
|
cont = cont && self.dvWrapField(visitor, Fields::comments, m_comments);
|
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
void EnumItem::writeOut(const DomItem &self, OutWriter &ow) const
|
2021-03-23 14:37:32 +00:00
|
|
|
{
|
|
|
|
ow.ensureNewline();
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(IdentifierRegion, name());
|
2021-03-23 14:37:32 +00:00
|
|
|
index_type myIndex = self.pathFromOwner().last().headIndex();
|
2024-05-31 09:06:27 +00:00
|
|
|
if (m_valueKind == ValueKind::ExplicitValue) {
|
2021-03-23 14:37:32 +00:00
|
|
|
QString v = QString::number(value(), 'f', 0);
|
|
|
|
if (abs(value() - v.toDouble()) > 1.e-10)
|
|
|
|
v = QString::number(value());
|
2024-05-31 09:06:27 +00:00
|
|
|
ow.space().writeRegion(EqualTokenRegion).space().writeRegion(EnumValueRegion, v);
|
2021-03-23 14:37:32 +00:00
|
|
|
}
|
|
|
|
if (myIndex >= 0 && self.container().indexes() != myIndex + 1)
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(CommaTokenRegion);
|
2021-03-23 14:37:32 +00:00
|
|
|
}
|
|
|
|
|
2021-12-06 21:18:28 +00:00
|
|
|
QmlUri QmlUri::fromString(const QString &str)
|
|
|
|
{
|
|
|
|
if (str.startsWith(u'"'))
|
2022-10-05 05:29:16 +00:00
|
|
|
return fromDirectoryString(str.mid(1, str.size() - 2)
|
2022-03-21 09:21:18 +00:00
|
|
|
.replace(u"\\\""_s, u"\""_s)
|
|
|
|
.replace(u"\\\\"_s, u"\\"_s));
|
2021-12-06 21:18:28 +00:00
|
|
|
else
|
|
|
|
return fromUriString(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
QmlUri QmlUri::fromUriString(const QString &str)
|
|
|
|
{
|
|
|
|
QRegularExpression moduleUriRe(QLatin1String(R"(\A\w+(?:\.\w+)*\Z)"));
|
|
|
|
return QmlUri((moduleUriRe.match(str).hasMatch() ? Kind::ModuleUri : Kind::Invalid), str);
|
|
|
|
}
|
|
|
|
|
|
|
|
QmlUri QmlUri::fromDirectoryString(const QString &str)
|
|
|
|
{
|
|
|
|
QUrl url(str);
|
2022-10-05 05:29:16 +00:00
|
|
|
if (url.isValid() && url.scheme().size() > 1)
|
2021-12-06 21:18:28 +00:00
|
|
|
return QmlUri(url);
|
|
|
|
if (!str.isEmpty()) {
|
|
|
|
QFileInfo path(str);
|
|
|
|
return QmlUri((path.isRelative() ? Kind::RelativePath : Kind::AbsolutePath), str);
|
|
|
|
}
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QmlUri::isValid() const
|
|
|
|
{
|
|
|
|
return m_kind != Kind::Invalid;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QmlUri::isDirectory() const
|
|
|
|
{
|
|
|
|
switch (m_kind) {
|
|
|
|
case Kind::Invalid:
|
|
|
|
case Kind::ModuleUri:
|
|
|
|
break;
|
|
|
|
case Kind::DirectoryUrl:
|
|
|
|
case Kind::RelativePath:
|
|
|
|
case Kind::AbsolutePath:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QmlUri::isModule() const
|
|
|
|
{
|
|
|
|
return m_kind == Kind::ModuleUri;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString QmlUri::moduleUri() const
|
|
|
|
{
|
|
|
|
if (m_kind == Kind::ModuleUri)
|
|
|
|
return std::get<QString>(m_value);
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
QString QmlUri::localPath() const
|
|
|
|
{
|
|
|
|
switch (m_kind) {
|
|
|
|
case Kind::Invalid:
|
|
|
|
case Kind::ModuleUri:
|
|
|
|
break;
|
|
|
|
case Kind::DirectoryUrl: {
|
|
|
|
const QUrl &url = std::get<QUrl>(m_value);
|
|
|
|
if (url.scheme().compare(u"file", Qt::CaseInsensitive) == 0)
|
|
|
|
return url.path();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Kind::RelativePath:
|
|
|
|
case Kind::AbsolutePath:
|
|
|
|
return std::get<QString>(m_value);
|
|
|
|
}
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
QString QmlUri::absoluteLocalPath(const QString &basePath) const
|
|
|
|
{
|
|
|
|
switch (m_kind) {
|
|
|
|
case Kind::Invalid:
|
|
|
|
case Kind::ModuleUri:
|
|
|
|
break;
|
|
|
|
case Kind::DirectoryUrl: {
|
|
|
|
const QUrl &url = std::get<QUrl>(m_value);
|
|
|
|
if (url.scheme().compare(u"file", Qt::CaseInsensitive) == 0)
|
|
|
|
return url.path();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Kind::RelativePath: {
|
|
|
|
if (!basePath.isEmpty())
|
|
|
|
return QDir(basePath).filePath(std::get<QString>(m_value));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Kind::AbsolutePath:
|
|
|
|
return std::get<QString>(m_value);
|
|
|
|
}
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
QUrl QmlUri::directoryUrl() const
|
|
|
|
{
|
|
|
|
if (m_kind == Kind::DirectoryUrl)
|
|
|
|
return std::get<QUrl>(m_value);
|
|
|
|
return QUrl {};
|
|
|
|
}
|
|
|
|
|
|
|
|
QString QmlUri::directoryString() const
|
|
|
|
{
|
|
|
|
switch (m_kind) {
|
|
|
|
case Kind::Invalid:
|
|
|
|
case Kind::ModuleUri:
|
|
|
|
break;
|
|
|
|
case Kind::DirectoryUrl:
|
|
|
|
return std::get<QUrl>(m_value).toString(); // set formatting? options?
|
|
|
|
case Kind::RelativePath:
|
|
|
|
case Kind::AbsolutePath:
|
|
|
|
return std::get<QString>(m_value);
|
|
|
|
}
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
QString QmlUri::toString() const
|
|
|
|
{
|
|
|
|
switch (m_kind) {
|
|
|
|
case Kind::Invalid:
|
|
|
|
break;
|
|
|
|
case Kind::ModuleUri:
|
|
|
|
return std::get<QString>(m_value);
|
|
|
|
case Kind::DirectoryUrl:
|
|
|
|
case Kind::RelativePath:
|
|
|
|
case Kind::AbsolutePath:
|
2022-03-21 09:21:18 +00:00
|
|
|
return u"\""_s + directoryString().replace(u'\\', u"\\\\"_s).replace(u'"', u"\\\""_s)
|
|
|
|
+ u"\""_s;
|
2021-12-06 21:18:28 +00:00
|
|
|
}
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
QmlUri::Kind QmlUri::kind() const
|
|
|
|
{
|
|
|
|
return m_kind;
|
|
|
|
}
|
|
|
|
|
2023-04-05 14:43:50 +00:00
|
|
|
void ScriptExpression::setScriptElement(const ScriptElementVariant &p)
|
|
|
|
{
|
|
|
|
m_element = p;
|
|
|
|
}
|
|
|
|
|
2021-03-23 10:02:18 +00:00
|
|
|
} // end namespace Dom
|
|
|
|
} // end namespace QQmlJS
|
|
|
|
|
|
|
|
QT_END_NAMESPACE
|
2022-04-28 14:10:10 +00:00
|
|
|
|
|
|
|
#include "moc_qqmldomelements_p.cpp"
|