Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qqmljsutils_p.h
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#ifndef QQMLJSUTILS_P_H
5#define QQMLJSUTILS_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16
17#include <private/qtqmlcompilerexports_p.h>
18
19#include "qqmljslogger_p.h"
21#include "qqmljsscope_p.h"
22#include "qqmljsmetatypes_p.h"
23
24#include <QtCore/qstack.h>
25#include <QtCore/qstring.h>
26#include <QtCore/qstringview.h>
27#include <QtCore/qstringbuilder.h>
28#include <private/qduplicatetracker_p.h>
29
30#include <optional>
31#include <functional>
32#include <type_traits>
33#include <variant>
34
36
37namespace detail {
43template<typename To, typename From, typename std::enable_if_t<!std::is_pointer_v<To>, int> = 0>
44static auto getQQmlJSScopeFromSmartPtr(const From &p) -> From
45{
46 static_assert(!std::is_pointer_v<From>, "From has to be a smart pointer holding QQmlJSScope");
47 return p;
48}
49
57template<typename To, typename From, typename std::enable_if_t<std::is_pointer_v<To>, int> = 0>
58static auto getQQmlJSScopeFromSmartPtr(const From &p) -> decltype(p.get())
59{
60 static_assert(!std::is_pointer_v<From>, "From has to be a smart pointer holding QQmlJSScope");
61 return p.get();
62}
63}
64
67struct Q_QMLCOMPILER_PRIVATE_EXPORT QQmlJSUtils
68{
74 {
75 using namespace Qt::StringLiterals;
76 return s.replace(u'\\', u"\\\\"_s).replace(u'"', u"\\\""_s).replace(u'\n', u"\\n"_s);
77 }
78
86 static QString toLiteral(const QString &s, QStringView ctor = u"QStringLiteral")
87 {
88 return ctor % u"(\"" % escapeString(s) % u"\")";
89 }
90
96 {
97 if (!type.endsWith(u'*'))
98 type = u"const " % type % u"&";
99 return type;
100 }
101
105 static std::optional<QString> signalName(QStringView handlerName)
106 {
107 if (handlerName.startsWith(u"on") && handlerName.size() > 2) {
108 QString signal = handlerName.mid(2).toString();
109 for (int i = 0; i < signal.size(); ++i) {
110 QChar &ch = signal[i];
111 if (ch.isLower())
112 return {};
113 if (ch.isUpper()) {
114 ch = ch.toLower();
115 return signal;
116 }
117 }
118 }
119 return {};
120 }
121
122 static std::optional<QQmlJSMetaProperty>
124 {
125 if (!signalName.endsWith(QLatin1String("Changed")))
126 return {};
127 constexpr int length = int(sizeof("Changed") / sizeof(char)) - 1;
128 signalName.chop(length);
129 auto p = scope->property(signalName.toString());
130 const bool isBindable = !p.bindable().isEmpty();
131 const bool canNotify = !p.notify().isEmpty();
132 if (p.isValid() && (isBindable || canNotify))
133 return p;
134 return {};
135 }
136
137 static bool hasCompositeBase(const QQmlJSScope::ConstPtr &scope)
138 {
139 if (!scope)
140 return false;
141 const auto base = scope->baseType();
142 if (!base)
143 return false;
144 return base->isComposite() && base->scopeType() == QQmlSA::ScopeType::QMLScope;
145 }
146
150 };
159 PropertyAccessor accessor)
160 {
161 if (p.bindable().isEmpty())
162 return false;
163 switch (accessor) {
164 case PropertyAccessor::PropertyAccessor_Read:
165 return p.read() == QLatin1String("default");
166 case PropertyAccessor::PropertyAccessor_Write:
167 return p.write() == QLatin1String("default");
168 default:
169 break;
170 }
171 return false;
172 }
173
178 };
180 {
183 ResolvedAliasTarget kind = ResolvedAliasTarget::AliasTarget_Invalid;
184 };
186 {
187 std::function<void()> reset = []() {};
188 std::function<void(const QQmlJSScope::ConstPtr &)> processResolvedId =
189 [](const QQmlJSScope::ConstPtr &) {};
190 std::function<void(const QQmlJSMetaProperty &, const QQmlJSScope::ConstPtr &)>
191 processResolvedProperty =
192 [](const QQmlJSMetaProperty &, const QQmlJSScope::ConstPtr &) {};
193 };
194 static ResolvedAlias resolveAlias(const QQmlJSTypeResolver *typeResolver,
196 const QQmlJSScope::ConstPtr &owner,
197 const AliasResolutionVisitor &visitor);
198 static ResolvedAlias resolveAlias(const QQmlJSScopesById &idScopes,
200 const QQmlJSScope::ConstPtr &owner,
201 const AliasResolutionVisitor &visitor);
202
203 template<typename QQmlJSScopePtr, typename Action>
204 static bool searchBaseAndExtensionTypes(QQmlJSScopePtr type, const Action &check)
205 {
206 if (!type)
207 return false;
208
209 using namespace detail;
210
211 // NB: among other things, getQQmlJSScopeFromSmartPtr() also resolves const
212 // vs non-const pointer issue, so use it's return value as the type
213 using T = decltype(getQQmlJSScopeFromSmartPtr<QQmlJSScopePtr>(
214 std::declval<QQmlJSScope::ConstPtr>()));
215
216 const auto checkWrapper = [&](const auto &scope, QQmlJSScope::ExtensionKind mode) {
217 if constexpr (std::is_invocable<Action, decltype(scope),
219 return check(scope, mode);
220 } else {
221 static_assert(std::is_invocable<Action, decltype(scope)>::value,
222 "Inferred type Action has unexpected arguments");
223 Q_UNUSED(mode);
224 return check(scope);
225 }
226 };
227
228 const bool isValueOrSequenceType = [type]() {
229 switch (type->accessSemantics()) {
230 case QQmlJSScope::AccessSemantics::Value:
231 case QQmlJSScope::AccessSemantics::Sequence:
232 return true;
233 default:
234 break;
235 }
236 return false;
237 }();
238
240 for (T scope = type; scope && !seen.hasSeen(scope);
241 scope = getQQmlJSScopeFromSmartPtr<QQmlJSScopePtr>(scope->baseType())) {
242 QDuplicateTracker<T> seenExtensions;
243 // Extensions override the types they extend. However, usually base
244 // types of extensions are ignored. The unusual cases are when we
245 // have a value or sequence type or when we have the QObject type, in which
246 // case we also study the extension's base type hierarchy.
247 const bool isQObject = scope->internalName() == QLatin1String("QObject");
248 auto [extensionPtr, extensionKind] = scope->extensionType();
249 auto extension = getQQmlJSScopeFromSmartPtr<QQmlJSScopePtr>(extensionPtr);
250 do {
251 if (!extension || seenExtensions.hasSeen(extension))
252 break;
253
254 if (checkWrapper(extension, extensionKind))
255 return true;
256 extension = getQQmlJSScopeFromSmartPtr<QQmlJSScopePtr>(extension->baseType());
257 } while (isValueOrSequenceType || isQObject);
258
259 if (checkWrapper(scope, QQmlJSScope::NotExtension))
260 return true;
261 }
262
263 return false;
264 }
265
266 template<typename Action>
267 static void traverseFollowingQmlIrObjectStructure(const QQmlJSScope::Ptr &root, Action act)
268 {
269 // We *have* to perform DFS here: QmlIR::Object entries within the
270 // QmlIR::Document are stored in the order they appear during AST traversal
271 // (which does DFS)
273 stack.push(root);
274
275 while (!stack.isEmpty()) {
276 QQmlJSScope::Ptr current = stack.pop();
277
278 act(current);
279
280 auto children = current->childScopes();
281 // arrays are special: they are reverse-processed in QmlIRBuilder
282 if (!current->isArrayScope())
283 std::reverse(children.begin(), children.end()); // left-to-right DFS
284 stack.append(std::move(children));
285 }
286 }
287
298 template<typename Action>
300 const QQmlJSScope::ConstPtr &start, Action act)
301 {
302 // Meta objects are arranged in the following way:
303 // * static meta objects are chained first
304 // * dynamic meta objects are added on top - they come from extensions.
305 // QQmlVMEMetaObject ignored here
306 //
307 // Example:
308 // ```
309 // class A : public QObject {
310 // QML_EXTENDED(Ext)
311 // };
312 // class B : public A {
313 // QML_EXTENDED(Ext2)
314 // };
315 // ```
316 // gives: Ext2 -> Ext -> B -> A -> QObject
317 // ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^
318 // ^^^^^^^^^^^ static meta objects
319 // dynamic meta objects
320
321 using namespace Qt::StringLiterals;
322 // ignore special extensions
323 const QLatin1String ignoredExtensionNames[] = {
324 // QObject extensions: (not related to C++)
325 "Object"_L1,
326 "ObjectPrototype"_L1,
327 };
328
331 const auto collect = [&](const QQmlJSScope::ConstPtr &type, QQmlJSScope::ExtensionKind m) {
334 return false;
335 }
336
337 for (const auto &name : ignoredExtensionNames) {
338 if (type->internalName() == name)
339 return false;
340 }
341 extensions.append(QQmlJSScope::AnnotatedScope { type, m });
342 return false;
343 };
344 searchBaseAndExtensionTypes(scope, collect);
345
347 all.reserve(extensions.size() + types.size());
348 // first extensions then types
349 all.append(std::move(extensions));
350 all.append(std::move(types));
351
352 auto begin = all.cbegin();
353 // skip to start
354 while (begin != all.cend() && !begin->scope->isSameType(start))
355 ++begin;
356
357 // iterate over extensions and types starting at a specified point
358 for (; begin != all.cend(); ++begin)
359 act(begin->scope, begin->extensionSpecifier);
360 }
361
362 static std::optional<QQmlJSFixSuggestion> didYouMean(const QString &userInput,
363 QStringList candidates,
365
366 static std::variant<QString, QQmlJS::DiagnosticMessage>
367 sourceDirectoryPath(const QQmlJSImporter *importer, const QString &buildDirectoryPath);
368};
369
370bool Q_QMLCOMPILER_PRIVATE_EXPORT canStrictlyCompareWithVar(
371 const QQmlJSTypeResolver *typeResolver, const QQmlJSRegisterContent &lhsContent,
372 const QQmlJSRegisterContent &rhsContent);
373
374bool Q_QMLCOMPILER_PRIVATE_EXPORT canCompareWithQObject(const QQmlJSTypeResolver *typeResolver,
375 const QQmlJSRegisterContent &lhsContent,
376 const QQmlJSRegisterContent &rhsContent);
377
378bool Q_QMLCOMPILER_PRIVATE_EXPORT canCompareWithQUrl(const QQmlJSTypeResolver *typeResolver,
379 const QQmlJSRegisterContent &lhsContent,
380 const QQmlJSRegisterContent &rhsContent);
381
383
384#endif // QQMLJSUTILS_P_H
\inmodule QtCore
Definition qchar.h:48
bool hasSeen(const T &s)
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
void append(parameter_type t)
Definition qlist.h:441
QString bindable() const
QVector< QQmlJSScope::Ptr > childScopes()
bool isArrayScope() const
QQmlJSMetaProperty property(const QString &name) const
QQmlJSScope::ConstPtr baseType() const
\inmodule QtCore
Definition qstack.h:13
T pop()
Removes the top item from the stack and returns it.
Definition qstack.h:18
void push(const T &t)
Adds element t to the top of the stack.
Definition qstack.h:17
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:76
bool startsWith(QStringView s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
constexpr void chop(qsizetype n) noexcept
Truncates this string view by length characters.
constexpr qsizetype size() const noexcept
Returns the size of this string view, in UTF-16 code units (that is, surrogate pairs count as two for...
bool endsWith(QStringView s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
QString toString() const
Returns a deep copy of this string view's data as a QString.
Definition qstring.h:1014
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
void extension()
[6]
Definition dialogs.cpp:230
auto signal
Combined button and popup list for selecting options.
static auto getQQmlJSScopeFromSmartPtr(const From &p) -> From
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
GLint location
GLenum mode
const GLfloat * m
GLsizei GLenum GLenum * types
GLenum GLuint GLenum GLsizei length
GLenum type
GLuint start
GLuint name
GLboolean reset
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
static QQmlJSUtils::ResolvedAlias resolveAlias(ScopeForId scopeForId, const QQmlJSMetaProperty &property, const QQmlJSScope::ConstPtr &owner, const QQmlJSUtils::AliasResolutionVisitor &visitor)
bool Q_QMLCOMPILER_PRIVATE_EXPORT canCompareWithQUrl(const QQmlJSTypeResolver *typeResolver, const QQmlJSRegisterContent &lhsContent, const QQmlJSRegisterContent &rhsContent)
bool Q_QMLCOMPILER_PRIVATE_EXPORT canCompareWithQObject(const QQmlJSTypeResolver *typeResolver, const QQmlJSRegisterContent &lhsContent, const QQmlJSRegisterContent &rhsContent)
bool Q_QMLCOMPILER_PRIVATE_EXPORT canStrictlyCompareWithVar(const QQmlJSTypeResolver *typeResolver, const QQmlJSRegisterContent &lhsContent, const QQmlJSRegisterContent &rhsContent)
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define Q_UNUSED(x)
const char property[13]
Definition qwizard.cpp:101
QQmlJSScope::ConstPtr owner
QQmlJSMetaProperty property
static QString escapeString(QString s)
static void traverseFollowingQmlIrObjectStructure(const QQmlJSScope::Ptr &root, Action act)
static QString toLiteral(const QString &s, QStringView ctor=u"QStringLiteral")
static std::optional< QQmlJSMetaProperty > changeHandlerProperty(const QQmlJSScope::ConstPtr &scope, QStringView signalName)
static bool hasCompositeBase(const QQmlJSScope::ConstPtr &scope)
static void traverseFollowingMetaObjectHierarchy(const QQmlJSScope::ConstPtr &scope, const QQmlJSScope::ConstPtr &start, Action act)
static QString constRefify(QString type)
static std::optional< QString > signalName(QStringView handlerName)
static bool bindablePropertyHasDefaultAccessor(const QQmlJSMetaProperty &p, PropertyAccessor accessor)
static bool searchBaseAndExtensionTypes(QQmlJSScopePtr type, const Action &check)