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
codemarker.cpp
Go to the documentation of this file.
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#include "codemarker.h"
5
6#include "classnode.h"
7#include "config.h"
8#include "functionnode.h"
9#include "node.h"
10#include "propertynode.h"
12
13#include <QtCore/qobjectdefs.h>
14
16
17using namespace Qt::StringLiterals;
18
19QString CodeMarker::s_defaultLang;
20QList<CodeMarker *> CodeMarker::s_markers;
21
22
23/*!
24 When a code marker constructs itself, it puts itself into
25 the static list of code markers. All the code markers in
26 the static list get initialized in initialize(), which is
27 not called until after the qdoc configuration file has
28 been read.
29 */
31{
32 s_markers.prepend(this);
33}
34
35/*!
36 When a code marker destroys itself, it removes itself from
37 the static list of code markers.
38 */
40{
41 s_markers.removeAll(this);
42}
43
44/*!
45 A code market performs no initialization by default. Marker-specific
46 initialization is performed in subclasses.
47 */
49
50/*!
51 Terminating a code marker is trivial.
52 */
54{
55 // nothing.
56}
57
58/*!
59 All the code markers in the static list are initialized
60 here, after the qdoc configuration file has been loaded.
61 */
63{
64 s_defaultLang = Config::instance().get(CONFIG_LANGUAGE).asString();
65 for (const auto &marker : std::as_const(s_markers))
66 marker->initializeMarker();
67}
68
69/*!
70 All the code markers in the static list are terminated here.
71 */
73{
74 for (const auto &marker : std::as_const(s_markers))
75 marker->terminateMarker();
76}
77
78CodeMarker *CodeMarker::markerForCode(const QString &code)
79{
80 CodeMarker *defaultMarker = markerForLanguage(s_defaultLang);
81 if (defaultMarker != nullptr && defaultMarker->recognizeCode(code))
82 return defaultMarker;
83
84 for (const auto &marker : std::as_const(s_markers)) {
85 if (marker->recognizeCode(code))
86 return marker;
87 }
88
89 return defaultMarker;
90}
91
92CodeMarker *CodeMarker::markerForFileName(const QString &fileName)
93{
94 CodeMarker *defaultMarker = markerForLanguage(s_defaultLang);
95 qsizetype dot = -1;
96 while ((dot = fileName.lastIndexOf(QLatin1Char('.'), dot)) != -1) {
97 QString ext = fileName.mid(dot + 1);
98 if (defaultMarker != nullptr && defaultMarker->recognizeExtension(ext))
99 return defaultMarker;
100 for (const auto &marker : std::as_const(s_markers)) {
101 if (marker->recognizeExtension(ext))
102 return marker;
103 }
104 --dot;
105 }
106 return defaultMarker;
107}
108
109CodeMarker *CodeMarker::markerForLanguage(const QString &lang)
110{
111 for (const auto &marker : std::as_const(s_markers)) {
112 if (marker->recognizeLanguage(lang))
113 return marker;
114 }
115 return nullptr;
116}
117
118const Node *CodeMarker::nodeForString(const QString &string)
119{
120#if QT_POINTER_SIZE == 4
121 const quintptr n = string.toUInt();
122#else
123 const quintptr n = string.toULongLong();
124#endif
125 return reinterpret_cast<const Node *>(n);
126}
127
128QString CodeMarker::stringForNode(const Node *node)
129{
130 return QString::number(reinterpret_cast<quintptr>(node));
131}
132
133/*!
134 Returns a string representing the \a node status, set using \preliminary, \since,
135 and \deprecated commands.
136
137 If a string is returned, it is one of:
138 \list
139 \li \c {"preliminary"}
140 \li \c {"since <version_since>, deprecated in <version_deprecated>"}
141 \li \c {"since <version_since>, until <version_deprecated>"}
142 \li \c {"since <version_since>"}
143 \li \c {"since <version_since>, deprecated"}
144 \li \c {"deprecated in <version_deprecated>"}
145 \li \c {"until <version_deprecated>"}
146 \li \c {"deprecated"}
147 \endlist
148
149 If \a node has no related status information, returns std::nullopt.
150*/
152{
153 if (node->isPreliminary())
154 return std::optional(u"preliminary"_s);
155
156 QStringList result;
157 if (const auto &since = node->since(); !since.isEmpty())
158 result << "since %1"_L1.arg(since);
159 if (const auto &deprecated = node->deprecatedSince(); !deprecated.isEmpty()) {
160 if (node->isDeprecated())
161 result << "deprecated in %1"_L1.arg(deprecated);
162 else
163 result << "until %1"_L1.arg(deprecated);
164 } else if (node->isDeprecated()) {
165 result << u"deprecated"_s;
166 }
167
168 return result.isEmpty() ? std::nullopt : std::optional(result.join(u", "_s));
169}
170
171/*!
172 Returns the 'extra' synopsis string for \a node with status information,
173 using a specified section \a style.
174*/
175QString CodeMarker::extraSynopsis(const Node *node, Section::Style style)
176{
177 if (style != Section::Summary && style != Section::Details)
178 return {};
179
180 QStringList extra;
181 if (style == Section::Details) {
182 switch (node->nodeType()) {
183 case Node::Function: {
184 const auto *func = static_cast<const FunctionNode *>(node);
185 if (func->isStatic()) {
186 extra << "static";
187 } else if (!func->isNonvirtual()) {
188 if (func->isFinal())
189 extra << "final";
190 if (func->isOverride())
191 extra << "override";
192 if (func->isPureVirtual())
193 extra << "pure";
194 extra << "virtual";
195 }
196
197 if (func->isExplicit()) extra << "explicit";
198 if (func->isConstexpr()) extra << "constexpr";
199 if (auto noexcept_info = func->getNoexcept()) {
200 extra << (QString("noexcept") + (!(*noexcept_info).isEmpty() ? "(...)" : ""));
201 }
202
203 if (func->access() == Access::Protected)
204 extra << "protected";
205 else if (func->access() == Access::Private)
206 extra << "private";
207
208 if (func->isSignal()) {
210 extra << "private";
211 extra << "signal";
212 } else if (func->isSlot())
213 extra << "slot";
214 else if (func->isDefault())
215 extra << "default";
216 else if (func->isInvokable())
217 extra << "invokable";
218 }
219 break;
220 case Node::TypeAlias:
221 extra << "alias";
222 break;
223 case Node::Property: {
224 auto propertyNode = static_cast<const PropertyNode *>(node);
226 extra << "bindable";
227 if (!propertyNode->isWritable())
228 extra << "read-only";
229 }
230 break;
231 case Node::QmlProperty: {
232 auto qmlProperty = static_cast<const QmlPropertyNode *>(node);
233 if (qmlProperty->isDefault())
234 extra << u"default"_s;
235 // Call non-const overloads to ensure attributes are fetched from
236 // associated C++ properties
237 else if (const_cast<QmlPropertyNode *>(qmlProperty)->isReadOnly())
238 extra << u"read-only"_s;
239 else if (const_cast<QmlPropertyNode *>(qmlProperty)->isRequired())
240 extra << u"required"_s;
241 else if (!qmlProperty->defaultValue().isEmpty()) {
242 extra << u"default: "_s + qmlProperty->defaultValue();
243 }
244 break;
245 }
246 default:
247 break;
248 }
249 }
250
251 // Add status for both Summary and Details
252 if (auto status = nodeStatusAsString(node)) {
253 if (!extra.isEmpty())
254 extra.last() += ','_L1;
255 extra << *status;
256 }
257
258 QString extraStr = extra.join(QLatin1Char(' '));
259 if (!extraStr.isEmpty()) {
260 extraStr.prepend(style == Section::Details ? '[' : '(');
261 extraStr.append(style == Section::Details ? ']' : ')');
262 }
263
264 return extraStr;
265}
266
267static const QString samp = QLatin1String("&amp;");
268static const QString slt = QLatin1String("&lt;");
269static const QString sgt = QLatin1String("&gt;");
270static const QString squot = QLatin1String("&quot;");
271
272QString CodeMarker::protect(const QString &str)
273{
274 qsizetype n = str.size();
275 QString marked;
276 marked.reserve(n * 2 + 30);
277 const QChar *data = str.constData();
278 for (int i = 0; i != n; ++i) {
279 switch (data[i].unicode()) {
280 case '&':
281 marked += samp;
282 break;
283 case '<':
284 marked += slt;
285 break;
286 case '>':
287 marked += sgt;
288 break;
289 case '"':
290 marked += squot;
291 break;
292 default:
293 marked += data[i];
294 }
295 }
296 return marked;
297}
298
299void CodeMarker::appendProtectedString(QString *output, QStringView str)
300{
301 qsizetype n = str.size();
302 output->reserve(output->size() + n * 2 + 30);
303 const QChar *data = str.constData();
304 for (int i = 0; i != n; ++i) {
305 switch (data[i].unicode()) {
306 case '&':
307 *output += samp;
308 break;
309 case '<':
310 *output += slt;
311 break;
312 case '>':
313 *output += sgt;
314 break;
315 case '"':
316 *output += squot;
317 break;
318 default:
319 *output += data[i];
320 }
321 }
322}
323
324QString CodeMarker::typified(const QString &string, bool trailingSpace)
325{
326 QString result;
327 QString pendingWord;
328
329 for (int i = 0; i <= string.size(); ++i) {
330 QChar ch;
331 if (i != string.size())
332 ch = string.at(i);
333
334 QChar lower = ch.toLower();
335 if ((lower >= QLatin1Char('a') && lower <= QLatin1Char('z')) || ch.digitValue() >= 0
336 || ch == QLatin1Char('_') || ch == QLatin1Char(':')) {
337 pendingWord += ch;
338 } else {
339 if (!pendingWord.isEmpty()) {
340 bool isProbablyType = (pendingWord != QLatin1String("const"));
341 if (isProbablyType)
342 result += QLatin1String("<@type>");
343 result += pendingWord;
344 if (isProbablyType)
345 result += QLatin1String("</@type>");
346 }
347 pendingWord.clear();
348
349 switch (ch.unicode()) {
350 case '\0':
351 break;
352 case '&':
353 result += QLatin1String("&amp;");
354 break;
355 case '<':
356 result += QLatin1String("&lt;");
357 break;
358 case '>':
359 result += QLatin1String("&gt;");
360 break;
361 default:
362 result += ch;
363 }
364 }
365 }
366 if (trailingSpace && string.size()) {
367 if (!string.endsWith(QLatin1Char('*')) && !string.endsWith(QLatin1Char('&')))
368 result += QLatin1Char(' ');
369 }
370 return result;
371}
372
374{
375 QString tag;
376 const QString &name = node->name();
377
378 switch (node->nodeType()) {
379 case Node::Namespace:
380 tag = QLatin1String("@namespace");
381 break;
382 case Node::Class:
383 case Node::Struct:
384 case Node::Union:
385 tag = QLatin1String("@class");
386 break;
387 case Node::Enum:
388 tag = QLatin1String("@enum");
389 break;
390 case Node::TypeAlias:
391 case Node::Typedef:
392 tag = QLatin1String("@typedef");
393 break;
394 case Node::Function:
395 tag = QLatin1String("@function");
396 break;
397 case Node::Property:
398 tag = QLatin1String("@property");
399 break;
400 case Node::QmlType:
401 tag = QLatin1String("@property");
402 break;
403 case Node::Page:
404 tag = QLatin1String("@property");
405 break;
406 default:
407 tag = QLatin1String("@unknown");
408 break;
409 }
410 return (QLatin1Char('<') + tag + QLatin1Char('>') + protect(name) + QLatin1String("</") + tag
411 + QLatin1Char('>'));
412}
413
415{
416 QString tag;
417 if (node->isFunction()) {
418 const auto *fn = static_cast<const FunctionNode *>(node);
419 switch (fn->metaness()) {
421 tag = QLatin1String("@signal");
422 break;
424 tag = QLatin1String("@signalhandler");
425 break;
427 tag = QLatin1String("@method");
428 break;
429 default:
430 tag = QLatin1String("@unknown");
431 break;
432 }
433 } else if (node->isQmlProperty()) {
434 tag = QLatin1String("@property");
435 } else {
436 tag = QLatin1String("@unknown");
437 }
438 return QLatin1Char('<') + tag + QLatin1Char('>') + protect(node->name()) + QLatin1String("</")
439 + tag + QLatin1Char('>');
440}
441
442QString CodeMarker::linkTag(const Node *node, const QString &body)
443{
444 return QLatin1String("<@link node=\"") + stringForNode(node) + QLatin1String("\">") + body
445 + QLatin1String("</@link>");
446}
447
448QT_END_NAMESPACE
QString typified(const QString &string, bool trailingSpace=false)
CodeMarker()
When a code marker constructs itself, it puts itself into the static list of code markers.
virtual void initializeMarker()
A code market performs no initialization by default.
static void initialize()
All the code markers in the static list are initialized here, after the qdoc configuration file has b...
QString taggedQmlNode(const Node *node)
virtual ~CodeMarker()
When a code marker destroys itself, it removes itself from the static list of code markers.
virtual void terminateMarker()
Terminating a code marker is trivial.
static void terminate()
All the code markers in the static list are terminated here.
QString linkTag(const Node *node, const QString &body)
QString taggedNode(const Node *node)
This node is used to represent any kind of function being documented.
bool isOverride() const
const Parameters & parameters() const
bool isConstexpr() const
bool isNonvirtual() const
bool isInvokable() const
bool isDefault() const override
Returns true if the QML property node is marked as default.
bool isPureVirtual() const
bool isExplicit() const
bool isSignal() const
bool isStatic() const override
Returns true if the FunctionNode represents a static function.
bool isFinal() const
bool isSlot() const
Metaness metaness() const
@ Struct
Definition node.h:58
@ Typedef
Definition node.h:66
@ Function
Definition node.h:65
@ TypeAlias
Definition node.h:67
@ Union
Definition node.h:59
@ Page
Definition node.h:61
@ Enum
Definition node.h:62
@ QmlProperty
Definition node.h:74
@ QmlType
Definition node.h:72
@ Namespace
Definition node.h:56
@ Property
Definition node.h:68
@ Class
Definition node.h:57
bool isFunction(Genus g=DontCare) const
Returns true if this is a FunctionNode and its Genus is set to g.
Definition node.h:135
virtual bool isDeprecated() const
Returns true if this node's status is Deprecated.
Definition node.h:168
NodeType nodeType() const
Returns this node's type.
Definition node.h:121
Access access() const
Returns the node's Access setting, which can be Public, Protected, or Private.
Definition node.h:264
LinkType
An unsigned char value that probably should be moved out of the Node base class.
Definition node.h:112
bool isQmlProperty() const
Returns true if the node type is QmlProperty.
Definition node.h:154
bool isPrivateSignal() const
Definition parameters.h:69
This class describes one instance of using the Q_PROPERTY macro.
PropertyType propertyType() const
bool isWritable() const
bool isDefault() const override
Returns true if the QML property node is marked as default.
bool isRequired()
Returns true if this QML property is marked with \required or the corresponding C++ property uses the...
bool isReadOnly()
Returns true if this QML property or attached property is read-only.
A class for containing the elements of one documentation section.
Definition sections.h:17
@ Summary
Definition sections.h:19
@ Details
Definition sections.h:19
static const QString slt
static const QString sgt
static std::optional< QString > nodeStatusAsString(const Node *node)
Returns a string representing the node status, set using \preliminary,.
static const QString samp
static const QString squot
#define CONFIG_LANGUAGE
Definition config.h:359
Combined button and popup list for selecting options.