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
qqmldomfilelocations.cpp
Go to the documentation of this file.
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
6
8namespace QQmlJS {
9namespace Dom {
10
11using namespace Qt::StringLiterals;
12
13/*!
14\internal
15\namespace QQmlJS::Dom::FileLocations
16\brief Provides entities to maintain mappings between elements and their location in a file
17
18The location information is associated with the element it refers to via ::Node
19There are free functions to simplify the handling of the FileLocations tree.
20*/
21namespace FileLocations {
22
23/*!
24\internal
25\namespace QQmlJS::Dom::FileLocations::Info
26\brief Contains region information about the item
27
28Attributes:
29\list
30\li fullRegion: A location guaranteed to include this element and all its sub elements
31\li regions: a map with locations of regions of this element, the empty string is the default region
32 of this element
33\endlist
34*/
35bool Info::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
36{
37 bool cont = true;
38 cont = cont && self.invokeVisitorOnLazyField(visitor, Fields::fullRegion, [this]() {
39 return sourceLocationToQCborValue(fullRegion);
40 });
41 cont = cont && visitor(PathEls::Field(Fields::regions), [this, &self]() -> DomItem {
42 const Path pathFromOwner = self.pathFromOwner().withField(Fields::regions);
43 auto map = Map::fromFileRegionMap(pathFromOwner, regions);
44 return self.subMapItem(map);
45 });
46 return cont;
47}
48
49Tree createTree(const Path &basePath)
50{
51 return Node::instantiate(nullptr, basePath);
52}
53
54Tree ensure(const Tree &base, const Path &basePath)
55{
56 Path relative = basePath;
57 Tree res = base;
58 for (const auto &p : std::as_const(relative)) {
59 res = res->insertOrReturnChildAt(p);
60 }
61 return res;
62}
63
64Tree find(const Tree &self, const Path &p)
65{
66 Path rest = p;
67 Tree res = self;
68 while (rest) {
69 if (!res)
70 break;
71 res = res->subItems().value(rest.head());
72 rest = rest.dropFront();
73 }
74 return res;
75}
76
77bool visitTree(const Tree &base, function_ref<bool(const Path &, const Tree &)> visitor,
78 const Path &basePath)
79{
80 if (base) {
81 Path pNow = basePath.withPath(base->path());
82 if (!visitor(pNow, base)) {
83 return false;
84 }
85 for (const auto &childNode : base->subItems()) {
86 if (!visitTree(childNode, visitor, pNow))
87 return false;
88 }
89 }
90 return true;
91}
92
94{
95 QString result;
96 for (auto *it = base.get(); it; it = it->parent().get()) {
97 result.prepend(it->path().toString());
98 }
99 return result;
100}
101
102/*!
103 \internal
104 Returns the tree corresponding to a DomItem.
105 */
106Tree treeOf(const DomItem &item)
107{
108 Path p;
109 DomItem fLoc = item.field(Fields::fileLocationsTree);
110 if (!fLoc) {
111 // owner or container.owner should be a file, so this works, but we could simply use the
112 // canonical path, and PathType::Canonical instead...
113 DomItem o = item.owner();
114 p = item.pathFromOwner();
115 fLoc = o.field(Fields::fileLocationsTree);
116 while (!fLoc && o) {
119 o = c.owner();
120 fLoc = o.field(Fields::fileLocationsTree);
121 }
122 }
123 if (Node::Ptr fLocPtr = fLoc.ownerAs<Node>())
124 return find(fLocPtr, p);
125 return {};
126}
127
128static void updateFullLocation(const Tree &fLoc, SourceLocation loc)
129{
130 Q_ASSERT(fLoc);
131 if (loc != SourceLocation()) {
132 Tree p = fLoc;
133 while (p) {
134 SourceLocation &l = p->info().fullRegion;
135 if (loc.begin() < l.begin() || loc.end() > l.end()) {
136 l = combine(l, loc);
137 p->info().regions[MainRegion] = l;
138 } else {
139 break;
140 }
141 p = p->parent();
142 }
143 }
144}
145
146// Adding a new region to file location regions might break down qmlformat because
147// comments might be linked to new region undesirably. We might need to add an
148// exception to AstRangesVisitor::shouldSkipRegion when confronted those cases.
149// beware of shrinking and reassigning regions (QTBUG-131288)
150void addRegion(const Tree &fLoc, FileLocationRegion region, SourceLocation loc)
151{
152 Q_ASSERT(fLoc);
153 fLoc->info().regions[region] = loc;
154 updateFullLocation(fLoc, loc);
155}
156
157SourceLocation region(const Tree &fLoc, FileLocationRegion region)
158{
159 Q_ASSERT(fLoc);
160 const auto &regions = fLoc->info().regions;
161 if (auto it = regions.constFind(region); it != regions.constEnd() && it->isValid()) {
162 return *it;
163 }
164
165 if (region == MainRegion)
166 return fLoc->info().fullRegion;
167
168 return SourceLocation{};
169}
170
171/*!
172\internal
173\class QQmlJS::Dom::FileLocations::Node
174\brief Represents a Node of FileLocations tree
175
176Attributes:
177\list
178\li parent: parent Node in tree (might be empty)
179\li subItems: subItems of the tree (path -> Node)
180\li infoItem: actual FileLocations::Info with regions
181\endlist
182
183\sa QQmlJs::Dom::Node
184*/
185
186Node::Ptr Node::instantiate(const Ptr &parent, const Path &p)
187{
188 return std::shared_ptr<Node>(new Node(parent, p));
189}
190
191bool Node::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
192{
193 bool cont = true;
194 if (const Ptr p = parent()) {
195 cont = cont && visitor(PathEls::Field(Fields::parent), [&self, &p]() {
196 return self.copy(p, self.m_ownerPath.dropTail(2), p.get());
197 });
198 }
199 cont = cont && self.invokeVisitorOnLazyField(visitor, Fields::path, [this]() {
200 return path().toString();
201 });
202 cont = cont && visitor(PathEls::Field(Fields::subItems), [this, &self]() {
203 return self.subMapItem(Map(
204 Path::fromField(Fields::subItems),
205 [this](const DomItem &map, const QString &key) {
206 Path p = Path::fromString(key);
207 return map.copy(m_subItems.value(p), map.canonicalPath().withKey(key));
208 },
209 [this](const DomItem &) {
210 QSet<QString> res;
211 for (const auto &p : m_subItems.keys())
212 res.insert(p.toString());
213 return res;
214 },
215 QLatin1String("Node")));
216 });
217 cont = cont && visitor(PathEls::Field(Fields::infoItem), [&self, this]() {
218 return self.wrap(PathEls::Field(Fields::infoItem), m_info);
219 });
220 return cont;
221}
222
224{
225 if (Node::Ptr subEl = m_subItems.value(path)) {
226 return subEl;
227 }
228 return m_subItems.insert(path, Node::instantiate(shared_from_this(), path)).value();
229}
230
231std::shared_ptr<OwningItem> Node::doCopy(const DomItem &) const
232{
233 return std::shared_ptr<Node>(new Node(*this));
234}
235
236} // namespace FileLocations
237} // namespace Dom
238} // namespace QQmlJS
239QT_END_NAMESPACE
A value type that references any element of the Dom.
DomItem container() const
Path canonicalPath() const
DomItem subMapItem(const Map &map) const
DomItem owner() const
The owner of an element, for an qmlObject this is the containing qml file.
Path pathFromOwner() const
Represents a Node of FileLocations tree.
bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override
std::shared_ptr< OwningItem > doCopy(const DomItem &) const override
static Ptr instantiate(const Ptr &parent=nullptr, const Path &p=Path())
A DomItem that owns other DomItems and is managed through a shared pointer.
Path withPath(const Path &toAdd, bool avoidToAddAsBase=false) const
Returns a copy of this with toAdd appended to it.
Path head() const
Path last() const
Path dropFront(int n=1) const
Provides entities to maintain mappings between elements and their location in a file.
void addRegion(const Tree &fLoc, FileLocationRegion region, SourceLocation loc)
Tree createTree(const Path &basePath)
QString canonicalPathForTesting(const Tree &base)
QQmlJS::SourceLocation region(const Tree &fLoc, FileLocationRegion region)
bool visitTree(const Tree &base, function_ref< bool(const Path &, const Tree &)> visitor, const Path &basePath=Path())
Tree ensure(const Tree &base, const Path &basePath)
static void updateFullLocation(const Tree &fLoc, SourceLocation loc)
Tree find(const Tree &self, const Path &p)
Combined button and popup list for selecting options.
bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const