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
tagfilewriter.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
5
6#include "access.h"
7#include "aggregate.h"
8#include "classnode.h"
9#include "enumnode.h"
10#include "functionnode.h"
11#include "genustypes.h"
12#include "htmlgenerator.h"
13#include "location.h"
14#include "node.h"
15#include "propertynode.h"
16#include "qdocdatabase.h"
17#include "typedefnode.h"
18
19#include <algorithm>
20
22
23/*!
24 \class TagFileWriter
25
26 This class handles the generation of the QDoc tag files.
27 */
28
29/*!
30 Default constructor. \a qdb is the pointer to the
31 qdoc database that is used when reading and writing the
32 index files.
33 */
34TagFileWriter::TagFileWriter() : m_qdb(QDocDatabase::qdocDB()) { }
35
36/*!
37 Generate the tag file section with the given \a writer for the \a parent
38 node.
39 */
40void TagFileWriter::generateTagFileCompounds(QXmlStreamWriter &writer, const Aggregate *parent)
41{
42 auto nonFunctionChildren = parent->nonFunctionChildren();
43 std::sort(nonFunctionChildren.begin(), nonFunctionChildren.end(),
45 for (const auto *node : nonFunctionChildren) {
46 if (!node->url().isNull() || node->isPrivate())
47 continue;
48
49 QString kind;
50 switch (node->nodeType()) {
51 case NodeType::Namespace:
52 kind = "namespace";
53 break;
54 case NodeType::Class:
55 case NodeType::Struct:
56 case NodeType::Union:
57 case NodeType::QmlType:
58 kind = "class";
59 break;
60 default:
61 continue;
62 }
63 const auto *aggregate = static_cast<const Aggregate *>(node);
64
65 QString access = "public";
66 if (node->isProtected())
67 access = "protected";
68
69 QString objName = node->name();
70
71 // Special case: only the root node should have an empty name.
72 if (objName.isEmpty() && node != m_qdb->primaryTreeRoot())
73 continue;
74
75 // *** Write the starting tag for the element here. ***
76 writer.writeStartElement("compound");
77 writer.writeAttribute("kind", kind);
78
79 if (node->isClassNode()) {
80 writer.writeTextElement("name", node->fullDocumentName());
81 writer.writeTextElement("filename", m_generator->fullDocumentLocation(node));
82
83 // Classes contain information about their base classes.
84 const auto *classNode = static_cast<const ClassNode *>(node);
85 const QList<RelatedClass> &bases = classNode->baseClasses();
86 for (const auto &related : bases) {
87 ClassNode *n = related.m_node;
88 if (n)
89 writer.writeTextElement("base", n->name());
90 }
91
92 // Recurse to write all members.
93 generateTagFileMembers(writer, aggregate);
94 writer.writeEndElement();
95
96 // Recurse to write all compounds.
97 generateTagFileCompounds(writer, aggregate);
98 } else {
99 writer.writeTextElement("name", node->fullDocumentName());
100 writer.writeTextElement("filename", m_generator->fullDocumentLocation(node));
101
102 // Recurse to write all members.
103 generateTagFileMembers(writer, aggregate);
104 writer.writeEndElement();
105
106 // Recurse to write all compounds.
107 generateTagFileCompounds(writer, aggregate);
108 }
109 }
110}
111
112/*!
113 Writes all the members of the \a parent node with the \a writer.
114 The node represents a C++ class, namespace, etc.
115 */
116void TagFileWriter::generateTagFileMembers(QXmlStreamWriter &writer, const Aggregate *parent)
117{
118 auto childNodes = parent->childNodes();
119 std::sort(childNodes.begin(), childNodes.end(), Node::nodeNameLessThan);
120 for (const auto *node : childNodes) {
121 if (!node->url().isNull())
122 continue;
123
124 QString nodeName;
125 QString kind;
126 switch (node->nodeType()) {
127 case NodeType::Enum:
128 case NodeType::QmlEnum:
129 nodeName = "member";
130 kind = "enumeration";
131 break;
132 case NodeType::TypeAlias: // Treated as typedef
133 case NodeType::Typedef:
134 nodeName = "member";
135 kind = "typedef";
136 break;
137 case NodeType::Property:
138 nodeName = "member";
139 kind = "property";
140 break;
141 case NodeType::Function:
142 nodeName = "member";
143 kind = "function";
144 break;
145 case NodeType::Namespace:
146 nodeName = "namespace";
147 break;
148 case NodeType::Class:
149 case NodeType::Struct:
150 case NodeType::Union:
151 nodeName = "class";
152 break;
153 case NodeType::Variable:
154 default:
155 continue;
156 }
157
158 QString access;
159 switch (node->access()) {
160 case Access::Public:
161 access = "public";
162 break;
163 case Access::Protected:
164 access = "protected";
165 break;
166 case Access::Private:
167 default:
168 continue;
169 }
170
171 QString objName = node->name();
172
173 // Special case: only the root node should have an empty name.
174 if (objName.isEmpty() && node != m_qdb->primaryTreeRoot())
175 continue;
176
177 // *** Write the starting tag for the element here. ***
178 writer.writeStartElement(nodeName);
179 if (!kind.isEmpty())
180 writer.writeAttribute("kind", kind);
181
182 switch (node->nodeType()) {
183 case NodeType::Class:
184 case NodeType::Struct:
185 case NodeType::Union:
186 writer.writeCharacters(node->fullDocumentName());
187 writer.writeEndElement();
188 break;
189 case NodeType::Namespace:
190 writer.writeCharacters(node->fullDocumentName());
191 writer.writeEndElement();
192 break;
193 case NodeType::Function: {
194 /*
195 Function nodes contain information about
196 the type of function being described.
197 */
198
199 const auto *functionNode = static_cast<const FunctionNode *>(node);
200 writer.writeAttribute("protection", access);
201 writer.writeAttribute("virtualness", functionNode->virtualness());
202 writer.writeAttribute("static", functionNode->isStatic() ? "yes" : "no");
203
204 if (functionNode->isNonvirtual())
205 writer.writeTextElement("type", functionNode->returnType());
206 else
207 writer.writeTextElement("type", "virtual " + functionNode->returnType());
208
209 writer.writeTextElement("name", objName);
210 const QStringList pieces =
211 m_generator->fullDocumentLocation(node).split(QLatin1Char('#'));
212 writer.writeTextElement("anchorfile", pieces[0]);
213 writer.writeTextElement("anchor", pieces[1]);
214 QString signature = functionNode->signature(Node::SignatureReturnType);
215 signature = signature.mid(signature.indexOf(QChar('('))).trimmed();
216 if (functionNode->isConst())
217 signature += " const";
218 if (functionNode->isFinal())
219 signature += " final";
220 if (functionNode->isOverride())
221 signature += " override";
222 if (functionNode->isPureVirtual())
223 signature += " = 0";
224 writer.writeTextElement("arglist", signature);
225 }
226 writer.writeEndElement(); // member
227 break;
228 case NodeType::Property: {
229 const auto *propertyNode = static_cast<const PropertyNode *>(node);
230 writer.writeAttribute("type", propertyNode->dataType());
231 writer.writeTextElement("name", objName);
232 const QStringList pieces =
233 m_generator->fullDocumentLocation(node).split(QLatin1Char('#'));
234 writer.writeTextElement("anchorfile", pieces[0]);
235 writer.writeTextElement("anchor", pieces[1]);
236 writer.writeTextElement("arglist", QString());
237 }
238 writer.writeEndElement(); // member
239 break;
240 case NodeType::QmlEnum:
241 case NodeType::Enum: {
242 const auto *enumNode = static_cast<const EnumNode *>(node);
243 writer.writeTextElement("name", objName);
244 const QStringList pieces =
245 m_generator->fullDocumentLocation(node).split(QLatin1Char('#'));
246 writer.writeTextElement("anchorfile", pieces[0]);
247 writer.writeTextElement("anchor", pieces[1]);
248 writer.writeEndElement(); // member
249
250 for (const auto &item : enumNode->items()) {
251 writer.writeStartElement("member");
252 writer.writeAttribute("kind", "enumvalue");
253 writer.writeTextElement("name", item.name());
254 writer.writeTextElement("anchorfile", pieces[0]);
255 writer.writeTextElement("anchor", pieces[1]);
256 writer.writeTextElement("arglist", QString());
257 writer.writeEndElement(); // member
258 }
259 } break;
260 case NodeType::TypeAlias: // Treated as typedef
261 case NodeType::Typedef: {
262 const auto *typedefNode = static_cast<const TypedefNode *>(node);
263 if (typedefNode->associatedEnum())
264 writer.writeAttribute("type", typedefNode->associatedEnum()->fullDocumentName());
265 else
266 writer.writeAttribute("type", QString());
267 writer.writeTextElement("name", objName);
268 const QStringList pieces =
269 m_generator->fullDocumentLocation(node).split(QLatin1Char('#'));
270 writer.writeTextElement("anchorfile", pieces[0]);
271 writer.writeTextElement("anchor", pieces[1]);
272 writer.writeTextElement("arglist", QString());
273 }
274 writer.writeEndElement(); // member
275 break;
276
277 case NodeType::Variable:
278 default:
279 break;
280 }
281 }
282}
283
284/*!
285 Writes a tag file named \a fileName.
286 */
287void TagFileWriter::generateTagFile(const QString &fileName, Generator *g)
288{
289 QFile file(fileName);
290 QFileInfo fileInfo(fileName);
291
292 // If no path was specified or it doesn't exist,
293 // default to the output directory
294 if (fileInfo.fileName() == fileName || !fileInfo.dir().exists())
295 file.setFileName(m_generator->outputDir() + QLatin1Char('/') + fileInfo.fileName());
296
297 if (!file.open(QFile::WriteOnly | QFile::Text)) {
298 Location().warning(QString("Failed to open %1 for writing.").arg(file.fileName()));
299 return;
300 }
301
302 m_generator = g;
303 QXmlStreamWriter writer(&file);
304 writer.setAutoFormatting(true);
305 writer.writeStartDocument();
306 writer.writeStartElement("tagfile");
307 generateTagFileCompounds(writer, m_qdb->primaryTreeRoot());
308 writer.writeEndElement(); // tagfile
309 writer.writeEndDocument();
310 file.close();
311}
312
313QT_END_NAMESPACE
NodeList nonFunctionChildren() const
Returns a copy of the child nodes of this aggregate that are not function nodes, in the order they ap...
const NodeList & childNodes() const
Returns a const reference to the child list.
Definition aggregate.h:48
The Location class provides a way to mark a location in a file.
Definition location.h:20
Location()
Constructs an empty location.
Definition location.cpp:48
This class handles the generation of the QDoc tag files.
Combined button and popup list for selecting options.
The Node class is the base class for all the nodes in QDoc's parse tree.
static bool nodeNameLessThan(const Node *first, const Node *second)
Returns true if the node n1 is less than node n2.
Definition node.cpp:111
static bool nodeLessThan(const Node *first, const Node *second)
Returns true if the node n1 is less than node n2.
Definition node.cpp:79