18#include <qtqmlcompilerexports.h>
25#include <QtCore/qdir.h>
26#include <QtCore/qstack.h>
27#include <QtCore/qstring.h>
28#include <QtCore/qstringbuilder.h>
29#include <QtCore/qstringview.h>
31#include <QtQml/private/qqmlsignalnames_p.h>
32#include <private/qduplicatetracker_p.h>
43
44
45
46
47template<
typename To,
typename From,
typename std::enable_if_t<!std::is_pointer_v<To>,
int> = 0>
50 static_assert(!
std::is_pointer_v<From>,
"From has to be a smart pointer holding QQmlJSScope");
55
56
57
58
59
60
61template<
typename To,
typename From,
typename std::enable_if_t<std::is_pointer_v<To>,
int> = 0>
62static auto getQQmlJSScopeFromSmartPtr(
const From &p) ->
decltype(p.get())
64 static_assert(!
std::is_pointer_v<From>,
"From has to be a smart pointer holding QQmlJSScope");
69class QQmlJSTypeResolver;
74
75
76
77 template<
typename String,
typename CharacterLiteral,
typename StringView>
78 static String escapeString(String s)
80 return s.replace(CharacterLiteral(
'\\'), StringView(
"\\\\"))
81 .replace(CharacterLiteral(
'"'), StringView(
"\\\""))
82 .replace(CharacterLiteral(
'\n'), StringView(
"\\n"))
83 .replace(CharacterLiteral(
'?'), StringView(
"\\?"));
87
88
89
90
91
92
94 typename String = QString,
95 typename CharacterLiteral = QLatin1Char,
96 typename StringView = QLatin1StringView>
97 static String toLiteral(
const String &s, StringView ctor = StringView(
"QStringLiteral"))
99 return ctor % StringView(
"(\"")
100 % escapeString<String, CharacterLiteral, StringView>(s) % StringView(
"\")");
104
105
106
107 static QString constRefify(QString type)
109 if (!type.endsWith(u'*'))
110 type = u"const " % type % u"&";
114 static std::optional<QQmlJSMetaProperty>
115 changeHandlerProperty(
const QQmlJSScope::ConstPtr &scope, QStringView signalName)
117 if (!signalName.endsWith(QLatin1String(
"Changed")))
119 constexpr int length =
int(
sizeof(
"Changed") /
sizeof(
char)) - 1;
120 signalName.chop(length);
121 auto p = scope->property(signalName.toString());
122 const bool isBindable = !p.bindable().isEmpty();
123 const bool canNotify = !p.notify().isEmpty();
124 if (p.isValid() && (isBindable || canNotify))
129 static std::optional<QQmlJSMetaProperty>
130 propertyFromChangedHandler(
const QQmlJSScope::ConstPtr &scope, QStringView changedHandler)
132 auto signalName = QQmlSignalNames::changedHandlerNameToPropertyName(changedHandler);
136 auto p = scope->property(*signalName);
137 const bool isBindable = !p.bindable().isEmpty();
138 const bool canNotify = !p.notify().isEmpty();
139 if (p.isValid() && (isBindable || canNotify))
144 static bool hasCompositeBase(
const QQmlJSScope::ConstPtr &scope)
148 const auto base = scope->baseType();
151 return base->isComposite() && base->scopeType() == QQmlSA::ScopeType::QMLScope;
154 enum PropertyAccessor {
155 PropertyAccessor_Read,
156 PropertyAccessor_Write,
159
160
161
162
163
164
165 static bool bindablePropertyHasDefaultAccessor(
const QQmlJSMetaProperty &p,
166 PropertyAccessor accessor)
168 if (p.bindable().isEmpty())
171 case PropertyAccessor::PropertyAccessor_Read:
172 return p.read() == QLatin1String(
"default");
173 case PropertyAccessor::PropertyAccessor_Write:
174 return p.write() == QLatin1String(
"default");
181 enum ResolvedAliasTarget {
183 AliasTarget_Property,
188 QQmlJSMetaProperty property;
189 QQmlJSScope::ConstPtr owner;
190 ResolvedAliasTarget kind = ResolvedAliasTarget::AliasTarget_Invalid;
192 struct AliasResolutionVisitor
194 std::function<
void()> reset = []() {};
195 std::function<
void(
const QQmlJSScope::ConstPtr &)> processResolvedId =
196 [](
const QQmlJSScope::ConstPtr &) {};
197 std::function<
void(
const QQmlJSMetaProperty &,
const QQmlJSScope::ConstPtr &)>
198 processResolvedProperty =
199 [](
const QQmlJSMetaProperty &,
const QQmlJSScope::ConstPtr &) {};
201 static ResolvedAlias resolveAlias(
const QQmlJSTypeResolver *typeResolver,
202 const QQmlJSMetaProperty &property,
203 const QQmlJSScope::ConstPtr &owner,
204 const AliasResolutionVisitor &visitor);
205 static ResolvedAlias resolveAlias(
const QQmlJSScopesById &idScopes,
206 const QQmlJSMetaProperty &property,
207 const QQmlJSScope::ConstPtr &owner,
208 const AliasResolutionVisitor &visitor);
210 template<
typename QQmlJSScopePtr,
typename Action>
211 static bool searchBaseAndExtensionTypes(
const QQmlJSScopePtr &type,
const Action &check)
216 using namespace detail;
220 using T =
decltype(getQQmlJSScopeFromSmartPtr<QQmlJSScopePtr>(
221 std::declval<QQmlJSScope::ConstPtr>()));
223 const auto checkWrapper = [&](
const auto &scope, QQmlJSScope::ExtensionKind mode) {
224 if constexpr (std::is_invocable<Action,
decltype(scope),
225 QQmlJSScope::ExtensionKind>::value) {
226 return check(scope, mode);
228 static_assert(std::is_invocable<Action,
decltype(scope)>::value,
229 "Inferred type Action has unexpected arguments");
235 const bool isValueOrSequenceType = [type]() {
236 switch (type->accessSemantics()) {
237 case QQmlJSScope::AccessSemantics::Value:
238 case QQmlJSScope::AccessSemantics::Sequence:
246 QDuplicateTracker<T> seen;
247 for (T scope = type; scope && !seen.hasSeen(scope);
248 scope = getQQmlJSScopeFromSmartPtr<QQmlJSScopePtr>(scope->baseType())) {
249 QDuplicateTracker<T> seenExtensions;
254 const bool isQObject = scope->internalName() == QLatin1String(
"QObject");
255 auto [extensionPtr, extensionKind] = scope->extensionType();
257 if (extensionKind == QQmlJSScope::ExtensionJavaScript
258 && checkWrapper(scope, QQmlJSScope::NotExtension)) {
262 auto extension = getQQmlJSScopeFromSmartPtr<QQmlJSScopePtr>(extensionPtr);
264 if (!extension || seenExtensions.hasSeen(extension))
267 if (checkWrapper(extension, extensionKind))
269 extension = getQQmlJSScopeFromSmartPtr<QQmlJSScopePtr>(extension->baseType());
270 }
while (isValueOrSequenceType || isQObject);
272 if (extensionKind != QQmlJSScope::ExtensionJavaScript
273 && checkWrapper(scope, QQmlJSScope::NotExtension)) {
281 template<
typename Action>
282 static void traverseFollowingQmlIrObjectStructure(
const QQmlJSScope::Ptr &root, Action act)
287 QStack<QQmlJSScope::Ptr> stack;
290 while (!stack.isEmpty()) {
291 QQmlJSScope::Ptr current = stack.pop();
295 auto children = current->childScopes();
297 if (!current->isArrayScope())
298 std::reverse(children.begin(), children.end());
299 stack.append(std::move(children));
304
305
306
307
308
309
310
311
312
313 template<
typename Action>
314 static void traverseFollowingMetaObjectHierarchy(
const QQmlJSScope::ConstPtr &scope,
315 const QQmlJSScope::ConstPtr &start, Action act)
336 using namespace Qt::StringLiterals;
338 const QLatin1String ignoredExtensionNames[] = {
341 "ObjectPrototype"_L1,
344 QList<QQmlJSScope::AnnotatedScope> types;
345 QList<QQmlJSScope::AnnotatedScope> extensions;
346 const auto collect = [&](
const QQmlJSScope::ConstPtr &type, QQmlJSScope::ExtensionKind m) {
347 if (m == QQmlJSScope::NotExtension) {
348 types.append(QQmlJSScope::AnnotatedScope { type, m });
352 for (
const auto &name : ignoredExtensionNames) {
353 if (type->internalName() == name)
356 extensions.append(QQmlJSScope::AnnotatedScope { type, m });
359 searchBaseAndExtensionTypes(scope, collect);
361 QList<QQmlJSScope::AnnotatedScope> all;
362 all.reserve(extensions.size() + types.size());
364 all.append(std::move(extensions));
365 all.append(std::move(types));
367 auto begin = all.cbegin();
369 while (begin != all.cend() && !begin->scope->isSameType(start))
373 for (; begin != all.cend(); ++begin)
374 act(begin->scope, begin->extensionSpecifier);
377 static std::optional<QQmlJSFixSuggestion> didYouMean(
const QString &userInput,
378 QStringList candidates,
379 QQmlJS::SourceLocation location);
381 static std::variant<QString, QQmlJS::DiagnosticMessage>
382 sourceDirectoryPath(
const QQmlJSImporter *importer,
const QString &buildDirectoryPath);
384 template <
typename Container>
385 static void deduplicate(Container &container)
387 std::sort(container.begin(), container.end());
388 auto erase = std::unique(container.begin(), container.end());
389 container.erase(erase, container.end());
392 static QStringList cleanPaths(QStringList &&paths)
394 for (QString &path : paths)
395 path = QDir::cleanPath(path);
396 return std::move(paths);
399 static QStringList resourceFilesFromBuildFolders(
const QStringList &buildFolders);
400 static QString qmlSourcePathFromBuildPath(
const QQmlJSResourceFileMapper *mapper,
401 const QString &pathInBuildFolder);
402 static QString qmlBuildPathFromSourcePath(
const QQmlJSResourceFileMapper *mapper,
403 const QString &pathInBuildFolder);
406bool Q_QMLCOMPILER_EXPORT canStrictlyCompareWithVar(
407 const QQmlJSTypeResolver *typeResolver,
const QQmlJSScope::ConstPtr &lhsType,
408 const QQmlJSScope::ConstPtr &rhsType);
410bool Q_QMLCOMPILER_EXPORT canCompareWithQObject(
411 const QQmlJSTypeResolver *typeResolver,
const QQmlJSScope::ConstPtr &lhsType,
412 const QQmlJSScope::ConstPtr &rhsType);
414bool Q_QMLCOMPILER_EXPORT canCompareWithQUrl(
415 const QQmlJSTypeResolver *typeResolver,
const QQmlJSScope::ConstPtr &lhsType,
416 const QQmlJSScope::ConstPtr &rhsType);
friend bool operator==(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept
Returns true if lhs and rhs are equal, otherwise returns false.
friend bool operator!=(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept
Returns true if lhs and rhs are different, otherwise returns false.
QString fileName() const
If the currently assigned device is a QFile, or if setFileName() has been called, this function retur...
void setFileName(const QString &fileName)
Sets the file name of QImageReader to fileName.
virtual Type type() const =0
Reimplement this function to return the paint engine \l{Type}.
virtual bool isValid() const
QQmlJSRegisterContent createMethod(const QList< QQmlJSMetaMethod > &methods, const QQmlJSScope::ConstPtr &methodType, ContentVariant variant, QQmlJSRegisterContent scope)
QQmlJSRegisterContent createImportNamespace(uint importNamespaceStringId, const QQmlJSScope::ConstPtr &importNamespaceType, ContentVariant variant, QQmlJSRegisterContent scope)
QQmlJSRegisterContent createProperty(const QQmlJSMetaProperty &property, int baseLookupIndex, int resultLookupIndex, ContentVariant variant, QQmlJSRegisterContent scope)
void adjustType(QQmlJSRegisterContent content, const QQmlJSScope::ConstPtr &adjusted)
void generalizeType(QQmlJSRegisterContent content, const QQmlJSScope::ConstPtr &generalized)
void storeType(QQmlJSRegisterContent content, const QQmlJSScope::ConstPtr &stored)
QQmlJSRegisterContent castTo(QQmlJSRegisterContent content, const QQmlJSScope::ConstPtr &newContainedType)
QQmlJSRegisterContent createEnumeration(const QQmlJSMetaEnum &enumeration, const QString &enumMember, ContentVariant variant, QQmlJSRegisterContent scope)
void setAllocationMode(AllocationMode mode)
QQmlJSRegisterContent storedIn(QQmlJSRegisterContent content, const QQmlJSScope::ConstPtr &newStoredType)
QQmlJSRegisterContent clone(QQmlJSRegisterContent from)
QQmlJSRegisterContentPool()
QQmlJSRegisterContent createType(const QQmlJSScope::ConstPtr &type, int resultLookupIndex, ContentVariant variant, QQmlJSRegisterContent scope={})
QQmlJSRegisterContent createConversion(const QList< QQmlJSRegisterContent > &origins, const QQmlJSScope::ConstPtr &conversion, QQmlJSRegisterContent conversionScope, ContentVariant variant, QQmlJSRegisterContent scope)
QQmlJSRegisterContent createMethodCall(const QQmlJSMetaMethod &method, const QQmlJSScope::ConstPtr &returnType, QQmlJSRegisterContent scope)
Tracks the types for the QmlCompiler.
QTypeRevision revision() const
QTypeRevision version() const
Export(QString package, QString type, QTypeRevision version, QTypeRevision revision)
virtual QQmlSourceLocation sourceLocation() const
static BindingPrivate * get(Binding *binding)
static QQmlJSMetaPropertyBinding binding(QQmlSA::Binding &binding)
Element bindingScope() const
void setPropertyName(QString name)
static QQmlSA::Binding createBinding(const QQmlJSMetaPropertyBinding &)
static const QQmlJSMetaPropertyBinding binding(const QQmlSA::Binding &binding)
void setIsAttached(bool isAttached)
BindingPrivate(Binding *, const BindingPrivate &)
void setBindingScope(Element bindingScope)
static const BindingPrivate * get(const Binding *binding)
Element attachedType() const
Returns the attached type if the content type of this binding is AttachedProperty,...
BindingType bindingType() const
Returns the type of this binding.
Element bindingScope() const
Returns the Element scope in which the binding is defined.
friend bool operator!=(const Binding &lhs, const Binding &rhs)
Returns true if lhs and rhs are not equal, and false otherwise.
bool hasUndefinedScriptValue() const
Returns whether this binding has script value type undefined like when it is assigned undefined.
Binding(const Binding &)
Creates a copy of other.
Binding & operator=(const Binding &)
Assigns other to this Binding instance.
bool isAttached() const
Returns true if this type is attached to another one, false otherwise.
bool hasObject() const
Returns true if this binding has an objects, otherwise returns false.
friend bool operator==(const Binding &lhs, const Binding &rhs)
Returns true if lhs and rhs are equal, and false otherwise.
static bool isLiteralBinding(BindingType)
Returns true if bindingType is a literal type, and false otherwise.
QString propertyName() const
Returns the name of the property bound with this binding.
Binding()
Constructs a new Binding object.
QString stringValue() const
Returns the associated string literal if the content type of this binding is StringLiteral,...
Element objectType() const
Returns the type of the associated object if the content type of this binding is Object,...
Binding & operator=(Binding &&) noexcept
Move-assigns other to this Binding instance.
QQmlSA::SourceLocation sourceLocation() const
Returns the location in the QML code where this binding is defined.
ScriptBindingKind scriptKind() const
Returns the kind of the associated script if the content type of this binding is Script,...
double numberValue() const
Returns the associated number if the content type of this binding is NumberLiteral,...
Element groupType() const
Returns the type of the property of this binding if it is a group property, otherwise returns an inva...
bool hasFunctionScriptValue() const
Returns whether this binding has script value type function like when it is assigned a (lambda) metho...
~BindingsPrivate()=default
QMultiHash< QString, Binding >::const_iterator constBegin() const
BindingsPrivate(QQmlSA::Binding::Bindings *, const BindingsPrivate &)
friend class QT_PREPEND_NAMESPACE(QQmlJSMetaPropertyBinding)
QMultiHash< QString, Binding >::const_iterator constEnd() const
QQmlSA::SourceLocation location() const
FixSuggestionPrivate(FixSuggestion *, const QString &fixDescription, const QQmlSA::SourceLocation &location, const QString &replacement)
void setHint(const QString &)
void setFileName(const QString &)
QString fixDescription() const
FixSuggestionPrivate(FixSuggestion *)
bool isAutoApplicable() const
void setAutoApplicable(bool autoApplicable=true)
static const QQmlJSFixSuggestion & fixSuggestion(const QQmlSA::FixSuggestion &)
FixSuggestionPrivate(FixSuggestion *, FixSuggestionPrivate &&)
~FixSuggestionPrivate()=default
QString replacement() const
static QQmlJSFixSuggestion & fixSuggestion(QQmlSA::FixSuggestion &)
FixSuggestionPrivate(FixSuggestion *, const FixSuggestionPrivate &)
void setHint(const QString &)
Sets hint as the hint for this fix suggestion.
FixSuggestion(const FixSuggestion &)
Creates a copy of other.
QString hint() const
Returns the hint for this fix suggestion.
QString replacement() const
Returns the fix that will replace the problematic source code.
QString fixDescription() const
Returns the description of the fix.
bool isAutoApplicable() const
Returns whether this suggested fix can be applied automatically.
void setAutoApplicable(bool autoApplicable=true)
Sets autoApplicable to determine whether this suggested fix can be applied automatically.
void emitWarning(QAnyStringView diagnostic, LoggerWarningId id)
Emits a warning message diagnostic about an issue of type id.
Element resolveLiteralType(const Binding &binding)
Returns the element representing the type of literal in binding.
void emitWarning(QAnyStringView diagnostic, LoggerWarningId id, QQmlSA::SourceLocation srcLocation, const QQmlSA::FixSuggestion &fix)
Emits a warning message diagnostic about an issue of type id located at srcLocation and with suggeste...
void emitWarning(QAnyStringView diagnostic, LoggerWarningId id, QQmlSA::SourceLocation srcLocation)
Emits warning message diagnostic about an issue of type id located at srcLocation.
Element resolveBuiltinType(QAnyStringView typeName) const
Returns the type of the built-in type identified by typeName.
Element resolveAttached(QAnyStringView moduleName, QAnyStringView typeName)
Returns the attached type of typeName defined in module moduleName.
QString resolveElementToId(const Element &element, const Element &context)
Returns the id of element in a given context.
Element resolveTypeInFileScope(QAnyStringView typeName)
Returns the type corresponding to typeName inside the currently analysed file.
QString sourceCode(QQmlSA::SourceLocation location)
Returns the source code located within location.
Element resolveAttachedInFileScope(QAnyStringView typeName)
Returns the attached type corresponding to typeName used inside the currently analysed file.
Element resolveIdToElement(QAnyStringView id, const Element &context)
Returns the element in context that has id id.
Element resolveType(QAnyStringView moduleName, QAnyStringView typeName)
Returns the type of typeName defined in module moduleName.
MethodPrivate(Method *, const MethodPrivate &)
QQmlSA::SourceLocation sourceLocation() const
static QQmlSA::Method createMethod(const QQmlJSMetaMethod &)
MethodType methodType() const
static QQmlJSMetaMethod method(const QQmlSA::Method &)
QString methodName() const
Method & operator=(Method &&) noexcept
Move-assigns other to this Method instance.
MethodType methodType() const
Returns the type of this method.
Method(const Method &)
Creates a copy of other.
Method()
Constructs a new Method object.
Method & operator=(const Method &)
Assigns other to this Method instance.
QString methodName() const
Returns the name of the this method.
MethodsPrivate(QQmlSA::Method::Methods *, MethodsPrivate &&)
static QQmlSA::Method::Methods createMethods(const QMultiHash< QString, QQmlJSMetaMethod > &)
QMultiHash< QString, Method >::const_iterator constEnd() const
~MethodsPrivate()=default
MethodsPrivate(QQmlSA::Method::Methods *, const MethodsPrivate &)
QMultiHash< QString, Method >::const_iterator constBegin() const
void analyze(const Element &root)
Runs the element passes over root and all its children.
bool isCategoryEnabled(LoggerWarningId category) const
Returns true if warnings of category are enabled, false otherwise.
bool registerPropertyPass(std::shared_ptr< PropertyPass > pass, QAnyStringView moduleName, QAnyStringView typeName, QAnyStringView propertyName=QAnyStringView(), bool allowInheritance=true)
Registers a static analysis pass for properties.
std::unordered_map< quint32, Binding > bindingsByLocation() const
Returns bindings by their source location.
bool hasImportedModule(QAnyStringView name) const
Returns true if the module named module has been imported by the QML to be analyzed,...
PropertyPassBuilder(PassManager *passManager)
PropertyPassBuilder()=delete
~PropertyPrivate()=default
static QQmlSA::Property createProperty(const QQmlJSMetaProperty &)
PropertyPrivate(Property *, const PropertyPrivate &)
PropertyPrivate(Property *, PropertyPrivate &&)
static QQmlJSMetaProperty property(const QQmlSA::Property &property)
QQmlSA::Element type() const
Returns the type that this property was defined with.
bool isReadonly() const
Returns whether this property is readonly.
Property(const Property &)
Creates a copy of other.
QString typeName() const
Returns the name of the type of this property.
bool isReadonly() const
Returns true if this property is read-only, false otherwise.
Q_QMLCOMPILER_EXPORT void emitWarningWithOptionalFix(GenericPass &pass, QAnyStringView diagnostic, const LoggerWarningId &id, const QQmlSA::SourceLocation &srcLocation, const std::optional< QQmlJSFixSuggestion > &fix)
@ SignalHandlerFunctionScope
bool isRegularBindingType(BindingType type)
constexpr bool isFunctionScope(ScopeType type)
@ WrappedInImplicitComponent
static auto getQQmlJSScopeFromSmartPtr(const From &p) -> From
Q_DECLARE_INTERFACE(QNetworkAccessBackendFactory, QNetworkAccessBackendFactory_iid)
Q_DECLARE_TYPEINFO(QObjectPrivate::ConnectionList, Q_RELOCATABLE_TYPE)
static QString toNumericString(double value)
static QString messageTypeForMethod(const QString &method)
static QString derefContentPointer(const QString &contentPointer)
#define BYTECODE_UNIMPLEMENTED()
#define INJECT_TRACE_INFO(function)
static QString registerName(int registerIndex, int offset)
static QString minExpression(int argc)
static QString maxExpression(int argc)
static bool isTypeStorable(const QQmlJSTypeResolver *resolver, const QQmlJSScope::ConstPtr &type)
#define QmlLintPluginInterface_iid
static void onWriteDefault(PropertyPass *, const Element &, const QString &, const Element &, const Element &, SourceLocation)
static void onBindingDefault(PropertyPass *, const Element &, const QString &, const Binding &, const Element &, const Element &)
void onRead(const Element &element, const QString &propertyName, const Element &readScope, SourceLocation location) override
Executes whenever a property is read.
static void onCallDefault(PropertyPass *, const Element &, const QString &, const Element &, SourceLocation)
void onBinding(const Element &element, const QString &propertyName, const Binding &binding, const Element &bindingScope, const Element &value) override
Executes whenever a property gets bound to a value.
void onCall(const Element &element, const QString &propertyName, const Element &readScope, SourceLocation location) override
Executes whenever a property or method is called.
static void onReadDefault(PropertyPass *, const Element &, const QString &, const Element &, SourceLocation)
void onWrite(const Element &element, const QString &propertyName, const Element &value, const Element &writeScope, SourceLocation location) override
Executes whenever a property is written to.
std::shared_ptr< QQmlSA::PropertyPass > pass