1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2019 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the tools applications of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include "commentastvisitor.h" |
30 | |
31 | CommentAstVisitor::(QQmlJS::Engine *engine, Node *rootNode) : m_engine(engine) |
32 | { |
33 | rootNode->accept(visitor: this); |
34 | |
35 | // Look for complete orphans that have not been attached to *any* node |
36 | QVector<Comment> completeOrphans; |
37 | |
38 | for (const auto & : m_engine->comments()) { |
39 | if (isCommentAttached(location: comment)) |
40 | continue; |
41 | |
42 | bool found_orphan = false; |
43 | for (const auto &orphanList : orphanComments().values()) { |
44 | for (const auto &orphan : orphanList) { |
45 | if (orphan.contains(location: comment)) { |
46 | found_orphan = true; |
47 | break; |
48 | } |
49 | } |
50 | |
51 | if (found_orphan) |
52 | break; |
53 | } |
54 | |
55 | if (found_orphan) |
56 | continue; |
57 | |
58 | completeOrphans.append(t: Comment(m_engine, Comment::Location::Front, {comment})); |
59 | } |
60 | |
61 | m_orphanComments[nullptr] = completeOrphans; |
62 | } |
63 | |
64 | QList<SourceLocation> CommentAstVisitor::(quint32 line, bool includePrevious) const |
65 | { |
66 | QList<SourceLocation> results; |
67 | if (line == 0) |
68 | return results; |
69 | |
70 | for (const auto &location : m_engine->comments()) { |
71 | Comment (m_engine, Comment::Location::Front, { location }); |
72 | if (line < location.startLine || line > comment.endLine()) |
73 | continue; |
74 | |
75 | if (isCommentAttached(location)) |
76 | continue; |
77 | |
78 | results.append(t: location); |
79 | |
80 | if (includePrevious) { |
81 | // See if we can find any more comments above this one |
82 | auto previous = findCommentsInLine(line: location.startLine - 1, includePrevious: true); |
83 | |
84 | // Iterate it in reverse to restore the correct order |
85 | for (auto it = previous.rbegin(); it != previous.rend(); it++) { |
86 | results.prepend(t: *it); |
87 | } |
88 | } |
89 | |
90 | break; |
91 | } |
92 | |
93 | return results; |
94 | } |
95 | |
96 | bool CommentAstVisitor::(const SourceLocation &location) const |
97 | { |
98 | for (const auto &value : m_attachedComments.values()) { |
99 | if (value.contains(location)) |
100 | return true; |
101 | } |
102 | |
103 | for (const auto &value : m_listItemComments.values()) { |
104 | if (value.contains(location)) |
105 | return true; |
106 | } |
107 | |
108 | // If a comment is already marked as an orphan of a Node that counts as attached too. |
109 | for (const auto &orphanList : m_orphanComments.values()) { |
110 | for (const auto &value : orphanList) { |
111 | if (value.contains(location)) |
112 | return true; |
113 | } |
114 | } |
115 | |
116 | return false; |
117 | } |
118 | |
119 | Comment CommentAstVisitor::(SourceLocation first, SourceLocation last, |
120 | int locations) const |
121 | { |
122 | if (locations & Comment::Location::Front) { |
123 | quint32 searchAt = first.startLine - 1; |
124 | |
125 | const auto = findCommentsInLine(line: searchAt, includePrevious: true); |
126 | if (!comments.isEmpty()) |
127 | return Comment(m_engine, Comment::Location::Front, comments); |
128 | } |
129 | |
130 | if (locations & Comment::Location::Front_Inline) { |
131 | quint32 searchAt = first.startLine; |
132 | |
133 | const auto = findCommentsInLine(line: searchAt); |
134 | if (!comments.isEmpty()) |
135 | return Comment(m_engine, Comment::Location::Front_Inline, comments); |
136 | } |
137 | |
138 | if (locations & Comment::Location::Back_Inline) { |
139 | quint32 searchAt = last.startLine; |
140 | |
141 | const auto = findCommentsInLine(line: searchAt); |
142 | if (!comments.isEmpty()) |
143 | return Comment(m_engine, Comment::Location::Back_Inline, comments); |
144 | } |
145 | |
146 | if (locations & Comment::Location::Back) { |
147 | quint32 searchAt = last.startLine + 1; |
148 | |
149 | const auto = findCommentsInLine(line: searchAt); |
150 | if (!comments.isEmpty()) |
151 | return Comment(m_engine, Comment::Location::Back, comments); |
152 | } |
153 | |
154 | return Comment(); |
155 | |
156 | } |
157 | |
158 | Comment CommentAstVisitor::(Node *node, int locations) const |
159 | { |
160 | return findComment(first: node->firstSourceLocation(), last: node->lastSourceLocation(), locations); |
161 | } |
162 | |
163 | QVector<Comment> CommentAstVisitor::(Node *node) const |
164 | { |
165 | QVector<Comment> ; |
166 | |
167 | for (auto & : m_engine->comments()) { |
168 | if (isCommentAttached(location: comment)) |
169 | continue; |
170 | |
171 | if (comment.begin() <= node->firstSourceLocation().begin() |
172 | || comment.end() > node->lastSourceLocation().end()) { |
173 | continue; |
174 | } |
175 | |
176 | comments.append(t: Comment(m_engine, Comment::Location::Front, {comment})); |
177 | } |
178 | |
179 | return comments; |
180 | } |
181 | |
182 | void CommentAstVisitor::(Node *node, int locations) |
183 | { |
184 | auto = findComment(node, locations); |
185 | |
186 | if (comment.isValid()) |
187 | m_attachedComments[node] = comment; |
188 | } |
189 | |
190 | bool CommentAstVisitor::(UiScriptBinding *node) |
191 | { |
192 | attachComment(node); |
193 | return true; |
194 | } |
195 | |
196 | bool CommentAstVisitor::(StatementList *node) |
197 | { |
198 | for (auto *item = node; item != nullptr; item = item->next) |
199 | attachComment(node: item->statement, locations: Comment::Front | Comment::Back_Inline); |
200 | return true; |
201 | } |
202 | |
203 | void CommentAstVisitor::(StatementList *node) |
204 | { |
205 | m_orphanComments[node] = findOrphanComments(node); |
206 | } |
207 | |
208 | bool CommentAstVisitor::(UiObjectBinding *node) |
209 | { |
210 | attachComment(node, locations: Comment::Front | Comment::Front_Inline | Comment::Back); |
211 | return true; |
212 | } |
213 | |
214 | bool CommentAstVisitor::(UiObjectDefinition *node) |
215 | { |
216 | attachComment(node, locations: Comment::Front | Comment::Front_Inline | Comment::Back); |
217 | return true; |
218 | } |
219 | |
220 | void CommentAstVisitor::(UiObjectDefinition *node) |
221 | { |
222 | m_orphanComments[node] = findOrphanComments(node); |
223 | } |
224 | |
225 | bool CommentAstVisitor::(UiArrayBinding *node) |
226 | { |
227 | attachComment(node); |
228 | return true; |
229 | } |
230 | |
231 | void CommentAstVisitor::(UiArrayBinding *node) |
232 | { |
233 | m_orphanComments[node] = findOrphanComments(node); |
234 | } |
235 | |
236 | bool CommentAstVisitor::(UiEnumDeclaration *node) |
237 | { |
238 | attachComment(node); |
239 | return true; |
240 | } |
241 | |
242 | void CommentAstVisitor::(UiEnumDeclaration *node) |
243 | { |
244 | m_orphanComments[node] = findOrphanComments(node); |
245 | } |
246 | |
247 | bool CommentAstVisitor::(UiEnumMemberList *node) |
248 | { |
249 | for (auto *item = node; item != nullptr; item = item->next) { |
250 | auto = findComment(first: item->memberToken, |
251 | last: item->valueToken.isValid() ? item->valueToken : item->memberToken, |
252 | locations: Comment::Front | Comment::Back_Inline); |
253 | |
254 | if (comment.isValid()) |
255 | m_listItemComments[item->memberToken.begin()] = comment; |
256 | } |
257 | |
258 | m_orphanComments[node] = findOrphanComments(node); |
259 | |
260 | return true; |
261 | } |
262 | |
263 | bool CommentAstVisitor::(UiPublicMember *node) |
264 | { |
265 | attachComment(node); |
266 | return true; |
267 | } |
268 | |
269 | bool CommentAstVisitor::(FunctionDeclaration *node) |
270 | { |
271 | attachComment(node); |
272 | return true; |
273 | } |
274 | |
275 | bool CommentAstVisitor::(UiImport *node) |
276 | { |
277 | attachComment(node); |
278 | return true; |
279 | } |
280 | |
281 | bool CommentAstVisitor::(UiPragma *node) |
282 | { |
283 | attachComment(node); |
284 | return true; |
285 | } |
286 | |