Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqmldomoutwriter.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 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
7#include "qqmldomitem_p.h"
8#include "qqmldomcomments_p.h"
10#include "qqmldomtop_p.h"
11
12#include <QtCore/QLoggingCategory>
13
15namespace QQmlJS {
16namespace Dom {
17
19 const Path &itCanonicalPath, const DomItem &it, const FileLocations::Tree &fLoc)
20 : itemCanonicalPath(itCanonicalPath), item(it), currentMap(fLoc)
21{
22 DomItem cRegions = it.field(Fields::comments);
23 if (const RegionComments *cRegionsPtr = cRegions.as<RegionComments>())
24 pendingComments = cRegionsPtr->regionComments();
25}
26
28{
29 if (w.lineWriter.options().updateOptions & LineWriterOptions::Update::Locations)
30 w.lineWriter.endSourceLocation(fullRegionId);
31 if (!pendingRegions.isEmpty()) {
32 qCWarning(writeOutLog) << "PendingRegions non empty when closing item"
34 auto iend = pendingRegions.end();
35 auto it = pendingRegions.begin();
36 while (it == iend) {
37 w.lineWriter.endSourceLocation(it.value());
38 ++it;
39 }
40 }
41 if (!w.skipComments && !pendingComments.isEmpty())
42 qCWarning(writeOutLog) << "PendingComments when closing item "
43 << item.canonicalPath().toString() << "for regions"
44 << pendingComments.keys();
45}
46
48{
49 return states[states.size() - 1 - i];
50}
51
53{
54 if (!topLocation->path())
55 topLocation->setPath(it.canonicalPath());
58 Path itP = it.canonicalPath();
59 if (updateLocs) {
60 if (!states.isEmpty()
61 && states.last().itemCanonicalPath
62 == itP.mid(0, states.last().itemCanonicalPath.length())) {
63 int oldL = states.last().itemCanonicalPath.length();
64 newFLoc = FileLocations::ensure(states.last().currentMap,
65 itP.mid(oldL, itP.length() - oldL),
67
68 } else {
70 }
71 }
72 states.append(OutWriterState(itP, it, newFLoc));
73 if (updateLocs)
74 state().fullRegionId = lineWriter.startSourceLocation(
75 [newFLoc](SourceLocation l) { FileLocations::updateFullLocation(newFLoc, l); });
77}
78
80{
81 Q_ASSERT(states.size() > 0);
82 Q_ASSERT(state().item == it);
84 state().closeState(*this);
85 states.removeLast();
86}
87
89{
90 Q_ASSERT(!state().pendingRegions.contains(region));
91 FileLocations::Tree fMap = state().currentMap;
92 if (!skipComments && state().pendingComments.contains(region)) {
94 QList<SourceLocation> *cLocs =
95 (updateLocs ? &(fMap->info().preCommentLocations[region]) : nullptr);
96 state().pendingComments[region].writePre(*this, cLocs);
97 }
98 state().pendingRegions[region] = lineWriter.startSourceLocation(
99 [region, fMap](SourceLocation l) { FileLocations::addRegion(fMap, region, l); });
100}
101
103{
104 Q_ASSERT(state().pendingRegions.contains(region));
105 FileLocations::Tree fMap = state().currentMap;
106 lineWriter.endSourceLocation(state().pendingRegions.value(region));
107 state().pendingRegions.remove(region);
108 if (state().pendingComments.contains(region)) {
109 if (!skipComments) {
110 bool updateLocs =
112 QList<SourceLocation> *cLocs =
113 (updateLocs ? &(fMap->info().postCommentLocations[region]) : nullptr);
114 state().pendingComments[region].writePost(*this, cLocs);
115 }
116 state().pendingComments.remove(region);
117 }
118}
119
127{
128 QString codeForRegion;
129 switch (region) {
131 codeForRegion = u"component"_s;
132 break;
134 case ColonTokenRegion:
135 codeForRegion = u":"_s;
136 break;
138 codeForRegion = u"import"_s;
139 break;
140 case AsTokenRegion:
141 codeForRegion = u"as"_s;
142 break;
143 case OnTokenRegion:
144 codeForRegion = u"on"_s;
145 break;
146 case IdTokenRegion:
147 codeForRegion = u"id"_s;
148 break;
149 case LeftBraceRegion:
150 codeForRegion = u"{"_s;
151 break;
152 case RightBraceRegion:
153 codeForRegion = u"}"_s;
154 break;
156 codeForRegion = u"["_s;
157 break;
159 codeForRegion = u"]"_s;
160 break;
162 codeForRegion = u"("_s;
163 break;
165 codeForRegion = u")"_s;
166 break;
168 codeForRegion = u"enum"_s;
169 break;
171 codeForRegion = u"default"_s;
172 break;
174 codeForRegion = u"required"_s;
175 break;
177 codeForRegion = u"readonly"_s;
178 break;
180 codeForRegion = u"property"_s;
181 break;
183 codeForRegion = u"function"_s;
184 break;
186 codeForRegion = u"signal"_s;
187 break;
189 codeForRegion = u"return"_s;
190 break;
192 codeForRegion = u"..."_s;
193 break;
194 case EqualTokenRegion:
195 codeForRegion = u"="_s;
196 break;
198 codeForRegion = u"pragma"_s;
199 break;
200 case CommaTokenRegion:
201 codeForRegion = u","_s;
202 break;
203 case ForKeywordRegion:
204 codeForRegion = u"for"_s;
205 break;
207 codeForRegion = u"else"_s;
208 break;
209 case DoKeywordRegion:
210 codeForRegion = u"do"_s;
211 break;
213 codeForRegion = u"while"_s;
214 break;
215 case TryKeywordRegion:
216 codeForRegion = u"try"_s;
217 break;
219 codeForRegion = u"catch"_s;
220 break;
222 codeForRegion = u"finally"_s;
223 break;
225 codeForRegion = u"case"_s;
226 break;
228 codeForRegion = u"throw"_s;
229 break;
231 codeForRegion = u"continue"_s;
232 break;
234 codeForRegion = u"break"_s;
235 break;
237 codeForRegion = u"?"_s;
238 break;
240 codeForRegion = u";"_s;
241 break;
242 case IfKeywordRegion:
243 codeForRegion = u"if"_s;
244 break;
246 codeForRegion = u"switch"_s;
247 break;
248 // not keywords:
249 case ImportUriRegion:
250 case IdNameRegion:
251 case IdentifierRegion:
253 case MainRegion:
254 case OnTargetRegion:
258 case InOfTokenRegion:
260 case VersionRegion:
261 case EnumValueRegion:
262 Q_ASSERT_X(false, "regionToString", "Using regionToString on a value or an identifier!");
263 return *this;
264 }
265
266 return writeRegion(region, codeForRegion);
267}
268
270{
271 regionStart(region);
272 lineWriter.write(toWrite);
273 regionEnd(region);
274 return *this;
275}
288{
289 switch (fileItem.internalKind()) {
290 case DomType::QmlFile:
291 return writtenQmlFileItem(fileItem, fileItem.canonicalPath());
292 case DomType::JsFile:
293 return writtenJsFileItem(fileItem, fileItem.canonicalPath());
294 default:
295 qCWarning(writeOutLog) << fileItem.internalKind() << " is not supported";
296 return DomItem{};
297 }
298}
299
300DomItem OutWriter::writtenQmlFileItem(const DomItem &fileItem, const Path &filePath)
301{
302 Q_ASSERT(fileItem.internalKind() == DomType::QmlFile);
303 auto mutableFile = fileItem.makeCopy(DomItem::CopyOption::EnvDisconnected);
304 // QmlFile specific visitor for reformattedScriptExpressions tree
305 // lambda function responsible for the update of the initial expression by the formatted one
306 auto exprUpdater = [&mutableFile, filePath](
307 const Path &p, const UpdatedScriptExpression::Tree &t) {
308 if (std::shared_ptr<ScriptExpression> formattedExpr = t->info().expr) {
309 Q_ASSERT(p.mid(0, filePath.length()) == filePath);
310 MutableDomItem originalExprItem = mutableFile.path(p.mid(filePath.length()));
311 if (!originalExprItem)
312 qCWarning(writeOutLog) << "failed to get" << p.mid(filePath.length()) << "from"
313 << mutableFile.canonicalPath();
314 // Verifying originalExprItem.as<ScriptExpression>() == false is handy
315 // because we can't call setScript on the ScriptExpression itself and it needs to
316 // be called on the container / parent item. See setScript for details
317 else if (formattedExpr->ast()
318 || (!originalExprItem.as<ScriptExpression>()
319 || !originalExprItem.as<ScriptExpression>()->ast()))
320 originalExprItem.setScript(formattedExpr);
321 else {
322 logScriptExprUpdateSkipped(originalExprItem.item(),
323 originalExprItem.canonicalPath(), formattedExpr);
324 }
325 }
326 return true;
327 };
328 // update relevant formatted expressions
330 return mutableFile.item();
331}
332
333DomItem OutWriter::writtenJsFileItem(const DomItem &fileItem, const Path &filePath)
334{
335 Q_ASSERT(fileItem.internalKind() == DomType::JsFile);
336 auto mutableFile = fileItem.makeCopy(DomItem::CopyOption::EnvDisconnected);
339 [&mutableFile, filePath](const Path &p, const UpdatedScriptExpression::Tree &t) {
340 if (std::shared_ptr<ScriptExpression> formattedExpr = t->info().expr) {
341 Q_ASSERT(p.mid(0, filePath.length()) == filePath);
342 mutableFile.mutableAs<JsFile>()->setExpression(formattedExpr);
343 }
344 return true;
345 });
346 return mutableFile.item();
347}
348
349void OutWriter::logScriptExprUpdateSkipped(
350 const DomItem &exprItem, const Path &exprPath,
351 const std::shared_ptr<ScriptExpression> &formattedExpr)
352{
353 qCWarning(writeOutLog).noquote() << "Skipped update of reformatted ScriptExpression with "
354 "code:\n---------------\n"
355 << formattedExpr->code() << "\n---------------\n preCode:" <<
356 [&formattedExpr](Sink s) { sinkEscaped(s, formattedExpr->preCode()); }
357 << "\n postCode: " <<
358 [&formattedExpr](Sink s) { sinkEscaped(s, formattedExpr->postCode()); }
359 << "\n as it failed standalone reparse with errors:" <<
360 [&exprItem, &exprPath, &formattedExpr](Sink s) {
361 exprItem.copy(formattedExpr, exprPath)
362 .iterateErrors(
363 [s](const DomItem &, const ErrorMessage &msg) {
364 s(u"\n ");
365 msg.dump(s);
366 return true;
367 },
368 true);
369 } << "\n";
370}
371} // namespace Dom
372} // namespace QQmlJS
QList< Key > keys() const
Definition qmap.h:383
bool isEmpty() const
Definition qmap.h:269
iterator begin()
Definition qmap.h:598
iterator end()
Definition qmap.h:602
Path canonicalPath() const
static void addRegion(const Tree &fLoc, FileLocationRegion region, SourceLocation loc)
std::shared_ptr< AttachedInfoT< FileLocations > > Tree
static Tree ensure(const Tree &base, const Path &basePath, AttachedInfo::PathType pType=AttachedInfo::PathType::Relative)
static void updateFullLocation(const Tree &fLoc, SourceLocation loc)
LineWriter & write(QStringView v, TextAddType tType=TextAddType::Normal)
void endSourceLocation(PendingSourceLocationId)
PendingSourceLocationId startSourceLocation(SourceLocation *)
const LineWriterOptions & options() const
MutableDomItem path(const Path &p)
QMap< FileLocationRegion, PendingSourceLocationId > pendingRegions
PendingSourceLocationId fullRegionId
QMap< FileLocationRegion, CommentedElement > pendingComments
OutWriterState(const Path &itPath, const DomItem &it, const FileLocations::Tree &fLoc)
void regionStart(FileLocationRegion region)
void regionEnd(FileLocationRegion regino)
void itemStart(const DomItem &it)
UpdatedScriptExpression::Tree reformattedScriptExpressions
void itemEnd(const DomItem &it)
FileLocations::Tree topLocation
OutWriterState & state(int i=0)
OutWriter & writeRegion(FileLocationRegion region, QStringView toWrite)
DomItem restoreWrittenFileItem(const DomItem &fileItem)
QString toString() const
Keeps the comments associated with a DomItem.
std::shared_ptr< AttachedInfoT< UpdatedScriptExpression > > Tree
static bool visitTree(const Tree &base, function_ref< bool(const Path &, const Tree &)> visitor, const Path &basePath=Path())
\inmodule QtCore
Definition qstringview.h:78
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QSet< QString >::iterator it
else opt state
[0]
void sinkEscaped(const Sink &sink, QStringView s, EscapeOptions options)
dumps a string as quoted string (escaping things like quotes or newlines)
function_ref< void(QStringView)> Sink
Combined button and popup list for selecting options.
#define qCWarning(category,...)
GLfloat GLfloat GLfloat w
[0]
GLdouble s
[6]
Definition qopenglext.h:235
GLdouble GLdouble t
Definition qopenglext.h:243
GLfloat GLfloat p
[1]
GLuint * states
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
QGraphicsItem * item