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