1 | // Copyright (C) 2021 The Qt Company Ltd. |
---|---|
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
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 "qqmldomitem_p.h" |
21 | #include "qqmldomattachedinfo_p.h" |
22 | |
23 | #include <QtQml/private/qqmljsast_p.h> |
24 | #include <QtQml/private/qqmljsengine_p.h> |
25 | |
26 | #include <QtCore/QMultiMap> |
27 | #include <QtCore/QHash> |
28 | #include <QtCore/QStack> |
29 | #include <QtCore/QCoreApplication> |
30 | |
31 | #include <memory> |
32 | |
33 | QT_BEGIN_NAMESPACE |
34 | namespace QQmlJS { |
35 | namespace Dom { |
36 | |
37 | class QMLDOM_EXPORT CommentInfo |
38 | { |
39 | Q_DECLARE_TR_FUNCTIONS(CommentInfo) |
40 | public: |
41 | CommentInfo(QStringView, QQmlJS::SourceLocation loc); |
42 | |
43 | QStringView preWhitespace() const { return rawComment.mid(pos: 0, n: commentBegin); } |
44 | |
45 | QStringView comment() const { return rawComment.mid(pos: commentBegin, n: commentEnd - commentBegin); } |
46 | |
47 | QStringView commentContent() const |
48 | { |
49 | return rawComment.mid(pos: commentContentBegin, n: commentContentEnd - commentContentEnd); |
50 | } |
51 | |
52 | QStringView postWhitespace() const |
53 | { |
54 | return rawComment.mid(pos: commentEnd, n: rawComment.size() - commentEnd); |
55 | } |
56 | |
57 | // Comment source location populated during lexing doesn't include start strings // or /* |
58 | // Returns the location starting from // or /* |
59 | QQmlJS::SourceLocation sourceLocation() const { return commentLocation; } |
60 | |
61 | quint32 commentBegin = 0; |
62 | quint32 commentEnd = 0; |
63 | quint32 commentContentBegin = 0; |
64 | quint32 commentContentEnd = 0; |
65 | QStringView commentStartStr; |
66 | QStringView commentEndStr; |
67 | bool hasStartNewline = false; |
68 | bool hasEndNewline = false; |
69 | int nContentNewlines = 0; |
70 | QStringView rawComment; |
71 | QStringList warnings; |
72 | QQmlJS::SourceLocation commentLocation; |
73 | }; |
74 | |
75 | class QMLDOM_EXPORT Comment |
76 | { |
77 | public: |
78 | constexpr static DomType kindValue = DomType::Comment; |
79 | DomType kind() const { return kindValue; } |
80 | |
81 | enum CommentType {Pre, Post}; |
82 | |
83 | Comment(const QString &c, const QQmlJS::SourceLocation &loc, int newlinesBefore = 1, |
84 | CommentType type = Pre) |
85 | : m_comment(c), m_location(loc), m_newlinesBefore(newlinesBefore), m_type(type) |
86 | { |
87 | } |
88 | Comment(QStringView c, const QQmlJS::SourceLocation &loc, int newlinesBefore = 1, |
89 | CommentType type = Pre) |
90 | : m_comment(c), m_location(loc), m_newlinesBefore(newlinesBefore), m_type(type) |
91 | { |
92 | } |
93 | |
94 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const; |
95 | int newlinesBefore() const { return m_newlinesBefore; } |
96 | void setNewlinesBefore(int n) { m_newlinesBefore = n; } |
97 | QStringView rawComment() const { return m_comment; } |
98 | CommentInfo info() const { return CommentInfo(m_comment, m_location); } |
99 | void write(OutWriter &lw, SourceLocation *commentLocation = nullptr) const; |
100 | |
101 | CommentType type() const { return m_type; } |
102 | |
103 | friend bool operator==(const Comment &c1, const Comment &c2) |
104 | { |
105 | return c1.m_newlinesBefore == c2.m_newlinesBefore && c1.m_comment == c2.m_comment; |
106 | } |
107 | friend bool operator!=(const Comment &c1, const Comment &c2) { return !(c1 == c2); } |
108 | |
109 | private: |
110 | QStringView m_comment; |
111 | QQmlJS::SourceLocation m_location; |
112 | int m_newlinesBefore; |
113 | CommentType m_type; |
114 | }; |
115 | |
116 | class QMLDOM_EXPORT CommentedElement |
117 | { |
118 | public: |
119 | constexpr static DomType kindValue = DomType::CommentedElement; |
120 | DomType kind() const { return kindValue; } |
121 | |
122 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const; |
123 | void writePre(OutWriter &lw, QList<SourceLocation> *locations = nullptr) const; |
124 | void writePost(OutWriter &lw, QList<SourceLocation> *locations = nullptr) const; |
125 | |
126 | friend bool operator==(const CommentedElement &c1, const CommentedElement &c2) |
127 | { |
128 | return c1.m_preComments == c2.m_preComments && c1.m_postComments == c2.m_postComments; |
129 | } |
130 | friend bool operator!=(const CommentedElement &c1, const CommentedElement &c2) |
131 | { |
132 | return !(c1 == c2); |
133 | } |
134 | |
135 | void addComment(const Comment &comment) |
136 | { |
137 | if (comment.type() == Comment::CommentType::Pre) |
138 | m_preComments.append(t: comment); |
139 | else |
140 | m_postComments.append(t: comment); |
141 | } |
142 | |
143 | const QList<Comment> &preComments() const { return m_preComments;} |
144 | const QList<Comment> &postComments() const { return m_postComments;} |
145 | |
146 | private: |
147 | QList<Comment> m_preComments; |
148 | QList<Comment> m_postComments; |
149 | }; |
150 | |
151 | class QMLDOM_EXPORT RegionComments |
152 | { |
153 | public: |
154 | constexpr static DomType kindValue = DomType::RegionComments; |
155 | DomType kind() const { return kindValue; } |
156 | |
157 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const; |
158 | |
159 | friend bool operator==(const RegionComments &c1, const RegionComments &c2) |
160 | { |
161 | return c1.m_regionComments == c2.m_regionComments; |
162 | } |
163 | friend bool operator!=(const RegionComments &c1, const RegionComments &c2) |
164 | { |
165 | return !(c1 == c2); |
166 | } |
167 | |
168 | const QMap<FileLocationRegion, CommentedElement> ®ionComments() const { return m_regionComments;} |
169 | Path addComment(const Comment &comment, FileLocationRegion region) |
170 | { |
171 | if (comment.type() == Comment::CommentType::Pre) |
172 | return addPreComment(comment, region); |
173 | else |
174 | return addPostComment(comment, region); |
175 | } |
176 | |
177 | private: |
178 | Path addPreComment(const Comment &comment, FileLocationRegion region) |
179 | { |
180 | auto &preList = m_regionComments[region].preComments(); |
181 | index_type idx = preList.size(); |
182 | m_regionComments[region].addComment(comment); |
183 | return Path::Field(s: Fields::regionComments) |
184 | .key(name: fileLocationRegionName(region)) |
185 | .field(name: Fields::preComments) |
186 | .index(i: idx); |
187 | } |
188 | |
189 | Path addPostComment(const Comment &comment, FileLocationRegion region) |
190 | { |
191 | auto &postList = m_regionComments[region].postComments(); |
192 | index_type idx = postList.size(); |
193 | m_regionComments[region].addComment(comment); |
194 | return Path::Field(s: Fields::regionComments) |
195 | .key(name: fileLocationRegionName(region)) |
196 | .field(name: Fields::postComments) |
197 | .index(i: idx); |
198 | } |
199 | |
200 | QMap<FileLocationRegion, CommentedElement> m_regionComments; |
201 | }; |
202 | |
203 | class QMLDOM_EXPORT AstComments final : public OwningItem |
204 | { |
205 | protected: |
206 | std::shared_ptr<OwningItem> doCopy(const DomItem &) const override |
207 | { |
208 | return std::make_shared<AstComments>(args: *this); |
209 | } |
210 | |
211 | public: |
212 | constexpr static DomType kindValue = DomType::AstComments; |
213 | DomType kind() const override { return kindValue; } |
214 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override; |
215 | std::shared_ptr<AstComments> makeCopy(const DomItem &self) const |
216 | { |
217 | return std::static_pointer_cast<AstComments>(r: doCopy(self)); |
218 | } |
219 | |
220 | Path canonicalPath(const DomItem &self) const override { return self.m_ownerPath; } |
221 | AstComments(const std::shared_ptr<Engine> &e) : m_engine(e) { } |
222 | AstComments(const AstComments &o) |
223 | : OwningItem(o), m_engine(o.m_engine), m_commentedElements(o.m_commentedElements) |
224 | { |
225 | } |
226 | |
227 | const QHash<AST::Node *, CommentedElement> &commentedElements() const |
228 | { |
229 | return m_commentedElements; |
230 | } |
231 | |
232 | QHash<AST::Node *, CommentedElement> &commentedElements() |
233 | { |
234 | return m_commentedElements; |
235 | } |
236 | |
237 | CommentedElement *commentForNode(AST::Node *n) |
238 | { |
239 | if (m_commentedElements.contains(key: n)) |
240 | return &(m_commentedElements[n]); |
241 | return nullptr; |
242 | } |
243 | QMultiMap<quint32, const QList<Comment> *> allCommentsInNode(AST::Node *n); |
244 | |
245 | private: |
246 | std::shared_ptr<Engine> m_engine; |
247 | QHash<AST::Node *, CommentedElement> m_commentedElements; |
248 | }; |
249 | |
250 | class CommentCollector |
251 | { |
252 | public: |
253 | CommentCollector() = default; |
254 | CommentCollector(MutableDomItem item); |
255 | void collectComments(); |
256 | void collectComments(const std::shared_ptr<Engine> &engine, AST::Node *rootNode, |
257 | const std::shared_ptr<AstComments> &astComments); |
258 | |
259 | private: |
260 | MutableDomItem m_rootItem; |
261 | FileLocations::Tree m_fileLocations; |
262 | }; |
263 | |
264 | class VisitAll : public AST::Visitor |
265 | { |
266 | public: |
267 | VisitAll() = default; |
268 | |
269 | static QSet<int> uiKinds(); |
270 | |
271 | void throwRecursionDepthError() override { } |
272 | |
273 | bool visit(AST::UiPublicMember *el) override |
274 | { |
275 | AST::Node::accept(node: el->annotations, visitor: this); |
276 | AST::Node::accept(node: el->memberType, visitor: this); |
277 | return true; |
278 | } |
279 | |
280 | bool visit(AST::UiSourceElement *el) override |
281 | { |
282 | AST::Node::accept(node: el->annotations, visitor: this); |
283 | return true; |
284 | } |
285 | |
286 | bool visit(AST::UiObjectDefinition *el) override |
287 | { |
288 | AST::Node::accept(node: el->annotations, visitor: this); |
289 | return true; |
290 | } |
291 | |
292 | bool visit(AST::UiObjectBinding *el) override |
293 | { |
294 | AST::Node::accept(node: el->annotations, visitor: this); |
295 | return true; |
296 | } |
297 | |
298 | bool visit(AST::UiScriptBinding *el) override |
299 | { |
300 | AST::Node::accept(node: el->annotations, visitor: this); |
301 | return true; |
302 | } |
303 | |
304 | bool visit(AST::UiArrayBinding *el) override |
305 | { |
306 | AST::Node::accept(node: el->annotations, visitor: this); |
307 | return true; |
308 | } |
309 | |
310 | bool visit(AST::UiParameterList *el) override |
311 | { |
312 | AST::Node::accept(node: el->type, visitor: this); |
313 | return true; |
314 | } |
315 | |
316 | bool visit(AST::UiQualifiedId *el) override |
317 | { |
318 | AST::Node::accept(node: el->next, visitor: this); |
319 | return true; |
320 | } |
321 | |
322 | bool visit(AST::UiEnumDeclaration *el) override |
323 | { |
324 | AST::Node::accept(node: el->annotations, visitor: this); |
325 | return true; |
326 | } |
327 | |
328 | bool visit(AST::UiInlineComponent *el) override |
329 | { |
330 | AST::Node::accept(node: el->annotations, visitor: this); |
331 | return true; |
332 | } |
333 | |
334 | void endVisit(AST::UiImport *el) override { AST::Node::accept(node: el->version, visitor: this); } |
335 | void endVisit(AST::UiPublicMember *el) override { AST::Node::accept(node: el->parameters, visitor: this); } |
336 | |
337 | void endVisit(AST::UiParameterList *el) override |
338 | { |
339 | AST::Node::accept(node: el->next, visitor: this); // put other args at the same level as this one... |
340 | } |
341 | |
342 | void endVisit(AST::UiEnumMemberList *el) override |
343 | { |
344 | AST::Node::accept(node: el->next, |
345 | visitor: this); // put other enum members at the same level as this one... |
346 | } |
347 | |
348 | bool visit(AST::TemplateLiteral *el) override |
349 | { |
350 | AST::Node::accept(node: el->expression, visitor: this); |
351 | return true; |
352 | } |
353 | |
354 | void endVisit(AST::Elision *el) override |
355 | { |
356 | AST::Node::accept(node: el->next, visitor: this); // emit other elisions at the same level |
357 | } |
358 | }; |
359 | } // namespace Dom |
360 | } // namespace QQmlJS |
361 | QT_END_NAMESPACE |
362 | |
363 | #endif // QQMLDOMCOMMENTS_P_H |
364 |
Definitions
- CommentInfo
- preWhitespace
- comment
- commentContent
- postWhitespace
- sourceLocation
- Comment
- kindValue
- kind
- CommentType
- Comment
- Comment
- newlinesBefore
- setNewlinesBefore
- rawComment
- info
- type
- operator==
- operator!=
- CommentedElement
- kindValue
- kind
- operator==
- operator!=
- addComment
- preComments
- postComments
- RegionComments
- kindValue
- kind
- operator==
- operator!=
- regionComments
- addComment
- addPreComment
- addPostComment
- AstComments
- doCopy
- kindValue
- kind
- makeCopy
- canonicalPath
- AstComments
- AstComments
- commentedElements
- commentedElements
- commentForNode
- CommentCollector
- CommentCollector
- VisitAll
- VisitAll
- throwRecursionDepthError
- visit
- visit
- visit
- visit
- visit
- visit
- visit
- visit
- visit
- visit
- endVisit
- endVisit
- endVisit
- endVisit
- visit
Start learning QML with our Intro Training
Find out more