Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmljslintervisitor_p.h
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3// Qt-Security score:significant
4
5#ifndef QQMLJSLINTERVISITOR_P_H
6#define QQMLJSLINTERVISITOR_P_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17
18#include <private/qqmljsimportvisitor_p.h>
19#include <private/qqmljslinterrenamedcomponents_p.h>
20#include <private/qqmljslintercontext_p.h>
21
22#include <private/qqmljsengine_p.h>
23
24#include <QtCore/qtyperevision.h>
25
26QT_BEGIN_NAMESPACE
27
28namespace QQmlJS {
29
30/*!
31 \internal
32 Extends QQmlJSImportVisitor with extra warnings that are required for linting but unrelated to
33 QQmlJSImportVisitor actual task that is constructing QQmlJSScopes. One example of such warnings
34 are purely syntactic checks, or warnings that don't affect compilation.
35 */
36class LinterVisitor final : public QQmlJSImportVisitor
37{
38public:
39 LinterVisitor(QQmlJSImporter *importer, QQmlJSLogger *logger,
40 const QString &implicitImportDirectory,
41 const QStringList &qmldirFiles = QStringList(), QQmlJS::Engine *engine = nullptr);
42
43 const QQmlJS::LinterRenamedComponents &renamedComponents() const { return m_renamedComponents; }
44
45protected:
46 using QQmlJSImportVisitor::endVisit;
47 using QQmlJSImportVisitor::visit;
48
49 bool preVisit(QQmlJS::AST::Node *) override;
50 void postVisit(QQmlJS::AST::Node *) override;
52
54
55 bool visit(QQmlJS::AST::StringLiteral *) override;
56 bool visit(AST::CommaExpression *) override;
57 bool visit(QQmlJS::AST::NewMemberExpression *) override;
58 bool visit(QQmlJS::AST::VoidExpression *ast) override;
59 bool visit(QQmlJS::AST::BinaryExpression *) override;
60 bool visit(QQmlJS::AST::UiImport *import) override;
61 bool visit(QQmlJS::AST::UiEnumDeclaration *uied) override;
62 bool visit(QQmlJS::AST::CaseBlock *) override;
63 bool visit(QQmlJS::AST::ExpressionStatement *ast) override;
64 bool visit(QQmlJS::AST::FunctionDeclaration *fdecl) override;
65 bool visit(QQmlJS::AST::FunctionExpression *fexpr) override;
66 bool visit(QQmlJS::AST::UiPublicMember *publicMember) override;
67 bool visit(QQmlJS::AST::UiObjectDefinition *objectDefinition) override;
68 bool visit(QQmlJS::AST::Type *typeAnnotation) override;
69 bool visit(QQmlJS::AST::UiPragma *pragma) override;
70
71 bool visit(QQmlJS::AST::IdentifierExpression *idexp) override;
72 void endVisit(QQmlJS::AST::FieldMemberExpression *fieldMember) override;
73
74 bool visit(QQmlJS::AST::UiProgram *ast) override;
75 void endVisit(QQmlJS::AST::UiProgram *ast) override;
76
77 bool safeInsertJSIdentifier(QQmlJSScope::Ptr &scope, const QString &name,
78 const QQmlJSScope::JavaScriptIdentifier &identifier) override;
79
80 void addImportWithLocation(const QString &name, const QQmlJS::SourceLocation &loc,
81 bool hadWarnings) override;
82 void addStaticImportWithLocation(const QString &name, const QQmlJS::SourceLocation &loc,
83 bool isDependency) override;
84
85 QSet<QString> *usedTypes() override { return &m_usedTypes; }
86
87private:
88 struct SeenImport
89 {
90 QStringView filename;
91 QString uri;
92 QTypeRevision version;
93 QStringView id;
94 QQmlJS::AST::UiImport *uiImport;
95
96 SeenImport(QQmlJS::AST::UiImport *i) : filename(i->fileName), id(i->importId), uiImport(i)
97 {
98 if (i->importUri)
99 uri = i->importUri->toString();
100 if (i->version)
101 version = i->version->version;
102 }
103 friend bool comparesEqual(const SeenImport &lhs, const SeenImport &rhs) noexcept
104 {
105 return lhs.filename == rhs.filename && lhs.uri == rhs.uri
106 && lhs.version == rhs.version && lhs.id == rhs.id;
107 }
108 Q_DECLARE_EQUALITY_COMPARABLE(SeenImport)
109
110 friend size_t qHash(const SeenImport &i, size_t seed = 0)
111 {
112 return qHashMulti(seed, i.filename, i.uri, i.version, i.id);
113 }
114 };
115 QQmlJS::Engine *m_engine = nullptr;
116 QSet<SeenImport> m_seenImports;
117 std::vector<QQmlJS::AST::Node *> m_ancestryIncludingCurrentNode;
118 QQmlJS::LinterRenamedComponents m_renamedComponents;
119
120 // Maps all qmlNames to the source location of their import
121 QMultiHash<QString, QQmlJS::SourceLocation> m_importTypeLocationMap;
122 // Maps all static modules to the source location of their import
123 QMultiHash<QString, QQmlJS::SourceLocation> m_importStaticModuleLocationMap;
124 // Contains all import source locations (could be extracted from above but that is expensive)
125 QSet<QQmlJS::SourceLocation> m_importLocations;
126 // A set of all types that have been used during type resolution
127 QSet<QString> m_usedTypes;
128
129 struct HandlerLikeProperty
130 {
131 QQmlJSScope::ConstPtr scope;
132 QString name;
133 QQmlJS::SourceLocation location;
134 };
135 // Properties whose names could be mistaken for signal handler names. Checked once the
136 // document is fully parsed, since the clashing member may be declared further down.
137 QList<HandlerLikeProperty> m_handlerLikeProperties;
138
139 void handleDuplicateEnums(QQmlJS::AST::UiEnumMemberList *members, QStringView key,
140 const QQmlJS::SourceLocation &location);
141 void warnCaseNoFlowControl(QQmlJS::SourceLocation caseToken) const;
142 void checkCaseFallthrough(QQmlJS::AST::StatementList *statements, SourceLocation errorLoc,
143 SourceLocation nextLoc);
145 const QString &name, const QQmlJS::AST::Statement *statement,
146 const QQmlJS::AST::UiPublicMember *associatedPropertyDefinition = nullptr) override;
147 void handleLiteralBinding(const QQmlJSMetaPropertyBinding &binding,
148 const AST::UiPublicMember *associatedPropertyDefinition) override;
149 void handleUselessExpressionStatement(const AST::ExpressionStatement *ast);
150 void handleRecursivelyInstantiatedType(AST::UiQualifiedId *qualifiedId);
151 void handleRenamedType(QQmlJS::AST::UiQualifiedId *id);
152 void checkSingletonRoot();
153 void checkFileSelections();
154 void checkUnusedImports();
155 void checkGroupedAndAttachedScope(const QQmlJSScope::ConstPtr &scope);
157 void checkSignalHandlerNameClashes();
158
159 bool m_rootIsSingleton = false;
160 bool m_hasMaybeUnresolvedTypes = false;
161};
162
163} // namespace QQmlJS
164
165QT_END_NAMESPACE
166
167#endif // QQMLJSLINTERVISITOR_P_H
void reportParserWarnings(const QString &, QQmlJS::SourceLocation, const QString &) override
void reportVarUsedBeforeDeclaration(const QString &name, const QString &fileName, QQmlJS::SourceLocation declarationLocation, QQmlJS::SourceLocation accessLocation) override
void reportFunctionUsedBeforeDeclaration(const QString &name, const QString &fileName, QQmlJS::SourceLocation declarationLocation, QQmlJS::SourceLocation accessLocation) override
UnreachableVisitor * unreachableVisitor() override
CodegenWarningInterface(QQmlJSLogger *logger)
void reportSyntaxWarnings(QSpan< const QQmlJS::DiagnosticMessage > warnings) override
bool visit(QQmlJS::AST::FunctionDeclaration *functionDeclaration) override
void throwRecursionDepthError() override
void setPassManager(QQmlSA::PassManager *passManager)
const QList< QQmlJS::LoggerCategory > categories() const
bool isInternal() const
Plugin(Plugin &&plugin) noexcept
Plugin(const QStaticPlugin &plugin)
const QString & name() const
const QString & version() const
const QString & author() const
void setEnabled(bool isEnabled)
const QString & description() const
void setPluginsEnabled(bool enablePlugins)
bool prepareFileForBatchLinting(const QString &filename, const QString *fileContents, LintOptions options, const QStringList &qmlImportPaths, const QStringList &qmldirFiles, const QStringList &resourceFiles, const QList< QQmlJS::LoggerCategory > &categories, qsizetype maxWarnings)
bool useAbsolutePath() const
Result lintModule(const QString &uri, LintOptions options, const QStringList &qmlImportPaths, const QStringList &resourceFiles, qsizetype maxWarnings)
Result lintFileInBatch(const QString &filename)
static std::vector< Plugin > loadPlugins(QStringList paths)
QQmlJSLinter(const QStringList &importPaths, const QStringList &extraPluginPaths={}, bool useAbsolutePath=false)
std::vector< Plugin > & plugins()
void setPlugins(std::vector< Plugin > plugins)
QQmlJSImporter m_importer
Q_DECLARE_FLAGS(LintOptions, LintOption)
static FixResult applyFixes(const QQmlJSLogger *logger, QString *fixedCode, bool silent)
bool pluginsEnabled() const
void postVisit(QQmlJS::AST::Node *) override
void checkGroupedAndAttachedScopes() override
QSet< QString > * usedTypes() override
void addStaticImportWithLocation(const QString &name, const QQmlJS::SourceLocation &loc, bool isDependency) override
void handleLiteralBinding(const QQmlJSMetaPropertyBinding &binding, const AST::UiPublicMember *associatedPropertyDefinition) override
LinterVisitor(QQmlJSImporter *importer, QQmlJSLogger *logger, const QString &implicitImportDirectory, const QStringList &qmldirFiles=QStringList(), QQmlJS::Engine *engine=nullptr)
const QQmlJS::LinterRenamedComponents & renamedComponents() const
BindingExpressionParseResult parseBindingExpression(const QString &name, const QQmlJS::AST::Statement *statement, const QQmlJS::AST::UiPublicMember *associatedPropertyDefinition=nullptr) override
void addImportWithLocation(const QString &name, const QQmlJS::SourceLocation &loc, bool hadWarnings) override
bool safeInsertJSIdentifier(QQmlJSScope::Ptr &scope, const QString &name, const QQmlJSScope::JavaScriptIdentifier &identifier) override
bool visit(QQmlJS::AST::StringLiteral *) override
QQmlJS::AST::Node * astParentOfVisitedNode() const
void endVisit(QQmlJS::AST::FieldMemberExpression *fieldMember) override
bool preVisit(QQmlJS::AST::Node *) override
UnreachableVisitor(QQmlJSLogger *logger)
void throwRecursionDepthError() override
bool containsFunctionDeclaration(QQmlJS::AST::Node *node)
bool visit(QQmlJS::AST::StatementList *unreachable) override
\inmodule QtQmlCompiler
Combined button and popup list for selecting options.
static void checkMaxWarnings(QQmlJSLogger *logger, qsizetype maxWarnings)
static void addJsonWarning(QJsonArray &warnings, const QQmlJS::DiagnosticMessage &message, QAnyStringView id, const std::optional< QQmlJSFixSuggestion > &suggestion={})
static void processMessages(const QQmlJSLogger &logger, QJsonArray &warnings)
std::unique_ptr< QQmlJSLogger > logger