8#include <QtQmlCompiler/private/qqmljsimporter_p.h>
9#include <QtQmlCompiler/private/qqmljsimportvisitor_p.h>
10#include <QtQmlCompiler/private/qqmljsliteralbindingcheck_p.h>
12#include <QtCore/qjsonobject.h>
13#include <QtCore/qfileinfo.h>
14#include <QtCore/qloggingcategory.h>
15#include <QtCore/qpluginloader.h>
16#include <QtCore/qlibraryinfo.h>
17#include <QtCore/qdir.h>
18#include <QtCore/private/qduplicatetracker_p.h>
19#include <QtCore/qscopedpointer.h>
21#include <QtQmlCompiler/private/qqmlsa_p.h>
22#include <QtQmlCompiler/private/qqmljsloggingutils_p.h>
25# include <QtCore/qdiriterator.h>
26# include <QtCore/qlibrary.h>
29#include <QtQml/private/qqmljslexer_p.h>
30#include <QtQml/private/qqmljsparser_p.h>
31#include <QtQml/private/qqmljsengine_p.h>
32#include <QtQml/private/qqmljsastvisitor_p.h>
33#include <QtQml/private/qqmljsast_p.h>
34#include <QtQml/private/qqmljsdiagnosticmessage_p.h>
52 u
"Variable \"%1\" is used here before its declaration. The declaration is at %2:%3."_s
70 : m_useAbsolutePath(useAbsolutePath),
71 m_enablePlugins(true),
72 m_importer(importPaths,
nullptr, true)
78 : m_name(std::move(plugin.m_name))
79 , m_description(std::move(plugin.m_description))
80 , m_version(std::move(plugin.m_version))
81 , m_author(std::move(plugin.m_author))
82 , m_categories(std::move(plugin.m_categories))
83 , m_instance(std::move(plugin.m_instance))
84 , m_loader(std::move(plugin.m_loader))
85 , m_isBuiltin(std::move(plugin.m_isBuiltin))
86 , m_isInternal(std::move(plugin.m_isInternal))
87 , m_isValid(std::move(plugin.m_isValid))
91 plugin.m_instance =
nullptr;
92 plugin.m_isValid =
false;
98 m_loader = std::make_unique<QPluginLoader>(
path);
99 if (!parseMetaData(m_loader->metaData(),
path))
102 QObject *
object = m_loader->instance();
106 m_instance = qobject_cast<QQmlSA::LintPlugin *>(
object);
116 if (!parseMetaData(staticPlugin.metaData(), u
"built-in"_s))
119 m_instance = qobject_cast<QQmlSA::LintPlugin *>(staticPlugin.instance());
128#if QT_CONFIG(library)
129 if (m_loader !=
nullptr) {
131 m_loader->deleteLater();
136bool QQmlJSLinter::Plugin::parseMetaData(
const QJsonObject &metaData,
QString pluginName)
140 if (metaData[u
"IID"].
toString() != pluginIID)
143 QJsonObject pluginMetaData = metaData[u
"MetaData"].toObject();
145 for (
const QString &requiredKey :
146 { u
"name"_s, u
"version"_s, u
"author"_s, u
"loggingCategories"_s }) {
147 if (!pluginMetaData.contains(requiredKey)) {
148 qWarning() << pluginName <<
"is missing the required " << requiredKey
149 <<
"metadata, skipping";
154 m_name = pluginMetaData[u
"name"].toString();
155 m_author = pluginMetaData[u
"author"].toString();
156 m_version = pluginMetaData[u
"version"].toString();
157 m_description = pluginMetaData[u
"description"].toString(u
"-/-"_s);
158 m_isInternal = pluginMetaData[u
"isInternal"].toBool(
false);
160 if (!pluginMetaData[u
"loggingCategories"].isArray()) {
161 qWarning() << pluginName <<
"has loggingCategories which are not an array, skipping";
168 if (!
value.isObject()) {
169 qWarning() << pluginName <<
"has invalid loggingCategories entries, skipping";
175 for (
const QString &requiredKey : { u
"name"_s, u
"description"_s }) {
176 if (!
object.
contains(requiredKey)) {
177 qWarning() << pluginName <<
" logging category is missing the required "
178 << requiredKey <<
"metadata, skipping";
183 const auto it =
object.
find(
"enabled"_L1);
184 const bool ignored = (
it !=
object.
end() && !
it->toBool());
187 (m_isInternal ? u
""_s : u
"Plugin."_s) + m_name + u
'.' +
object[u
"name"].
toString();
188 const auto settingsNameIt =
object.constFind(u
"settingsName");
189 const QString settingsName = (settingsNameIt ==
object.constEnd())
191 : settingsNameIt->
toString(categoryId);
204 QDuplicateTracker<QString> seenPlugins;
207 Plugin plugin(staticPlugin);
208 if (!plugin.isValid())
211 if (seenPlugins.hasSeen(plugin.name().toLower())) {
212 qWarning() <<
"Two plugins named" << plugin.name()
213 <<
"present, make sure no plugins are duplicated. The second plugin will "
218 plugins.push_back(std::move(plugin));
221#if QT_CONFIG(library)
225 while (
it.hasNext()) {
226 auto potentialPlugin =
it.next();
231 Plugin plugin(potentialPlugin);
233 if (!plugin.isValid())
236 if (seenPlugins.hasSeen(plugin.name().toLower())) {
237 qWarning() <<
"Two plugins named" << plugin.name()
238 <<
"present, make sure no plugins are duplicated. The second plugin "
239 "will not be loaded.";
243 plugins.push_back(std::move(plugin));
252 const QList<QQmlJS::SourceLocation> &comments)
254 QHash<int, QSet<QString>> disablesPerLine;
255 QHash<int, QSet<QString>> enablesPerLine;
256 QHash<int, QSet<QString>> oneLineDisablesPerLine;
262 for (
const auto &loc : comments) {
263 const QString comment = code.
mid(loc.offset, loc.length);
268 if (words.size() < 2)
274 const auto categoryExists = std::any_of(
275 loggerCategories.cbegin(), loggerCategories.cend(),
291 if (command == u
"disable"_s) {
292 if (
const qsizetype lineIndex = loc.startLine - 1; lineIndex < lines.size()) {
296 bool lineHasContent =
false;
298 if (!preComment[
i].isSpace()) {
299 lineHasContent =
true;
305 oneLineDisablesPerLine[loc.startLine] |=
categories;
309 }
else if (command == u
"enable"_s) {
310 enablesPerLine[loc.startLine + 1] |=
categories;
312 logger->
log(u
"Invalid qmllint directive \"%1\" provided"_s.arg(command),
317 if (disablesPerLine.isEmpty() && oneLineDisablesPerLine.isEmpty())
320 QSet<QString> currentlyDisabled;
322 currentlyDisabled.unite(disablesPerLine[
i]).subtract(enablesPerLine[
i]);
324 currentlyDisabled.unite(oneLineDisablesPerLine[
i]);
326 if (!currentlyDisabled.isEmpty())
329 currentlyDisabled.subtract(oneLineDisablesPerLine[
i]);
334 QAnyStringView id,
const std::optional<QQmlJSFixSuggestion> &suggestion = {})
347 type = u
"critical"_s;
360 jsonMessage[u
"type"_s] =
type;
361 jsonMessage[u
"id"_s] =
id.toString();
364 jsonMessage[u
"line"_s] =
static_cast<int>(
message.loc.startLine);
365 jsonMessage[u
"column"_s] =
static_cast<int>(
message.loc.startColumn);
366 jsonMessage[u
"charOffset"_s] =
static_cast<int>(
message.loc.offset);
367 jsonMessage[u
"length"_s] =
static_cast<int>(
message.loc.length);
370 jsonMessage[u
"message"_s] =
message.message;
379 if (suggestion.has_value()) {
381 {
"message"_L1, suggestion->fixDescription() },
382 {
"replacement"_L1, suggestion->replacement() },
383 {
"isHint"_L1, !suggestion->isAutoApplicable() },
385 convertLocation(suggestion->location(), &jsonFix);
386 const QString filename = suggestion->filename();
388 jsonFix.
insert(
"fileName"_L1, filename);
389 suggestions << jsonFix;
392 if (!
hint.isEmpty()) {
396 {
"message"_L1,
hint },
397 {
"replacement"_L1,
QString() },
398 {
"isHint"_L1,
true }
401 suggestions << jsonHint;
404 jsonMessage[u
"suggestions"] = suggestions;
406 warnings << jsonMessage;
410void QQmlJSLinter::processMessages(
QJsonArray &warnings)
412 for (
const auto &
error : m_logger->errors())
414 for (
const auto &
warning : m_logger->warnings())
416 for (
const auto &
info : m_logger->infos())
421 const QString *fileContents,
const bool silent,
425 const QList<QQmlJS::LoggerCategory> &
categories)
440 result[u
"warnings"] = warnings;
441 result[u
"success"] = success;
448 if (fileContents ==
nullptr) {
459 }
else if (!silent) {
468 code = *fileContents;
471 m_fileContents = code;
477 const QString lowerSuffix =
info.suffix().toLower();
479 const bool isJavaScript = isESModule || lowerSuffix ==
QLatin1String(
"js");
481 lexer.
setCode(code, 1, !isJavaScript);
482 QQmlJS::Parser parser(&
engine);
484 success = isJavaScript ? (isESModule ? parser.parseModule() : parser.parseProgram())
488 const auto diagnosticMessages = parser.diagnosticMessages();
492 }
else if (!silent) {
495 .arg(
m.loc.startLine)
496 .arg(
m.loc.startColumn)
503 if (success && !isJavaScript) {
511 m_logger->
setFileName(m_useAbsolutePath ?
info.absoluteFilePath() : filename);
517 m_logger->
fileName(), m_importer.resourceFileMapper()),
520 if (m_enablePlugins) {
521 for (
const Plugin &plugin : m_plugins) {
535 parseComments(m_logger.
get(),
engine.comments());
550 typeResolver.
init(&
v, parser.rootNode());
552 using PassManagerPtr = std::unique_ptr<
556 passMan->registerPropertyPass(
557 std::make_unique<QQmlJSLiteralBindingCheck>(passMan.get()),
QString(),
560 if (m_enablePlugins) {
561 for (
const Plugin &plugin : m_plugins) {
562 if (!plugin.isValid() || !plugin.isEnabled())
577 processMessages(warnings);
585 (resourcePaths.size() == 1) ? u
':' + resourcePaths.first() : filename;
588 codegen.setTypeResolver(std::move(typeResolver));
590 codegen.setPassManager(passMan.get());
605 if (!globalWarnings.isEmpty()) {
614 processMessages(warnings);
617 if (resourceFiles.isEmpty()) {
642 if (!resourceFiles.isEmpty())
656 result[u
"module"_s] =
module;
658 result[u
"warnings"] = warnings;
659 result[u
"success"] = success;
671 QList<QQmlJS::DiagnosticMessage> importWarnings =
674 if (!importWarnings.isEmpty()) {
680 QMap<QString, QSet<QString>> missingTypes;
681 QMap<QString, QSet<QString>> partiallyResolvedTypes;
683 const QString modulePrefix = u
"$module$."_s;
684 const QString internalPrefix = u
"$internal$."_s;
686 for (
auto &&[
typeName, importedScope] :
types.types().asKeyValueRange()) {
690 if (
name.startsWith(modulePrefix))
693 if (
name.startsWith(internalPrefix)) {
694 name =
name.mid(internalPrefix.size());
698 if (!missingTypes.contains(
name))
699 missingTypes[
name] = {};
704 if (!partiallyResolvedTypes.contains(
name))
705 partiallyResolvedTypes[
name] = {};
708 if (
property.typeName().isEmpty()) {
714 missingTypes[
property.typeName()]
715 << scope->
internalName() + u
'.' +
property.propertyName();
718 if (!
property.type()->isFullyResolved()) {
719 partiallyResolvedTypes[
property.typeName()]
720 << scope->
internalName() + u
'.' +
property.propertyName();
724 m_logger->
log(u
"Attached type of \"%1\" not fully resolved"_s.arg(
name),
729 if (
method.returnTypeName().isEmpty())
731 if (
method.returnType().isNull()) {
732 missingTypes[
method.returnTypeName()] << u
"return type of "_s
734 }
else if (!
method.returnType()->isFullyResolved()) {
735 partiallyResolvedTypes[
method.returnTypeName()] << u
"return type of "_s
739 const auto parameters =
method.parameters();
741 auto ¶meter = parameters[
i];
743 const QSharedPointer<const QQmlJSScope>
type = parameter.type();
747 missingTypes[
typeName] << u
"parameter %1 of "_s.arg(
i + 1)
751 if (!
type->isFullyResolved()) {
752 partiallyResolvedTypes[
typeName] << u
"parameter %1 of "_s.arg(
i + 1)
760 for (
auto &&[
name, uses] : missingTypes.asKeyValueRange()) {
763 if (!uses.isEmpty()) {
765 message += u
". Used in %1"_s.arg(usesList.join(u
", "_s));
771 for (
auto &&[
name, uses] : partiallyResolvedTypes.asKeyValueRange()) {
774 if (!uses.isEmpty()) {
776 message += u
". Used in %1"_s.arg(usesList.join(u
", "_s));
783 processMessages(warnings);
798 if (m_logger ==
nullptr)
803 QList<QQmlJSFixSuggestion> fixesToApply;
806 const QString currentFileAbsolutePath =
info.absoluteFilePath();
808 const QString lowerSuffix =
info.suffix().toLower();
810 const bool isJavaScript = isESModule || lowerSuffix ==
QLatin1String(
"js");
812 if (isESModule || isJavaScript)
815 for (
const auto &messages : { m_logger->
infos(), m_logger->
warnings(), m_logger->
errors() })
816 for (
const Message &msg : messages) {
817 if (!msg.fixSuggestion.has_value() || !msg.fixSuggestion->isAutoApplicable())
821 const QString filename = msg.fixSuggestion->filename();
827 fixesToApply << msg.fixSuggestion.value();
830 if (fixesToApply.isEmpty())
833 std::sort(fixesToApply.begin(), fixesToApply.end(),
835 return a.location().offset < b.location().offset;
838 const auto dupes = std::unique(fixesToApply.begin(), fixesToApply.end());
839 fixesToApply.erase(dupes, fixesToApply.end());
841 for (
auto it = fixesToApply.
begin();
it + 1 != fixesToApply.
end();
it++) {
844 if (srcLocA.offset + srcLocA.length > srcLocB.offset) {
846 qWarning() <<
"Fixes for two warnings are overlapping, aborting. Please file a bug "
852 int offsetChange = 0;
854 for (
const auto &fix : fixesToApply) {
858 const QString after = code.
mid(cutLocation + fixLocation.length);
860 const QString replacement = fix.replacement();
861 code = before + replacement + after;
862 offsetChange += replacement.
size() - fixLocation.length;
868 lexer.
setCode(code, 1, !isJavaScript);
869 QQmlJS::Parser parser(&
engine);
871 bool success = parser.parse();
874 const auto diagnosticMessages = parser.diagnosticMessages();
877 qDebug() <<
"File became unparseable after suggestions were applied. Please file a bug "
886 .arg(
m.loc.startLine)
887 .arg(
m.loc.startColumn)
void reportVarUsedBeforeDeclaration(const QString &name, const QString &fileName, QQmlJS::SourceLocation declarationLocation, QQmlJS::SourceLocation accessLocation) override
CodegenWarningInterface(QQmlJSLogger *logger)
The QDirIterator class provides an iterator for directory entrylists.
static QChar separator()
Returns the native directory separator: "/" under Unix and "\\" under Windows.
FileError error() const
Returns the file error status.
void close() override
Calls QFileDevice::flush() and closes the file.
QString absoluteFilePath() const
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
QByteArray readAll()
Reads all remaining data from the device, and returns it as a byte array.
QString errorString() const
Returns a human-readable description of the last device error that occurred.
\inmodule QtCore\reentrant
void insert(qsizetype i, const QJsonValue &value)
Inserts value at index position i in the array.
void append(const QJsonValue &value)
Inserts value at the end of the array.
\inmodule QtCore\reentrant
\inmodule QtCore\reentrant
static QString path(LibraryPath p)
static bool isLibrary(const QString &fileName)
Returns true if fileName has a valid suffix for a loadable library; otherwise returns false.
static void setFilterRules(const QString &rules)
Configures which categories and message types should be enabled through a set of rules.
static QList< QStaticPlugin > staticPlugins()
Returns a list of QStaticPlugins held by the plugin loader.
static QString implicitImportDirectory(const QString &localFile, QQmlJSResourceFileMapper *mapper)
QStringList importPaths() const
QList< QQmlJS::DiagnosticMessage > takeWarnings()
void setImportPaths(const QStringList &importPaths)
QList< QQmlJS::DiagnosticMessage > takeGlobalWarnings()
void setResourceFileMapper(QQmlJSResourceFileMapper *mapper)
ImportedTypes importModule(const QString &module, const QString &prefix=QString(), QTypeRevision version=QTypeRevision(), QStringList *staticModuleList=nullptr)
FixResult applyFixes(QString *fixedCode, bool silent)
static std::vector< Plugin > loadPlugins(QStringList paths)
const QQmlJSLogger * logger() const
QQmlJSLinter(const QStringList &importPaths, const QStringList &pluginPaths={ QQmlJSLinter::defaultPluginPath() }, bool useAbsolutePath=false)
std::vector< Plugin > & plugins()
static QString defaultPluginPath()
LintResult lintModule(const QString &uri, const bool silent, QJsonArray *json, const QStringList &qmlImportPaths, const QStringList &resourceFiles)
LintResult lintFile(const QString &filename, const QString *fileContents, const bool silent, QJsonArray *json, const QStringList &qmlImportPaths, const QStringList &qmldirFiles, const QStringList &resourceFiles, const QList< QQmlJS::LoggerCategory > &categories)
void processMessages(const QList< QQmlJS::DiagnosticMessage > &messages, const QQmlJS::LoggerWarningId id)
void setCode(const QString &code)
QList< QQmlJS::LoggerCategory > categories() const
void setSilent(bool silent)
void setFileName(const QString &fileName)
const QList< Message > & warnings() const
void setCategoryIgnored(QQmlJS::LoggerWarningId id, bool error)
void setCategoryLevel(QQmlJS::LoggerWarningId id, QtMsgType level)
const QList< Message > & errors() const
void log(const QString &message, QQmlJS::LoggerWarningId id, const QQmlJS::SourceLocation &srcLocation, bool showContext=true, bool showFileName=true, const std::optional< QQmlJSFixSuggestion > &suggestion={}, const QString overrideFileName=QString())
void registerCategory(const QQmlJS::LoggerCategory &category)
void ignoreWarnings(uint32_t line, const QSet< QString > &categories)
const QList< Message > & infos() const
static QQmlJSScope::Ptr create()
QString internalName() const
static QQmlSA::Element createQQmlSAElement(const ConstPtr &)
bool isFullyResolved() const
QQmlJSScope::ConstPtr attachedType() const
QHash< QString, QQmlJSMetaProperty > ownProperties() const
QQmlJS::SourceLocation sourceLocation() const
QMultiHash< QString, QQmlJSMetaMethod > ownMethods() const
void setParentMode(ParentMode mode)
void init(QQmlJSImportVisitor *visitor, QQmlJS::AST::Node *program)
void setCloneMode(CloneMode mode)
void setCode(const QString &code, int lineno, bool qmlMode=true, CodeContinuation codeContinuation=CodeContinuation::Reset)
static LoggerCategoryPrivate * get(LoggerCategory *)
virtual void registerPasses(PassManager *manager, const Element &rootElement)=0
Adds a pass manager that will be executed on rootElement.
QAnyStringView name() const
static void deletePassManager(PassManager *q)
static PassManager * createPassManager(QQmlJSImportVisitor *visitor, QQmlJSTypeResolver *resolver)
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
const_iterator cend() const noexcept
iterator find(const T &value)
const_iterator cbegin() const noexcept
\macro QT_RESTRICTED_CAST_FROM_ASCII
QString left(qsizetype n) const &
qsizetype indexOf(QLatin1StringView s, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QStringList split(const QString &sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Splits the string into substrings wherever sep occurs, and returns the list of those strings.
QString mid(qsizetype position, qsizetype n=-1) const &
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
qsizetype size() const noexcept
Returns the number of characters in this string.
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
QString & insert(qsizetype i, QChar c)
const QLoggingCategory & category()
[1]
QSet< QString >::iterator it
Combined button and popup list for selecting options.
QList< QString > QStringList
Constructs a string list that contains the given string, str.
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 * interface
DBusConnection const char DBusError * error
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 * method
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
static bool contains(const QJsonArray &haystack, unsigned needle)
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLsizei GLenum GLenum * types
GLsizei const GLuint * paths
GLuint GLsizei const GLchar * message
GLsizei GLsizei GLchar * source
GLsizei GLenum * categories
GLsizei const GLchar *const * path
bool qCompileQmlFile(const QString &inputFileName, QQmlJSSaveFunction saveFunction, QQmlJSAotCompiler *aotCompiler, QQmlJSCompileError *error, bool storeSourceLocation, QV4::Compiler::CodegenWarningInterface *interface, const QString *fileContents)
std::function< bool(const QV4::CompiledData::SaveableUnitPointer &, const QQmlJSAotFunctionMap &, QString *)> QQmlJSSaveFunction
static void addJsonWarning(QJsonArray &warnings, const QQmlJS::DiagnosticMessage &message, QAnyStringView id, const std::optional< QQmlJSFixSuggestion > &suggestion={})
const QQmlSA::LoggerWarningId qmlVarUsedBeforeDeclaration
const QQmlSA::LoggerWarningId qmlInvalidLintDirective
const QQmlSA::LoggerWarningId qmlUnresolvedType
const QQmlSA::LoggerWarningId qmlImport
const QQmlSA::LoggerWarningId qmlSyntax
#define QmlLintPluginInterface_iid
QDebug warning(QAnyStringView fileName, int lineNumber)
QLatin1StringView QLatin1String
#define QStringLiteral(str)
static QT_BEGIN_NAMESPACE QVariant hint(QPlatformIntegration::StyleHint h)
char * toString(const MyType &t)
[31]
static Filter localFileFilter(const QString &file)