1 | // Copyright (C) 2021 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 |
3 | |
4 | #ifndef QDOCDATABASE_H |
5 | #define QDOCDATABASE_H |
6 | |
7 | #include "config.h" |
8 | #include "examplenode.h" |
9 | #include "propertynode.h" |
10 | #include "text.h" |
11 | #include "tree.h" |
12 | |
13 | #include <QtCore/qdebug.h> |
14 | #include <QtCore/qmap.h> |
15 | #include <QtCore/qstring.h> |
16 | |
17 | QT_BEGIN_NAMESPACE |
18 | |
19 | typedef QMultiMap<Text, const Node *> TextToNodeMap; |
20 | |
21 | class Atom; |
22 | class FunctionNode; |
23 | class Generator; |
24 | class QDocDatabase; |
25 | |
26 | enum FindFlag { |
27 | SearchBaseClasses = 0x1, |
28 | SearchEnumValues = 0x2, |
29 | TypesOnly = 0x4, |
30 | IgnoreModules = 0x8 |
31 | }; |
32 | |
33 | class QDocForest |
34 | { |
35 | private: |
36 | friend class QDocDatabase; |
37 | explicit QDocForest(QDocDatabase *qdb) : m_qdb(qdb), m_primaryTree(nullptr), m_currentIndex(0) |
38 | { |
39 | } |
40 | ~QDocForest(); |
41 | |
42 | Tree *firstTree(); |
43 | Tree *nextTree(); |
44 | Tree *primaryTree() { return m_primaryTree; } |
45 | Tree *findTree(const QString &t) { return m_forest.value(key: t); } |
46 | QStringList keys() { return m_forest.keys(); } |
47 | NamespaceNode *primaryTreeRoot() { return (m_primaryTree ? m_primaryTree->root() : nullptr); } |
48 | bool isEmpty() { return searchOrder().isEmpty(); } |
49 | bool done() { return (m_currentIndex >= searchOrder().size()); } |
50 | const QList<Tree *> &searchOrder(); |
51 | const QList<Tree *> &indexSearchOrder(); |
52 | void setSearchOrder(const QStringList &t); |
53 | bool isLoaded(const QString &fn) |
54 | { |
55 | return std::any_of(first: searchOrder().constBegin(), last: searchOrder().constEnd(), |
56 | pred: [fn](Tree *tree) { return fn == tree->indexFileName(); }); |
57 | } |
58 | |
59 | const Node *findNode(const QStringList &path, const Node *relative, int findFlags, |
60 | Node::Genus genus) |
61 | { |
62 | for (const auto *tree : searchOrder()) { |
63 | const Node *n = tree->findNode(path, relative, flags: findFlags, genus); |
64 | if (n) |
65 | return n; |
66 | relative = nullptr; |
67 | } |
68 | return nullptr; |
69 | } |
70 | |
71 | Node *findNodeByNameAndType(const QStringList &path, bool (Node::*isMatch)() const) |
72 | { |
73 | for (const auto *tree : searchOrder()) { |
74 | Node *n = tree->findNodeByNameAndType(path, isMatch); |
75 | if (n) |
76 | return n; |
77 | } |
78 | return nullptr; |
79 | } |
80 | |
81 | ClassNode *findClassNode(const QStringList &path) |
82 | { |
83 | for (const auto *tree : searchOrder()) { |
84 | ClassNode *n = tree->findClassNode(path); |
85 | if (n) |
86 | return n; |
87 | } |
88 | return nullptr; |
89 | } |
90 | |
91 | Node *findNodeForInclude(const QStringList &path) |
92 | { |
93 | for (const auto *tree : searchOrder()) { |
94 | Node *n = tree->findNodeForInclude(path); |
95 | if (n) |
96 | return n; |
97 | } |
98 | return nullptr; |
99 | } |
100 | |
101 | const FunctionNode *findFunctionNode(const QStringList &path, const Parameters ¶meters, |
102 | const Node *relative, Node::Genus genus); |
103 | const Node *findNodeForTarget(QStringList &targetPath, const Node *relative, Node::Genus genus, |
104 | QString &ref); |
105 | |
106 | const Node *findTypeNode(const QStringList &path, const Node *relative, Node::Genus genus) |
107 | { |
108 | int flags = SearchBaseClasses | SearchEnumValues | TypesOnly; |
109 | if (relative && genus == Node::DontCare && relative->genus() != Node::DOC) |
110 | genus = relative->genus(); |
111 | for (const auto *tree : searchOrder()) { |
112 | const Node *n = tree->findNode(path, relative, flags, genus); |
113 | if (n) |
114 | return n; |
115 | relative = nullptr; |
116 | } |
117 | return nullptr; |
118 | } |
119 | |
120 | const PageNode *findPageNodeByTitle(const QString &title) |
121 | { |
122 | for (const auto *tree : searchOrder()) { |
123 | const PageNode *n = tree->findPageNodeByTitle(title); |
124 | if (n) |
125 | return n; |
126 | } |
127 | return nullptr; |
128 | } |
129 | |
130 | const CollectionNode *getCollectionNode(const QString &name, Node::NodeType type) |
131 | { |
132 | for (auto *tree : searchOrder()) { |
133 | const CollectionNode *cn = tree->getCollection(name, type); |
134 | if (cn) |
135 | return cn; |
136 | } |
137 | return nullptr; |
138 | } |
139 | |
140 | QmlTypeNode *lookupQmlType(const QString &name) |
141 | { |
142 | for (const auto *tree : searchOrder()) { |
143 | QmlTypeNode *qcn = tree->lookupQmlType(name); |
144 | if (qcn) |
145 | return qcn; |
146 | } |
147 | return nullptr; |
148 | } |
149 | |
150 | void clearSearchOrder() { m_searchOrder.clear(); } |
151 | void newPrimaryTree(const QString &module); |
152 | void setPrimaryTree(const QString &t); |
153 | NamespaceNode *newIndexTree(const QString &module); |
154 | |
155 | private: |
156 | QDocDatabase *m_qdb; |
157 | Tree *m_primaryTree; |
158 | int m_currentIndex; |
159 | QMap<QString, Tree *> m_forest; |
160 | QList<Tree *> m_searchOrder; |
161 | QList<Tree *> m_indexSearchOrder; |
162 | QList<QString> m_moduleNames; |
163 | }; |
164 | |
165 | class QDocDatabase |
166 | { |
167 | public: |
168 | static QDocDatabase *qdocDB(); |
169 | static void destroyQdocDB(); |
170 | ~QDocDatabase() = default; |
171 | |
172 | using FindFunctionPtr = void (QDocDatabase::*)(Aggregate *); |
173 | |
174 | Tree *findTree(const QString &t) { return m_forest.findTree(t); } |
175 | |
176 | const CNMap &groups() { return primaryTree()->groups(); } |
177 | const CNMap &modules() { return primaryTree()->modules(); } |
178 | const CNMap &qmlModules() { return primaryTree()->qmlModules(); } |
179 | |
180 | CollectionNode *addGroup(const QString &name) { return primaryTree()->addGroup(name); } |
181 | CollectionNode *addModule(const QString &name) { return primaryTree()->addModule(name); } |
182 | CollectionNode *addQmlModule(const QString &name) { return primaryTree()->addQmlModule(name); } |
183 | |
184 | CollectionNode *addToGroup(const QString &name, Node *node) |
185 | { |
186 | return primaryTree()->addToGroup(name, node); |
187 | } |
188 | CollectionNode *addToModule(const QString &name, Node *node) |
189 | { |
190 | return primaryTree()->addToModule(name, node); |
191 | } |
192 | CollectionNode *addToQmlModule(const QString &name, Node *node) |
193 | { |
194 | return primaryTree()->addToQmlModule(name, node); |
195 | } |
196 | |
197 | void addExampleNode(ExampleNode *n) { primaryTree()->addExampleNode(n); } |
198 | ExampleNodeMap &exampleNodeMap() { return primaryTree()->exampleNodeMap(); } |
199 | |
200 | QmlTypeNode *findQmlType(const QString &name); |
201 | QmlTypeNode *findQmlType(const QString &qmid, const QString &name); |
202 | QmlTypeNode *findQmlType(const ImportRec &import, const QString &name); |
203 | |
204 | static NodeMultiMap &obsoleteClasses() { return s_obsoleteClasses; } |
205 | static NodeMultiMap &obsoleteQmlTypes() { return s_obsoleteQmlTypes; } |
206 | static NodeMultiMap &classesWithObsoleteMembers() { return s_classesWithObsoleteMembers; } |
207 | static NodeMultiMap &qmlTypesWithObsoleteMembers() { return s_qmlTypesWithObsoleteMembers; } |
208 | static NodeMultiMap &cppClasses() { return s_cppClasses; } |
209 | static NodeMultiMap &qmlBasicTypes() { return s_qmlBasicTypes; } |
210 | static NodeMultiMap &qmlTypes() { return s_qmlTypes; } |
211 | static NodeMultiMap &examples() { return s_examples; } |
212 | static NodeMultiMapMap &newClassMaps() { return s_newClassMaps; } |
213 | static NodeMultiMapMap &newQmlTypeMaps() { return s_newQmlTypeMaps; } |
214 | static NodeMultiMapMap &newEnumValueMaps() { return s_newEnumValueMaps; } |
215 | static NodeMultiMapMap &newSinceMaps() { return s_newSinceMaps; } |
216 | |
217 | private: |
218 | void findAllClasses(Aggregate *node) { node->findAllClasses(); } |
219 | void findAllFunctions(Aggregate *node) { node->findAllFunctions(functionIndex&: m_functionIndex); } |
220 | void findAllAttributions(Aggregate *node) { node->findAllAttributions(attributions&: m_attributions); } |
221 | void findAllLegaleseTexts(Aggregate *node); |
222 | void findAllObsoleteThings(Aggregate *node) { node->findAllObsoleteThings(); } |
223 | void findAllSince(Aggregate *node) { node->findAllSince(); } |
224 | |
225 | public: |
226 | /******************************************************************* |
227 | special collection access functions |
228 | ********************************************************************/ |
229 | NodeMultiMap &getCppClasses(); |
230 | NodeMultiMap &getObsoleteClasses(); |
231 | NodeMultiMap &getClassesWithObsoleteMembers(); |
232 | NodeMultiMap &getObsoleteQmlTypes(); |
233 | NodeMultiMap &getQmlTypesWithObsoleteMembers(); |
234 | NodeMultiMap &getNamespaces(); |
235 | NodeMultiMap &getQmlValueTypes(); |
236 | NodeMultiMap &getQmlTypes(); |
237 | NodeMultiMap &getExamples(); |
238 | NodeMultiMap &getAttributions(); |
239 | NodeMapMap &getFunctionIndex(); |
240 | TextToNodeMap &getLegaleseTexts(); |
241 | const NodeMultiMap &getClassMap(const QString &key); |
242 | const NodeMultiMap &getQmlTypeMap(const QString &key); |
243 | const NodeMultiMap &getSinceMap(const QString &key); |
244 | |
245 | /******************************************************************* |
246 | Many of these will be either eliminated or replaced. |
247 | ********************************************************************/ |
248 | void resolveStuff(); |
249 | void insertTarget(const QString &name, const QString &title, TargetRec::TargetType type, |
250 | Node *node, int priority) |
251 | { |
252 | primaryTree()->insertTarget(name, title, type, node, priority); |
253 | } |
254 | |
255 | /******************************************************************* |
256 | The functions declared below are called for the current tree only. |
257 | ********************************************************************/ |
258 | Aggregate *findRelatesNode(const QStringList &path) |
259 | { |
260 | return primaryTree()->findRelatesNode(path); |
261 | } |
262 | Node *findNodeInOpenNamespace(QStringList &path, bool (Node::*)() const); |
263 | /*******************************************************************/ |
264 | |
265 | /***************************************************************************** |
266 | This function can handle parameters enclosed in '[' ']' (domain and genus). |
267 | ******************************************************************************/ |
268 | const Node *findNodeForAtom(const Atom *atom, const Node *relative, QString &ref, |
269 | Node::Genus genus = Node::DontCare); |
270 | /*******************************************************************/ |
271 | |
272 | /******************************************************************* |
273 | The functions declared below are called for all trees. |
274 | ********************************************************************/ |
275 | ClassNode *findClassNode(const QStringList &path) { return m_forest.findClassNode(path); } |
276 | Node *findNodeForInclude(const QStringList &path) { return m_forest.findNodeForInclude(path); } |
277 | const FunctionNode *findFunctionNode(const QString &target, const Node *relative, |
278 | Node::Genus genus); |
279 | const Node *findTypeNode(const QString &type, const Node *relative, Node::Genus genus); |
280 | const Node *findNodeForTarget(const QString &target, const Node *relative); |
281 | const PageNode *findPageNodeByTitle(const QString &title) |
282 | { |
283 | return m_forest.findPageNodeByTitle(title); |
284 | } |
285 | Node *findNodeByNameAndType(const QStringList &path, bool (Node::*isMatch)() const) |
286 | { |
287 | return m_forest.findNodeByNameAndType(path, isMatch); |
288 | } |
289 | const CollectionNode *getCollectionNode(const QString &name, Node::NodeType type) |
290 | { |
291 | return m_forest.getCollectionNode(name, type); |
292 | } |
293 | const CollectionNode *getModuleNode(const Node *relative); |
294 | |
295 | FunctionNode *findFunctionNodeForTag(const QString &tag) |
296 | { |
297 | return primaryTree()->findFunctionNodeForTag(tag); |
298 | } |
299 | FunctionNode *findMacroNode(const QString &t) { return primaryTree()->findMacroNode(t); } |
300 | |
301 | QStringList groupNamesForNode(Node *node); |
302 | |
303 | private: |
304 | const Node *findNodeForTarget(QStringList &targetPath, const Node *relative, Node::Genus genus, |
305 | QString &ref) |
306 | { |
307 | return m_forest.findNodeForTarget(targetPath, relative, genus, ref); |
308 | } |
309 | const FunctionNode *findFunctionNode(const QStringList &path, const Parameters ¶meters, |
310 | const Node *relative, Node::Genus genus) |
311 | { |
312 | return m_forest.findFunctionNode(path, parameters, relative, genus); |
313 | } |
314 | |
315 | /*******************************************************************/ |
316 | public: |
317 | void addPropertyFunction(PropertyNode *property, const QString &funcName, |
318 | PropertyNode::FunctionRole funcRole) |
319 | { |
320 | primaryTree()->addPropertyFunction(property, funcName, funcRole); |
321 | } |
322 | |
323 | void setVersion(const QString &v) { m_version = v; } |
324 | [[nodiscard]] QString version() const { return m_version; } |
325 | |
326 | void readIndexes(const QStringList &indexFiles); |
327 | void generateIndex(const QString &fileName, const QString &url, const QString &title, |
328 | Generator *g); |
329 | |
330 | void clearOpenNamespaces() { m_openNamespaces.clear(); } |
331 | void insertOpenNamespace(const QString &path) { m_openNamespaces.insert(value: path); } |
332 | void processForest(); |
333 | |
334 | NamespaceNode *primaryTreeRoot() { return m_forest.primaryTreeRoot(); } |
335 | void newPrimaryTree(const QString &module) { m_forest.newPrimaryTree(module); } |
336 | void setPrimaryTree(const QString &t) { m_forest.setPrimaryTree(t); } |
337 | NamespaceNode *newIndexTree(const QString &module) { return m_forest.newIndexTree(module); } |
338 | const QList<Tree *> &searchOrder() { return m_forest.searchOrder(); } |
339 | void setLocalSearch() { m_forest.m_searchOrder = QList<Tree *>(1, primaryTree()); } |
340 | void setSearchOrder(const QList<Tree *> &searchOrder) { m_forest.m_searchOrder = searchOrder; } |
341 | void setSearchOrder(QStringList &t) { m_forest.setSearchOrder(t); } |
342 | void mergeCollections(Node::NodeType type, CNMap &cnm, const Node *relative); |
343 | void mergeCollections(CollectionNode *c); |
344 | void clearSearchOrder() { m_forest.clearSearchOrder(); } |
345 | QStringList keys() { return m_forest.keys(); } |
346 | void resolveNamespaces(); |
347 | void resolveProxies(); |
348 | void resolveBaseClasses(); |
349 | void updateNavigation(); |
350 | |
351 | private: |
352 | friend class Tree; |
353 | |
354 | void processForest(FindFunctionPtr func); |
355 | bool isLoaded(const QString &t) { return m_forest.isLoaded(fn: t); } |
356 | static void initializeDB(); |
357 | |
358 | private: |
359 | QDocDatabase(); |
360 | QDocDatabase(QDocDatabase const &) : m_forest(this) { } |
361 | QDocDatabase &operator=(QDocDatabase const &); |
362 | |
363 | public: |
364 | Tree *primaryTree() { return m_forest.primaryTree(); } |
365 | |
366 | private: |
367 | static QDocDatabase *s_qdocDB; |
368 | static NodeMap s_typeNodeMap; |
369 | static NodeMultiMap s_obsoleteClasses; |
370 | static NodeMultiMap s_classesWithObsoleteMembers; |
371 | static NodeMultiMap s_obsoleteQmlTypes; |
372 | static NodeMultiMap s_qmlTypesWithObsoleteMembers; |
373 | static NodeMultiMap s_cppClasses; |
374 | static NodeMultiMap s_qmlBasicTypes; |
375 | static NodeMultiMap s_qmlTypes; |
376 | static NodeMultiMap s_examples; |
377 | static NodeMultiMapMap s_newClassMaps; |
378 | static NodeMultiMapMap s_newQmlTypeMaps; |
379 | static NodeMultiMapMap s_newEnumValueMaps; |
380 | static NodeMultiMapMap s_newSinceMaps; |
381 | |
382 | QString m_version {}; |
383 | QDocForest m_forest; |
384 | |
385 | NodeMultiMap m_namespaceIndex {}; |
386 | NodeMultiMap m_attributions {}; |
387 | NodeMapMap m_functionIndex {}; |
388 | TextToNodeMap m_legaleseTexts {}; |
389 | QSet<QString> m_openNamespaces {}; |
390 | QMultiHash<Tree*, FindFunctionPtr> m_completedFindFunctions {}; |
391 | }; |
392 | |
393 | QT_END_NAMESPACE |
394 | |
395 | #endif |
396 | |