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 QQMLDOMCOMMENTS_P_H
5#define QQMLDOMCOMMENTS_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
18#include "qqmldom_fwd_p.h"
19#include "qqmldomconstants_p.h"
20#include "qqmldomfunctionref_p.h"
21#include "qqmldomitem_p.h"
22#include "qqmldomattachedinfo_p.h"
23
24#include <QtQml/private/qqmljsast_p.h>
25#include <QtQml/private/qqmljsengine_p.h>
26
27#include <QtCore/QMultiMap>
28#include <QtCore/QHash>
29#include <QtCore/QStack>
30#include <QtCore/QCoreApplication>
31
32#include <memory>
33
34QT_BEGIN_NAMESPACE
35namespace QQmlJS {
36namespace Dom {
37
38class QMLDOM_EXPORT CommentInfo
39{
40 Q_DECLARE_TR_FUNCTIONS(CommentInfo)
41public:
42 CommentInfo(QStringView);
43
44 QStringView preWhitespace() const { return rawComment.mid(pos: 0, n: commentBegin); }
45
46 QStringView comment() const { return rawComment.mid(pos: commentBegin, n: commentEnd - commentBegin); }
47
48 QStringView commentContent() const
49 {
50 return rawComment.mid(pos: commentContentBegin, n: commentContentEnd - commentContentEnd);
51 }
52
53 QStringView postWhitespace() const
54 {
55 return rawComment.mid(pos: commentEnd, n: rawComment.size() - commentEnd);
56 }
57
58 quint32 commentBegin;
59 quint32 commentEnd;
60 quint32 commentContentBegin;
61 quint32 commentContentEnd;
62 QStringView commentStartStr;
63 QStringView commentEndStr;
64 bool hasStartNewline = false;
65 bool hasEndNewline = false;
66 int nContentNewlines;
67 QStringView rawComment;
68 QStringList warnings;
69};
70
71class QMLDOM_EXPORT Comment
72{
73public:
74 constexpr static DomType kindValue = DomType::Comment;
75 DomType kind() const { return kindValue; }
76
77 Comment(QString c, int newlinesBefore = 1)
78 : m_commentStr(c), m_comment(m_commentStr), m_newlinesBefore(newlinesBefore)
79 {
80 }
81 Comment(QStringView c, int newlinesBefore = 1) : m_comment(c), m_newlinesBefore(newlinesBefore)
82 {
83 }
84
85 bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor);
86 int newlinesBefore() const { return m_newlinesBefore; }
87 void setNewlinesBefore(int n) { m_newlinesBefore = n; }
88 QStringView rawComment() const { return m_comment; }
89 CommentInfo info() const { return CommentInfo(m_comment); }
90 void write(OutWriter &lw, SourceLocation *commentLocation = nullptr) const;
91
92 friend bool operator==(const Comment &c1, const Comment &c2)
93 {
94 return c1.m_newlinesBefore == c2.m_newlinesBefore && c1.m_comment == c2.m_comment;
95 }
96 friend bool operator!=(const Comment &c1, const Comment &c2) { return !(c1 == c2); }
97
98private:
99 QString m_commentStr;
100 QStringView m_comment;
101 int m_newlinesBefore;
102};
103
104class QMLDOM_EXPORT CommentedElement
105{
106public:
107 constexpr static DomType kindValue = DomType::CommentedElement;
108 DomType kind() const { return kindValue; }
109
110 bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor);
111 void writePre(OutWriter &lw, QList<SourceLocation> *locations = nullptr) const;
112 void writePost(OutWriter &lw, QList<SourceLocation> *locations = nullptr) const;
113 QMultiMap<quint32, const QList<Comment> *> commentGroups(SourceLocation elLocation) const;
114
115 friend bool operator==(const CommentedElement &c1, const CommentedElement &c2)
116 {
117 return c1.preComments == c2.preComments && c1.postComments == c2.postComments;
118 }
119 friend bool operator!=(const CommentedElement &c1, const CommentedElement &c2)
120 {
121 return !(c1 == c2);
122 }
123
124 QList<Comment> preComments;
125 QList<Comment> postComments;
126};
127
128class QMLDOM_EXPORT RegionComments
129{
130public:
131 constexpr static DomType kindValue = DomType::RegionComments;
132 DomType kind() const { return kindValue; }
133
134 bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor);
135
136 friend bool operator==(const RegionComments &c1, const RegionComments &c2)
137 {
138 return c1.regionComments == c2.regionComments;
139 }
140 friend bool operator!=(const RegionComments &c1, const RegionComments &c2)
141 {
142 return !(c1 == c2);
143 }
144
145 Path addPreComment(const Comment &comment, QString regionName)
146 {
147 auto &preList = regionComments[regionName].preComments;
148 index_type idx = preList.size();
149 preList.append(t: comment);
150 return Path::Field(s: Fields::regionComments)
151 .key(name: regionName)
152 .field(name: Fields::preComments)
153 .index(i: idx);
154 }
155
156 Path addPostComment(const Comment &comment, QString regionName)
157 {
158 auto &postList = regionComments[regionName].postComments;
159 index_type idx = postList.size();
160 postList.append(t: comment);
161 return Path::Field(s: Fields::regionComments)
162 .key(name: regionName)
163 .field(name: Fields::postComments)
164 .index(i: idx);
165 }
166
167 QMap<QString, CommentedElement> regionComments;
168};
169
170class QMLDOM_EXPORT AstComments final : public OwningItem
171{
172protected:
173 std::shared_ptr<OwningItem> doCopy(DomItem &) const override
174 {
175 return std::make_shared<AstComments>(args: *this);
176 }
177
178public:
179 constexpr static DomType kindValue = DomType::AstComments;
180 DomType kind() const override { return kindValue; }
181 bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
182 std::shared_ptr<AstComments> makeCopy(DomItem &self) const
183 {
184 return std::static_pointer_cast<AstComments>(r: doCopy(self));
185 }
186
187 Path canonicalPath(DomItem &self) const override { return self.m_ownerPath; }
188 static void collectComments(MutableDomItem &item);
189 static void collectComments(std::shared_ptr<Engine> engine, AST::Node *n,
190 std::shared_ptr<AstComments> collectComments,
191 MutableDomItem rootItem, FileLocations::Tree rootItemLocations);
192 AstComments(std::shared_ptr<Engine> e) : m_engine(e) { }
193 AstComments(const AstComments &o)
194 : OwningItem(o), m_engine(o.m_engine), m_commentedElements(o.m_commentedElements)
195 {
196 }
197
198 const QHash<AST::Node *, CommentedElement> &commentedElements() const
199 {
200 return m_commentedElements;
201 }
202 CommentedElement *commentForNode(AST::Node *n)
203 {
204 if (m_commentedElements.contains(key: n))
205 return &(m_commentedElements[n]);
206 return nullptr;
207 }
208 QMultiMap<quint32, const QList<Comment> *> allCommentsInNode(AST::Node *n);
209
210private:
211 std::shared_ptr<Engine> m_engine;
212 QHash<AST::Node *, CommentedElement> m_commentedElements;
213};
214
215class VisitAll : public AST::Visitor
216{
217public:
218 VisitAll() = default;
219
220 static QSet<int> uiKinds();
221
222 void throwRecursionDepthError() override { }
223
224 bool visit(AST::UiPublicMember *el) override
225 {
226 AST::Node::accept(node: el->annotations, visitor: this);
227 AST::Node::accept(node: el->memberType, visitor: this);
228 return true;
229 }
230
231 bool visit(AST::UiSourceElement *el) override
232 {
233 AST::Node::accept(node: el->annotations, visitor: this);
234 return true;
235 }
236
237 bool visit(AST::UiObjectDefinition *el) override
238 {
239 AST::Node::accept(node: el->annotations, visitor: this);
240 return true;
241 }
242
243 bool visit(AST::UiObjectBinding *el) override
244 {
245 AST::Node::accept(node: el->annotations, visitor: this);
246 return true;
247 }
248
249 bool visit(AST::UiScriptBinding *el) override
250 {
251 AST::Node::accept(node: el->annotations, visitor: this);
252 return true;
253 }
254
255 bool visit(AST::UiArrayBinding *el) override
256 {
257 AST::Node::accept(node: el->annotations, visitor: this);
258 return true;
259 }
260
261 bool visit(AST::UiParameterList *el) override
262 {
263 AST::Node::accept(node: el->type, visitor: this);
264 return true;
265 }
266
267 bool visit(AST::UiQualifiedId *el) override
268 {
269 AST::Node::accept(node: el->next, visitor: this);
270 return true;
271 }
272
273 bool visit(AST::UiEnumDeclaration *el) override
274 {
275 AST::Node::accept(node: el->annotations, visitor: this);
276 return true;
277 }
278
279 bool visit(AST::UiInlineComponent *el) override
280 {
281 AST::Node::accept(node: el->annotations, visitor: this);
282 return true;
283 }
284
285 void endVisit(AST::UiImport *el) override { AST::Node::accept(node: el->version, visitor: this); }
286 void endVisit(AST::UiPublicMember *el) override { AST::Node::accept(node: el->parameters, visitor: this); }
287
288 void endVisit(AST::UiParameterList *el) override
289 {
290 AST::Node::accept(node: el->next, visitor: this); // put other args at the same level as this one...
291 }
292
293 void endVisit(AST::UiEnumMemberList *el) override
294 {
295 AST::Node::accept(node: el->next,
296 visitor: this); // put other enum members at the same level as this one...
297 }
298
299 bool visit(AST::TemplateLiteral *el) override
300 {
301 AST::Node::accept(node: el->expression, visitor: this);
302 return true;
303 }
304
305 void endVisit(AST::Elision *el) override
306 {
307 AST::Node::accept(node: el->next, visitor: this); // emit other elisions at the same level
308 }
309};
310} // namespace Dom
311} // namespace QQmlJS
312QT_END_NAMESPACE
313
314#endif // QQMLDOMCOMMENTS_P_H
315

source code of qtdeclarative/src/qmldom/qqmldomcomments_p.h