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
doc.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 "doc.h"
5
6#include "atom.h"
7#include "config.h"
8#include "codemarker.h"
9#include "docparser.h"
10#include "docprivate.h"
11#include "generator.h"
12#include "qmltypenode.h"
13#include "quoter.h"
14#include "text.h"
15#include "utilities.h"
16
17#include <qcryptographichash.h>
18
20
21using namespace Qt::StringLiterals;
22
23DocUtilities &Doc::m_utilities = DocUtilities::instance();
24
25/*!
26 \typedef ArgList
27 \relates Doc
28
29 A list of metacommand arguments that appear in a Doc. Each entry
30 in the list is a <QString, QString> pair (ArgPair):
31
32 \list
33 \li \c {ArgPair.first} - arguments passed to the command.
34 \li \c {ArgPair.second} - optional argument string passed
35 within brackets immediately following the command.
36 \endlist
37*/
38
39/*!
40 Parse the qdoc comment \a source. Build up a list of all the topic
41 commands found including their arguments. This constructor is used
42 when there can be more than one topic command in theqdoc comment.
43 Normally, there is only one topic command in a qdoc comment, but in
44 QML documentation, there is the case where the qdoc \e{qmlproperty}
45 command can appear multiple times in a qdoc comment.
46 */
47Doc::Doc(const Location &start_loc, const Location &end_loc, const QString &source,
48 const QSet<QString> &metaCommandSet, const QSet<QString> &topics)
49{
50 m_priv = new DocPrivate(start_loc, end_loc, source);
51 DocParser parser;
52 parser.parse(source, m_priv, metaCommandSet, topics);
53
54 if (Config::instance().getAtomsDump()) {
55 start_loc.information(u"==== Atoms Structure for block comment starting at %1 ===="_s.arg(
56 start_loc.toString()));
58 end_loc.information(
59 u"==== Ending atoms Structure for block comment ending at %1 ===="_s.arg(
60 end_loc.toString()));
61 }
62}
63
64Doc::Doc(const Doc &doc) : m_priv(nullptr)
65{
66 operator=(doc);
67}
68
70{
71 if (m_priv && m_priv->deref())
72 delete m_priv;
73}
74
75Doc &Doc::operator=(const Doc &doc)
76{
77 if (&doc == this)
78 return *this;
79 if (doc.m_priv)
80 doc.m_priv->ref();
81 if (m_priv && m_priv->deref())
82 delete m_priv;
83 m_priv = doc.m_priv;
84 return *this;
85}
86
87/*!
88 Returns the starting location of a qdoc comment.
89 */
90const Location &Doc::location() const
91{
92 static const Location dummy;
93 return m_priv == nullptr ? dummy : m_priv->m_start_loc;
94}
95
96/*!
97 Returns the starting location of a qdoc comment.
98 */
99const Location &Doc::startLocation() const
100{
101 return location();
102}
103
104const QString &Doc::source() const
105{
106 static QString null;
107 return m_priv == nullptr ? null : m_priv->m_src;
108}
109
110bool Doc::isEmpty() const
111{
112 return m_priv == nullptr || m_priv->m_src.isEmpty();
113}
114
115const Text &Doc::body() const
116{
117 static const Text dummy;
118 return m_priv == nullptr ? dummy : m_priv->m_text;
119}
120
121const Text &Doc::title() const
122{
123 static const Text dummy;
124 return m_priv == nullptr ? dummy : m_priv->m_title;
125}
126
127Text Doc::briefText(bool inclusive) const
128{
130}
131
132Text Doc::trimmedBriefText(const QString &className) const
133{
134 QString classNameOnly = className;
135 if (className.contains("::"))
136 classNameOnly = className.split("::").last();
137
138 Text originalText = briefText();
139 Text resultText;
140 const Atom *atom = originalText.firstAtom();
141 if (atom) {
142 QString briefStr;
143 QString whats;
144 /*
145 This code is really ugly. The entire \brief business
146 should be rethought.
147 */
148 while (atom) {
149 if (atom->type() == Atom::AutoLink || atom->type() == Atom::String) {
150 briefStr += atom->string();
151 } else if (atom->type() == Atom::C) {
152 briefStr += Generator::plainCode(atom->string());
153 }
154 atom = atom->next();
155 }
156
157 QStringList w = briefStr.split(QLatin1Char(' '));
158 if (!w.isEmpty() && w.first() == "Returns") {
159 } else {
160 if (!w.isEmpty() && w.first() == "The")
161 w.removeFirst();
162
163 if (!w.isEmpty() && (w.first() == className || w.first() == classNameOnly))
164 w.removeFirst();
165
166 if (!w.isEmpty()
167 && ((w.first() == "class") || (w.first() == "function") || (w.first() == "macro")
168 || (w.first() == "widget") || (w.first() == "namespace")
169 || (w.first() == "header")))
170 w.removeFirst();
171
172 if (!w.isEmpty() && (w.first() == "is" || w.first() == "provides"))
173 w.removeFirst();
174
175 if (!w.isEmpty() && (w.first() == "a" || w.first() == "an"))
176 w.removeFirst();
177 }
178
179 whats = w.join(' ');
180
181 if (whats.endsWith(QLatin1Char('.')))
182 whats.truncate(whats.size() - 1);
183
184 if (!whats.isEmpty())
185 whats[0] = whats[0].toUpper();
186
187 // ### move this once \brief is abolished for properties
188 resultText << whats;
189 }
190 return resultText;
191}
192
194{
195 if (m_priv == nullptr || !m_priv->m_hasLegalese)
196 return Text();
197 else
199}
200
202{
203 return m_priv == nullptr ? QSet<QString>() : m_priv->m_params;
204}
205
207{
208 return m_priv == nullptr ? QStringList() : m_priv->m_enumItemList;
209}
210
212{
213 return m_priv == nullptr ? QStringList() : m_priv->m_omitEnumItemList;
214}
215
217{
218 return m_priv == nullptr ? QSet<QString>() : m_priv->m_metacommandsUsed;
219}
220
221/*!
222 Returns true if the set of metacommands used in the doc
223 comment contains \e {internal}.
224 */
225bool Doc::isInternal() const
226{
227 return metaCommandsUsed().contains(QLatin1String("internal"));
228}
229
230/*!
231 Returns true if the set of metacommands used in the doc
232 comment contains \e {reimp}.
233 */
234bool Doc::isMarkedReimp() const
235{
236 return metaCommandsUsed().contains(QLatin1String("reimp"));
237}
238
239/*!
240 Returns true if this documentation was auto-generated by QDoc
241 rather than written by an author.
242 */
243bool Doc::isAutoGenerated() const
244{
245 return m_priv != nullptr && m_priv->m_autoGenerated;
246}
247
248/*!
249 Marks this documentation as auto-generated by QDoc.
250 */
252{
253 if (m_priv == nullptr)
254 m_priv = new DocPrivate;
255 m_priv->m_autoGenerated = true;
256}
257
258/*!
259 Returns the list of arguments passed to the \c{\overload} command.
260 */
262{
263 return metaCommandArgs(u"overload"_s);
264}
265
266/*!
267 Returns a reference to the list of topic commands used in the
268 current qdoc comment. Normally there is only one, but there
269 can be multiple \e{qmlproperty} commands, for example.
270 */
272{
273 return m_priv == nullptr ? TopicList() : m_priv->m_topics;
274}
275
276ArgList Doc::metaCommandArgs(const QString &metacommand) const
277{
278 return m_priv == nullptr ? ArgList() : m_priv->m_metaCommandMap.value(metacommand);
279}
280
282{
283 return m_priv == nullptr ? QList<Text>() : m_priv->m_alsoList;
284}
285
287{
288 return m_priv && m_priv->extra && !m_priv->extra->m_tableOfContents.isEmpty();
289}
290
291bool Doc::hasKeywords() const
292{
293 return m_priv && m_priv->extra && !m_priv->extra->m_keywords.isEmpty();
294}
295
296bool Doc::hasTargets() const
297{
298 return m_priv && m_priv->extra && !m_priv->extra->m_targets.isEmpty();
299}
300
301const QList<Atom *> &Doc::tableOfContents() const
302{
303 if (m_priv == nullptr) {
304 static const QList<Atom *> empty;
305 return empty;
306 }
307 m_priv->constructExtra();
308 return m_priv->extra->m_tableOfContents;
309}
310
311const QList<int> &Doc::tableOfContentsLevels() const
312{
313 if (m_priv == nullptr) {
314 static const QList<int> empty;
315 return empty;
316 }
317 m_priv->constructExtra();
318 return m_priv->extra->m_tableOfContentsLevels;
319}
320
321const QList<Atom *> &Doc::keywords() const
322{
323 if (m_priv == nullptr) {
324 static const QList<Atom *> empty;
325 return empty;
326 }
327 m_priv->constructExtra();
328 return m_priv->extra->m_keywords;
329}
330
331const QList<Atom *> &Doc::targets() const
332{
333 if (m_priv == nullptr) {
334 static const QList<Atom *> empty;
335 return empty;
336 }
337 m_priv->constructExtra();
338 return m_priv->extra->m_targets;
339}
340
342{
343 return m_priv && m_priv->extra ? &m_priv->extra->m_metaMap : nullptr;
344}
345
347{
348 return m_priv && m_priv->extra ? &m_priv->extra->m_comparesWithMap : nullptr;
349}
350
351void Doc::constructExtra() const
352{
353 if (m_priv)
354 m_priv->constructExtra();
355}
356
357void Doc::initialize(FileResolver& file_resolver)
358{
359 Config &config = Config::instance();
360 DocParser::initialize(config, file_resolver);
361
362 const auto &configMacros = config.subVars(CONFIG_MACRO);
363 for (const auto &macroName : configMacros) {
364 QString macroDotName = CONFIG_MACRO + Config::dot + macroName;
365 Macro macro;
366 macro.numParams = -1;
367 const auto &macroConfigVar = config.get(macroDotName);
368 macro.m_defaultDef = macroConfigVar.asString();
369 if (!macro.m_defaultDef.isEmpty()) {
370 macro.m_defaultDefLocation = macroConfigVar.location();
371 macro.numParams = Config::numParams(macro.m_defaultDef);
372 }
373 bool silent = false;
374
375 const auto &macroDotNames = config.subVars(macroDotName);
376 for (const auto &f : macroDotNames) {
377 const auto &macroSubVar = config.get(macroDotName + Config::dot + f);
378 QString def{macroSubVar.asString()};
379 if (!def.isEmpty()) {
380 macro.m_otherDefs.insert(f, def);
381 int m = Config::numParams(def);
382 if (macro.numParams == -1)
383 macro.numParams = m;
384 // .match definition is a regular expression that contains no params
385 else if (macro.numParams != m && f != QLatin1String("match")) {
386 if (!silent) {
387 QString other = QStringLiteral("default");
388 if (macro.m_defaultDef.isEmpty())
389 other = macro.m_otherDefs.constBegin().key();
390 macroSubVar.location().warning(
391 QStringLiteral("Macro '\\%1' takes inconsistent number of "
392 "arguments (%2 %3, %4 %5)")
393 .arg(macroName, f, QString::number(m), other,
394 QString::number(macro.numParams)));
395 silent = true;
396 }
397 if (macro.numParams < m)
398 macro.numParams = m;
399 }
400 }
401 }
402 if (macro.numParams != -1)
403 m_utilities.macroHash.insert(macroName, macro);
404 }
405}
406
407/*!
408 All the heap allocated variables are deleted.
409 */
411{
412 m_utilities.cmdHash.clear();
413 m_utilities.macroHash.clear();
414}
415
416/*!
417 Replaces any asterisks used as a left margin in the comment \a str with
418 spaces then trims the comment syntax from the start and end of the string,
419 leaving only the text content. Updates the \a location to refer to the
420 location of the content in the original file.
421 */
422void Doc::trimCStyleComment(Location &location, QString &str)
423{
424 QString cleaned;
425 Location m = location;
426 bool metMargin = true;
427 int marginColumn = location.columnNo() + 1;
428 int i;
429
430 for (i = 0; i < str.size(); ++i) {
431 if (m.columnNo() == marginColumn) {
432 // Stop cleaning if the expected asterisk was missing.
433 if (str[i] != '*')
434 break;
435 cleaned += ' ';
436 metMargin = true;
437 } else {
438 if (str[i] == '\n') {
439 // Break if the line ends before any asterisks are found.
440 if (!metMargin)
441 break;
442 metMargin = false;
443 }
444 cleaned += str[i];
445 }
446 m.advance(str[i]);
447 }
448 // Only replace the string if a fully cleaned version was created
449 // to avoid producing incomplete or corrupted strings.
450 if (cleaned.size() == str.size())
451 str = std::move(cleaned);
452
453 // Update the location to refer to the start of the comment text.
454 for (int i = 0; i < 3; ++i)
455 location.advance(str[i]);
456
457 // Remove the comment syntax from the start (leading comment marker
458 // and newline) and end (comment marker).
459 str = str.mid(3, str.size() - 5);
460}
461
462void Doc::quoteFromFile(const Location &location, Quoter &quoter, ResolvedFile resolved_file)
463{
464 // TODO: quoteFromFile should not care about modifying a stateful
465 // quoter from the outside, instead, it should produce a quoter
466 // that allows the caller to retrieve the required information
467 // about the quoted file.
468 //
469 // When changing the way in which quoting works, this kind of
470 // spread resposability should be removed, together with quoteFromFile.
471 quoter.reset();
472
473 QString code;
474 {
475 QFile input_file{resolved_file.get_path()};
476 if (!input_file.open(QFile::ReadOnly))
477 return;
478 code = DocParser::untabifyEtc(QTextStream{&input_file}.readAll());
479 }
480
481 CodeMarker *marker = CodeMarker::markerForFileName(resolved_file.get_path());
482 quoter.quoteFromFile(resolved_file.get_path(), code, marker->markedUpCode(code, nullptr, location));
483}
484
485QT_END_NAMESPACE
The Atom class is the fundamental unit for representing documents internally.
Definition atom.h:19
AtomType type() const
Return the type of this atom.
Definition atom.h:153
@ BriefRight
Definition atom.h:27
@ LegaleseRight
Definition atom.h:59
@ String
Definition atom.h:93
@ BriefLeft
Definition atom.h:26
@ LegaleseLeft
Definition atom.h:58
@ C
Definition atom.h:28
@ AutoLink
Definition atom.h:23
const Atom * next() const
Return the next atom in the atom list.
Definition atom.h:150
The Config class contains the configuration variables for controlling how qdoc produces documentation...
Definition config.h:85
static void initialize(const Config &config, FileResolver &file_resolver)
void ref()
Definition docprivate.h:53
bool m_autoGenerated
Definition docprivate.h:73
Text m_title
Definition docprivate.h:62
DocPrivateExtra * extra
Definition docprivate.h:69
void constructExtra()
Text m_text
Definition docprivate.h:61
bool m_hasLegalese
Definition docprivate.h:72
bool deref()
Definition docprivate.h:54
TopicList m_topics
Definition docprivate.h:70
CommandMap m_metaCommandMap
Definition docprivate.h:68
Definition doc.h:31
QSet< QString > parameterNames() const
Definition doc.cpp:201
Text legaleseText() const
Definition doc.cpp:193
QList< Text > alsoList() const
Definition doc.cpp:281
const Location & location() const
Returns the starting location of a qdoc comment.
Definition doc.cpp:90
Doc & operator=(const Doc &doc)
Definition doc.cpp:75
Doc(const Location &start_loc, const Location &end_loc, const QString &source, const QSet< QString > &metaCommandSet, const QSet< QString > &topics)
Parse the qdoc comment source.
Definition doc.cpp:47
const QList< Atom * > & tableOfContents() const
Definition doc.cpp:301
static void quoteFromFile(const Location &location, Quoter &quoter, ResolvedFile resolved_file)
Definition doc.cpp:462
const Text & title() const
Definition doc.cpp:121
bool isInternal() const
Returns true if the set of metacommands used in the doc comment contains {internal}...
Definition doc.cpp:225
bool hasTableOfContents() const
Definition doc.cpp:286
const QList< Atom * > & keywords() const
Definition doc.cpp:321
~Doc()
Definition doc.cpp:69
const Text & body() const
Definition doc.cpp:115
static void initialize(FileResolver &file_resolver)
Definition doc.cpp:357
bool hasKeywords() const
Definition doc.cpp:291
QStringList omitEnumItemNames() const
Definition doc.cpp:211
const QList< Atom * > & targets() const
Definition doc.cpp:331
QMultiMap< ComparisonCategory, Text > * comparesWithMap() const
Definition doc.cpp:346
const QList< int > & tableOfContentsLevels() const
Definition doc.cpp:311
bool hasTargets() const
Definition doc.cpp:296
Text trimmedBriefText(const QString &className) const
Definition doc.cpp:132
ArgList metaCommandArgs(const QString &metaCommand) const
Definition doc.cpp:276
Text briefText(bool inclusive=false) const
Definition doc.cpp:127
const Location & startLocation() const
Returns the starting location of a qdoc comment.
Definition doc.cpp:99
bool isMarkedReimp() const
Returns true if the set of metacommands used in the doc comment contains {reimp}.
Definition doc.cpp:234
void markAutoGenerated()
Marks this documentation as auto-generated by QDoc.
Definition doc.cpp:251
bool isAutoGenerated() const
Returns true if this documentation was auto-generated by QDoc rather than written by an author.
Definition doc.cpp:243
static void terminate()
All the heap allocated variables are deleted.
Definition doc.cpp:410
QList< ArgPair > overloadList() const
Returns the list of arguments passed to the {\overload} command.
Definition doc.cpp:261
TopicList topicsUsed() const
Returns a reference to the list of topic commands used in the current qdoc comment.
Definition doc.cpp:271
QStringMultiMap * metaTagMap() const
Definition doc.cpp:341
QSet< QString > metaCommandsUsed() const
Definition doc.cpp:216
bool isEmpty() const
Definition doc.cpp:110
Doc(const Doc &doc)
Definition doc.cpp:64
void constructExtra() const
Definition doc.cpp:351
const QString & source() const
Definition doc.cpp:104
QStringList enumItemNames() const
Definition doc.cpp:206
Encapsulate the logic that QDoc uses to find files whose path is provided by the user and that are re...
The Location class provides a way to mark a location in a file.
Definition location.h:20
int columnNo() const
Returns the current column number.
Definition location.h:51
Definition text.h:12
void dump() const
Prints a human-readable version of the contained atoms to stderr.
Definition text.cpp:225
Text subText(Atom::AtomType left, Atom::AtomType right, const Atom *from=nullptr, bool inclusive=false) const
Definition text.cpp:153
Atom * firstAtom()
Definition text.h:21
Text()
Definition text.cpp:12
#define CONFIG_MACRO
Definition config.h:411
QList< ArgPair > ArgList
Definition doc.h:27
QMultiMap< QString, QString > QStringMultiMap
Definition doc.h:28
Combined button and popup list for selecting options.
QStringMultiMap m_metaMap
Definition docprivate.h:39
QHash_QString_Macro macroHash
QHash_QString_int cmdHash
Represents a file that is reachable by QDoc based on its current configuration.
QList< Topic > TopicList
Definition topic.h:25