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