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 {
|
|
|
|
|
|
|
|
Path moduleIndexPath(QString uri, int majorVersion, ErrorHandler errorHandler)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2021-12-06 21:18:28 +00:00
|
|
|
Path moduleScopePath(QString uri, Version version, 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());
|
|
|
|
}
|
|
|
|
|
|
|
|
Path moduleScopePath(QString uri, QString version, ErrorHandler errorHandler)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Component::updatePathFromOwner(Path newPath)
|
|
|
|
{
|
|
|
|
DomElement::updatePathFromOwner(newPath);
|
|
|
|
updatePathFromOwnerMultiMap(m_enumerations, newPath.field(Fields::enumerations));
|
|
|
|
updatePathFromOwnerQList(m_objects, newPath.field(Fields::objects));
|
|
|
|
}
|
|
|
|
|
|
|
|
Component::Component(QString name) : CommentableDomElement(Path()), m_name(name) { }
|
|
|
|
|
|
|
|
Component::Component(Path pathFromOwner) : CommentableDomElement(pathFromOwner) { }
|
|
|
|
|
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
|
|
|
{
|
2022-10-05 05:29:16 +00:00
|
|
|
switch (name.size()) {
|
2021-03-23 10:02:18 +00:00
|
|
|
case 4:
|
|
|
|
if (name == Fields::name)
|
|
|
|
return self.wrapField(Fields::name, m_name);
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
if (name == Fields::objects)
|
|
|
|
return self.wrapField(Fields::objects, m_objects);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
});
|
|
|
|
return cont;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QmlComponent::updatePathFromOwner(Path newPath)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
Import Import::fromUriString(QString importStr, Version v, QString importId, ErrorHandler handler)
|
|
|
|
{
|
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);
|
|
|
|
if (importId.isEmpty())
|
|
|
|
importId = 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);
|
|
|
|
return Import(QmlUri::fromUriString(m.captured(u"uri").trimmed()), v, importId);
|
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
|
|
|
}
|
|
|
|
|
2021-12-06 21:18:28 +00:00
|
|
|
Import Import::fromFileString(QString importStr, QString importId, 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
|
|
|
}
|
|
|
|
|
2021-03-23 10:02:18 +00:00
|
|
|
Id::Id(QString idName, Path referredObject) : name(idName), referredObjectPath(referredObject) { }
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Id::updatePathFromOwner(Path newPath)
|
|
|
|
{
|
|
|
|
updatePathFromOwnerQList(annotations, newPath.field(Fields::annotations));
|
|
|
|
}
|
|
|
|
|
|
|
|
Path Id::addAnnotation(Path selfPathFromOwner, const QmlObject &annotation, QmlObject **aPtr)
|
|
|
|
{
|
|
|
|
return appendUpdatableElementInQList(selfPathFromOwner.field(Fields::annotations), annotations,
|
|
|
|
annotation, aPtr);
|
|
|
|
}
|
|
|
|
|
|
|
|
QmlObject::QmlObject(Path pathFromOwner) : CommentableDomElement(pathFromOwner) { }
|
|
|
|
|
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-09-13 13:05:12 +00:00
|
|
|
[&self](const DomItem &map, 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")));
|
|
|
|
});
|
|
|
|
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
|
|
|
{
|
|
|
|
switch (name.size()) {
|
|
|
|
case 4:
|
|
|
|
if (name == Fields::name)
|
|
|
|
return self.subDataItem(PathEls::Field(Fields::name), this->name());
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
if (name == Fields::idStr) {
|
|
|
|
if (idStr().isEmpty())
|
|
|
|
return DomItem();
|
|
|
|
return self.subDataItem(PathEls::Field(Fields::idStr), idStr());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
if (name == Fields::methods)
|
|
|
|
return self.wrapField(Fields::methods, m_methods);
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
switch (name.at(1).unicode()) {
|
|
|
|
case u'i':
|
|
|
|
if (name == Fields::bindings)
|
|
|
|
return self.wrapField(Fields::bindings, m_bindings);
|
|
|
|
break;
|
|
|
|
case u'o':
|
|
|
|
if (name == Fields::comments)
|
|
|
|
return CommentableDomElement::field(self, name);
|
|
|
|
break;
|
|
|
|
case u'h':
|
|
|
|
if (name == Fields::children)
|
|
|
|
return self.wrapField(Fields::children, m_children);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
if (name == Fields::nextScope) {
|
|
|
|
if (nextScopePath())
|
|
|
|
return self.subReferenceItem(PathEls::Field(Fields::nextScope), nextScopePath());
|
|
|
|
else
|
|
|
|
return DomItem();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 10:
|
|
|
|
if (name == Fields::prototypes) {
|
|
|
|
if (prototypePaths().isEmpty())
|
|
|
|
return DomItem();
|
|
|
|
return self.subReferencesItem(PathEls::Field(Fields::prototypes), m_prototypePaths);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 11:
|
|
|
|
if (name == Fields::annotations)
|
|
|
|
return self.wrapField(Fields::annotations, m_annotations);
|
|
|
|
break;
|
|
|
|
case 12:
|
|
|
|
return self.wrapField(Fields::propertyDefs, m_propertyDefs);
|
|
|
|
break;
|
|
|
|
case 13:
|
|
|
|
if (name == Fields::propertyInfos)
|
2023-09-18 08:53:19 +00:00
|
|
|
// Need to explicitly copy self here since we might store this and call it later.
|
2021-03-23 10:02:18 +00:00
|
|
|
return self.subMapItem(Map(
|
|
|
|
pathFromOwner().field(Fields::propertyInfos),
|
2023-09-18 08:53:19 +00:00
|
|
|
[copiedSelf = self](const DomItem &map, const QString &k) {
|
|
|
|
return map.wrap(PathEls::Key(k), copiedSelf.propertyInfoWithName(k));
|
2021-03-23 10:02:18 +00:00
|
|
|
},
|
2023-09-18 08:53:19 +00:00
|
|
|
[copiedSelf = self](const DomItem &) { return copiedSelf.propertyInfoNames(); },
|
2021-03-23 10:02:18 +00:00
|
|
|
QLatin1String("PropertyInfo")));
|
|
|
|
break;
|
|
|
|
case 19:
|
|
|
|
if (name == Fields::defaultPropertyName)
|
|
|
|
return self.subDataItem(PathEls::Field(Fields::defaultPropertyName),
|
|
|
|
defaultPropertyName(self));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
static QStringList knownLookups({ QString::fromUtf16(Fields::fileLocationsTree) });
|
|
|
|
if (!knownLookups.contains(name))
|
|
|
|
qCWarning(domLog()) << "Asked non existing field " << name << " in QmlObject "
|
|
|
|
<< pathFromOwner();
|
|
|
|
return DomItem();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QmlObject::updatePathFromOwner(Path newPath)
|
|
|
|
{
|
|
|
|
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-09-13 13:05:12 +00:00
|
|
|
bool cont = self.field(Fields::bindings).visitKeys([visitor](QString, const DomItem &bs) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-01-20 10:01:54 +00:00
|
|
|
static QStringList dotExpressionToList(std::shared_ptr<ScriptExpression> expr)
|
|
|
|
{
|
|
|
|
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-09-13 13:05:12 +00:00
|
|
|
void QmlObject::writeOut(const DomItem &self, OutWriter &ow, 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);
|
|
|
|
ow.writeRegion(LeftBraceRegion, u" {").newline();
|
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);
|
|
|
|
}
|
2021-03-23 14:37:32 +00:00
|
|
|
if (myId)
|
|
|
|
myId.writeOutPost(ow);
|
|
|
|
}
|
|
|
|
quint32 counter = ow.counter();
|
|
|
|
DomItem component;
|
|
|
|
if (isRootObject)
|
|
|
|
component = self.containingObject();
|
2021-09-03 09:13:07 +00:00
|
|
|
auto startLoc = [&](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-09-13 13:05:12 +00:00
|
|
|
auto addMMap = [&attribs, &startLoc](const DomItem &base, 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-09-13 13:05:12 +00:00
|
|
|
auto addSingleLevel = [&attribs, &startLoc](const DomItem &base, 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ow.decreaseIndent(1, baseIndent);
|
|
|
|
ow.ensureNewline().write(u"}");
|
|
|
|
|
|
|
|
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);
|
|
|
|
ow.ensureNewline().write(u"}");
|
|
|
|
}
|
|
|
|
|
2021-03-23 10:02:18 +00:00
|
|
|
Binding::Binding(QString name, std::unique_ptr<BindingValue> value, BindingType bindingType)
|
|
|
|
: m_bindingType(bindingType), m_name(name), m_value(std::move(value))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Binding::Binding(QString name, std::shared_ptr<ScriptExpression> value, BindingType bindingType)
|
|
|
|
: Binding(name, std::make_unique<BindingValue>(value), bindingType)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Binding::Binding(QString name, QString scriptCode, BindingType bindingType)
|
|
|
|
: 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)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Binding::Binding(QString name, QmlObject value, BindingType bindingType)
|
|
|
|
: Binding(name, std::make_unique<BindingValue>(value), bindingType)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Binding::Binding(QString name, QList<QmlObject> value, BindingType bindingType)
|
|
|
|
: 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
Path Binding::addAnnotation(Path selfPathFromOwner, const QmlObject &annotation, QmlObject **aPtr)
|
|
|
|
{
|
|
|
|
return appendUpdatableElementInQList(selfPathFromOwner.field(Fields::annotations),
|
|
|
|
m_annotations, annotation, aPtr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Binding::updatePathFromOwner(Path newPath)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
Export Export::fromString(Path source, QStringView exp, Path typePath, ErrorHandler h)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
Path AttributeInfo::addAnnotation(Path selfPathFromOwner, const QmlObject &annotation,
|
|
|
|
QmlObject **aPtr)
|
|
|
|
{
|
|
|
|
return appendUpdatableElementInQList(selfPathFromOwner.field(Fields::annotations), annotations,
|
|
|
|
annotation, aPtr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AttributeInfo::updatePathFromOwner(Path newPath)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EnumDecl::updatePathFromOwner(Path newPath)
|
|
|
|
{
|
|
|
|
DomElement::updatePathFromOwner(newPath);
|
|
|
|
updatePathFromOwnerQList(m_annotations, newPath.field(Fields::annotations));
|
|
|
|
}
|
|
|
|
|
|
|
|
void EnumDecl::setAnnotations(QList<QmlObject> annotations)
|
|
|
|
{
|
|
|
|
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-09-13 13:05:12 +00:00
|
|
|
[this, &self](const DomItem &map, 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
BindingValue::BindingValue(std::shared_ptr<ScriptExpression> o)
|
|
|
|
: 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();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BindingValue::updatePathFromOwner(Path newPath)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-09-14 16:49:53 +00:00
|
|
|
ScriptExpression::ScriptExpression(QStringView code, std::shared_ptr<QQmlJS::Engine> engine,
|
|
|
|
AST::Node *ast, std::shared_ptr<AstComments> comments,
|
|
|
|
ExpressionType expressionType, SourceLocation localOffset,
|
|
|
|
int derivedFrom, QStringView preCode, QStringView postCode)
|
|
|
|
: 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-09-13 13:05:12 +00:00
|
|
|
std::shared_ptr<ScriptExpression> ScriptExpression::copyWithUpdatedCode(const DomItem &self,
|
2021-03-23 10:02:18 +00:00
|
|
|
QString code) const
|
|
|
|
{
|
|
|
|
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:
|
|
|
|
quint32 minStart = 0;
|
2021-09-03 09:13:07 +00:00
|
|
|
quint32 maxEnd = std::numeric_limits<quint32>::max();
|
2021-03-23 10:02:18 +00:00
|
|
|
AST::Node *firstNodeInRange = nullptr;
|
|
|
|
|
2021-09-03 09:13:07 +00:00
|
|
|
FirstNodeVisitor(quint32 minStart = 0, quint32 maxEnd = std::numeric_limits<quint32>::max())
|
2021-03-23 10:02:18 +00:00
|
|
|
: minStart(minStart), maxEnd(maxEnd)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool preVisit(AST::Node *n) override
|
|
|
|
{
|
|
|
|
if (!VisitAll::uiKinds().contains(n->kind)) {
|
|
|
|
quint32 start = n->firstSourceLocation().begin();
|
|
|
|
quint32 end = n->lastSourceLocation().end();
|
|
|
|
if (!firstNodeInRange && minStart <= start && end <= maxEnd && start < end)
|
|
|
|
firstNodeInRange = n;
|
|
|
|
}
|
|
|
|
return !firstNodeInRange;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
AST::Node *firstNodeInRange(AST::Node *n, quint32 minStart = 0, quint32 maxEnd = ~quint32(0))
|
|
|
|
{
|
|
|
|
FirstNodeVisitor visitor(minStart, maxEnd);
|
|
|
|
AST::Node::accept(n, &visitor);
|
|
|
|
return visitor.firstNodeInRange;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScriptExpression::setCode(QString code, QString preCode, QString postCode)
|
|
|
|
{
|
2023-11-07 16:57:53 +00:00
|
|
|
//TODO refactor and move parsing outside?
|
2021-03-23 10:02:18 +00:00
|
|
|
m_codeStr = code;
|
2021-09-14 16:49:53 +00:00
|
|
|
const bool qmlMode = (m_expressionType == ExpressionType::BindingExpression);
|
2022-03-17 12:51:27 +00:00
|
|
|
if (qmlMode && preCode.isEmpty()) {
|
|
|
|
preCode = Binding::preCodeForName(u"binding");
|
|
|
|
postCode = Binding::postCodeForName(u"binding");
|
|
|
|
}
|
2021-03-23 10:02:18 +00:00
|
|
|
if (!preCode.isEmpty() || !postCode.isEmpty())
|
|
|
|
m_codeStr = preCode + code + postCode;
|
2022-10-05 05:29:16 +00:00
|
|
|
m_code = QStringView(m_codeStr).mid(preCode.size(), code.size());
|
|
|
|
m_preCode = QStringView(m_codeStr).mid(0, preCode.size());
|
|
|
|
m_postCode = QStringView(m_codeStr).mid(preCode.size() + code.size(), postCode.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);
|
2021-03-23 10:02:18 +00:00
|
|
|
QQmlJS::Lexer lexer(m_engine.get());
|
|
|
|
lexer.setCode(m_codeStr, /*lineno = */ 1, /*qmlMode=*/true);
|
|
|
|
QQmlJS::Parser parser(m_engine.get());
|
2021-09-14 16:49:53 +00:00
|
|
|
if ((qmlMode && !parser.parse()) || (!qmlMode && !parser.parseScript()))
|
2021-03-23 10:02:18 +00:00
|
|
|
addErrorLocal(domParsingErrors().error(tr("Parsing of code failed")));
|
2023-09-13 15:36:59 +00:00
|
|
|
const auto messages = parser.diagnosticMessages();
|
|
|
|
for (const DiagnosticMessage &msg : messages) {
|
2021-03-23 10:02:18 +00:00
|
|
|
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;
|
2023-09-14 10:30:33 +00:00
|
|
|
addErrorLocal(std::move(err));
|
2021-03-23 10:02:18 +00:00
|
|
|
}
|
|
|
|
m_ast = parser.rootNode();
|
|
|
|
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;
|
2021-03-23 10:02:18 +00:00
|
|
|
AstComments::collectComments(m_engine, m_ast, m_astComments, MutableDomItem(), nullptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScriptExpression::astDumper(Sink s, AstDumperOptions options) const
|
|
|
|
{
|
|
|
|
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
|
|
|
|
{
|
|
|
|
return dumperToString([this](Sink s) {
|
|
|
|
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()) {
|
2023-11-20 11:57:54 +00:00
|
|
|
//If some reformatting of the expression took place,
|
|
|
|
//it will be saved as an intermediate step.
|
|
|
|
//then it will be used to assemble the final reformatted file
|
|
|
|
//in the OutWriter::updatedFile
|
|
|
|
|
|
|
|
//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
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:12 +00:00
|
|
|
void MethodInfo::writeOut(const DomItem &self, OutWriter &ow) const
|
2021-03-23 14:37:32 +00:00
|
|
|
{
|
|
|
|
switch (methodType) {
|
|
|
|
case MethodType::Signal: {
|
|
|
|
if (body)
|
|
|
|
qCWarning(domLog) << "signal should not have a body in" << self.canonicalPath();
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(SignalKeywordRegion).space().writeRegion(IdentifierRegion, name);
|
2021-03-23 14:37:32 +00:00
|
|
|
if (parameters.isEmpty())
|
|
|
|
return;
|
|
|
|
bool first = true;
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(LeftParenthesisRegion);
|
2021-03-23 14:37:32 +00:00
|
|
|
int baseIndent = ow.increaseIndent();
|
2023-09-13 15:36:59 +00:00
|
|
|
for (const DomItem &arg : self.field(Fields::parameters).values()) {
|
2021-03-23 14:37:32 +00:00
|
|
|
if (first)
|
|
|
|
first = false;
|
|
|
|
else
|
|
|
|
ow.write(u", ");
|
|
|
|
if (const MethodParameter *argPtr = arg.as<MethodParameter>())
|
|
|
|
argPtr->writeOutSignal(arg, ow);
|
|
|
|
else
|
|
|
|
qCWarning(domLog) << "failed to cast to MethodParameter";
|
|
|
|
}
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(RightParenthesisRegion);
|
2021-03-23 14:37:32 +00:00
|
|
|
ow.decreaseIndent(1, baseIndent);
|
|
|
|
return;
|
|
|
|
} break;
|
|
|
|
case MethodType::Method: {
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(FunctionKeywordRegion).space().writeRegion(IdentifierRegion, name);
|
2021-09-14 16:49:53 +00:00
|
|
|
bool first = true;
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(LeftParenthesisRegion);
|
2023-09-13 15:36:59 +00:00
|
|
|
for (const DomItem &arg : self.field(Fields::parameters).values()) {
|
2021-09-14 16:49:53 +00:00
|
|
|
if (first)
|
|
|
|
first = false;
|
|
|
|
else
|
|
|
|
ow.write(u", ");
|
|
|
|
arg.writeOut(ow);
|
|
|
|
}
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(RightParenthesisRegion);
|
2021-09-14 16:49:53 +00:00
|
|
|
if (!typeName.isEmpty()) {
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(ColonTokenRegion);
|
2021-09-14 16:49:53 +00:00
|
|
|
ow.space();
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.writeRegion(TypeIdentifierRegion, typeName);
|
2021-09-14 16:49:53 +00:00
|
|
|
}
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.ensureSpace().writeRegion(LeftBraceRegion);
|
2021-03-23 14:37:32 +00:00
|
|
|
int baseIndent = ow.increaseIndent();
|
|
|
|
if (DomItem b = self.field(Fields::body)) {
|
|
|
|
ow.ensureNewline();
|
|
|
|
b.writeOut(ow);
|
|
|
|
}
|
|
|
|
ow.decreaseIndent(1, baseIndent);
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.ensureNewline().writeRegion(RightBraceRegion);
|
2021-03-23 14:37:32 +00:00
|
|
|
} break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
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
|
|
|
bool hasDefaultValue = false;
|
|
|
|
index_type myIndex = self.pathFromOwner().last().headIndex();
|
|
|
|
if (myIndex == 0)
|
|
|
|
hasDefaultValue = value() == 0;
|
|
|
|
else if (myIndex > 0)
|
|
|
|
hasDefaultValue = value()
|
|
|
|
== self.container()
|
|
|
|
.index(myIndex - 1)
|
|
|
|
.field(Fields::value)
|
|
|
|
.value()
|
|
|
|
.toDouble(value())
|
|
|
|
+ 1;
|
|
|
|
if (!hasDefaultValue) {
|
|
|
|
QString v = QString::number(value(), 'f', 0);
|
|
|
|
if (abs(value() - v.toDouble()) > 1.e-10)
|
|
|
|
v = QString::number(value());
|
2023-09-29 13:32:33 +00:00
|
|
|
ow.space().writeRegion(EqualTokenRegion).space().writeRegion(PragmaValuesRegion, 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"
|