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.
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:59