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.dvValueLazyField(visitor, Fields::fullRegion, [this]() {
39 return sourceLocationToQCborValue(fullRegion);
40 });
41 cont = cont
42 && self.dvItemField(std::move(visitor), Fields::regions, [this, &self]() -> DomItem {
43 const Path pathFromOwner = self.pathFromOwner().withField(Fields::regions);
44 auto map = Map::fromFileRegionMap(pathFromOwner, regions);
45 return self.subMapItem(map);
46 });
47 return cont;
48}
49
50Tree createTree(const Path &basePath)
51{
52 return Node::instantiate(nullptr, basePath);
53}
54
55Tree ensure(const Tree &base, const Path &basePath)
56{
57 Path relative = basePath;
58 Tree res = base;
59 for (const auto &p : std::as_const(relative)) {
60 res = res->insertOrReturnChildAt(p);
61 }
62 return res;
63}
64
65Tree find(const Tree &self, const Path &p)
66{
67 Path rest = p;
68 Tree res = self;
69 while (rest) {
70 if (!res)
71 break;
72 res = res->subItems().value(rest.head());
73 rest = rest.dropFront();
74 }
75 return res;
76}
77
78bool visitTree(const Tree &base, function_ref<bool(const Path &, const Tree &)> visitor,
79 const Path &basePath)
80{
81 if (base) {
82 Path pNow = basePath.withPath(base->path());
83 if (!visitor(pNow, base)) {
84 return false;
85 }
86 for (const auto &childNode : base->subItems()) {
87 if (!visitTree(childNode, visitor, pNow))
88 return false;
89 }
90 }
91 return true;
92}
93
95{
96 QString result;
97 for (auto *it = base.get(); it; it = it->parent().get()) {
98 result.prepend(it->path().toString());
99 }
100 return result;
101}
102
103/*!
104 \internal
105 Returns the tree corresponding to a DomItem.
106 */
107Tree treeOf(const DomItem &item)
108{
109 Path p;
110 DomItem fLoc = item.field(Fields::fileLocationsTree);
111 if (!fLoc) {
112 // owner or container.owner should be a file, so this works, but we could simply use the
113 // canonical path, and PathType::Canonical instead...
114 DomItem o = item.owner();
115 p = item.pathFromOwner();
116 fLoc = o.field(Fields::fileLocationsTree);
117 while (!fLoc && o) {
120 o = c.owner();
121 fLoc = o.field(Fields::fileLocationsTree);
122 }
123 }
124 if (Node::Ptr fLocPtr = fLoc.ownerAs<Node>())
125 return find(fLocPtr, p);
126 return {};
127}
128
129static void updateFullLocation(const Tree &fLoc, SourceLocation loc)
130{
131 Q_ASSERT(fLoc);
132 if (loc != SourceLocation()) {
133 Tree p = fLoc;
134 while (p) {
135 SourceLocation &l = p->info().fullRegion;
136 if (loc.begin() < l.begin() || loc.end() > l.end()) {
137 l = combine(l, loc);
138 p->info().regions[MainRegion] = l;
139 } else {
140 break;
141 }
142 p = p->parent();
143 }
144 }
145}
146
147// Adding a new region to file location regions might break down qmlformat because
148// comments might be linked to new region undesirably. We might need to add an
149// exception to AstRangesVisitor::shouldSkipRegion when confronted those cases.
150// beware of shrinking and reassigning regions (QTBUG-131288)
151void addRegion(const Tree &fLoc, FileLocationRegion region, SourceLocation loc)
152{
153 Q_ASSERT(fLoc);
154 fLoc->info().regions[region] = loc;
155 updateFullLocation(fLoc, loc);
156}
157
158SourceLocation region(const Tree &fLoc, FileLocationRegion region)
159{
160 Q_ASSERT(fLoc);
161 const auto &regions = fLoc->info().regions;
162 if (auto it = regions.constFind(region); it != regions.constEnd() && it->isValid()) {
163 return *it;
164 }
165
166 if (region == MainRegion)
167 return fLoc->info().fullRegion;
168
169 return SourceLocation{};
170}
171
172/*!
173\internal
174\class QQmlJS::Dom::FileLocations::Node
175\brief Represents a Node of FileLocations tree
176
177Attributes:
178\list
179\li parent: parent Node in tree (might be empty)
180\li subItems: subItems of the tree (path -> Node)
181\li infoItem: actual FileLocations::Info with regions
182\endlist
183
184\sa QQmlJs::Dom::Node
185*/
186
187Node::Ptr Node::instantiate(const Ptr &parent, const Path &p)
188{
189 return std::shared_ptr<Node>(new Node(parent, p));
190}
191
192bool Node::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
193{
194 bool cont = true;
195 if (const Ptr p = parent()) {
196 cont = cont && self.dvItemField(visitor, Fields::parent, [&self, &p]() {
197 return self.copy(p, self.m_ownerPath.dropTail(2), p.get());
198 });
199 }
200 cont = cont
201 && self.dvValueLazyField(visitor, Fields::path, [this]() { return path().toString(); });
202 cont = cont && self.dvItemField(visitor, 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 && self.dvItemField(std::move(visitor), Fields::infoItem, [&self, this]() {
218 return self.wrapField(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)
bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const