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 if (!w.isEmpty() && w.first() == "Returns") {
158 } else {
159 if (!w.isEmpty() && w.first() == "The")
160 w.removeFirst();
161
162 if (!w.isEmpty() && (w.first() == className || w.first() == classNameOnly))
163 w.removeFirst();
164
165 if (!w.isEmpty()
166 && ((w.first() == "class") || (w.first() == "function") || (w.first() == "macro")
167 || (w.first() == "widget") || (w.first() == "namespace")
168 || (w.first() == "header")))
169 w.removeFirst();
170
171 if (!w.isEmpty() && (w.first() == "is" || w.first() == "provides"))
172 w.removeFirst();
173
174 if (!w.isEmpty() && (w.first() == "a" || w.first() == "an"))
175 w.removeFirst();
176 }
177
178 whats = w.join(' ');
179
180 if (whats.endsWith(QLatin1Char('.')))
181 whats.truncate(whats.size() - 1);
182
183 if (!whats.isEmpty())
184 whats[0] = whats[0].toUpper();
185
186 // ### move this once \brief is abolished for properties
187 resultText << whats;
188 }
189 return resultText;
190}
191
193{
194 if (m_priv == nullptr || !m_priv->m_hasLegalese)
195 return Text();
196 else
198}
199
201{
202 return m_priv == nullptr ? QSet<QString>() : m_priv->m_params;
203}
204
206{
207 return m_priv == nullptr ? QStringList() : m_priv->m_enumItemList;
208}
209
211{
212 return m_priv == nullptr ? QStringList() : m_priv->m_omitEnumItemList;
213}
214
216{
217 return m_priv == nullptr ? QSet<QString>() : m_priv->m_metacommandsUsed;
218}
219
220/*!
221 Returns true if the set of metacommands used in the doc
222 comment contains \e {internal}.
223 */
224bool Doc::isInternal() const
225{
226 return metaCommandsUsed().contains(QLatin1String("internal"));
227}
228
229/*!
230 Returns true if the set of metacommands used in the doc
231 comment contains \e {reimp}.
232 */
233bool Doc::isMarkedReimp() const
234{
235 return metaCommandsUsed().contains(QLatin1String("reimp"));
236}
237
238/*!
239 Returns true if this documentation was auto-generated by QDoc
240 rather than written by an author.
241 */
242bool Doc::isAutoGenerated() const
243{
244 return m_priv != nullptr && m_priv->m_autoGenerated;
245}
246
247/*!
248 Marks this documentation as auto-generated by QDoc.
249 */
251{
252 if (m_priv == nullptr)
253 m_priv = new DocPrivate;
254 m_priv->m_autoGenerated = true;
255}
256
257/*!
258 Returns the list of arguments passed to the \c{\overload} command.
259 */
261{
262 return metaCommandArgs(u"overload"_s);
263}
264
265/*!
266 Returns a reference to the list of topic commands used in the
267 current qdoc comment. Normally there is only one, but there
268 can be multiple \e{qmlproperty} commands, for example.
269 */
271{
272 return m_priv == nullptr ? TopicList() : m_priv->m_topics;
273}
274
275ArgList Doc::metaCommandArgs(const QString &metacommand) const
276{
277 return m_priv == nullptr ? ArgList() : m_priv->m_metaCommandMap.value(metacommand);
278}
279
281{
282 return m_priv == nullptr ? QList<Text>() : m_priv->m_alsoList;
283}
284
286{
287 return m_priv && m_priv->extra && !m_priv->extra->m_tableOfContents.isEmpty();
288}
289
290bool Doc::hasKeywords() const
291{
292 return m_priv && m_priv->extra && !m_priv->extra->m_keywords.isEmpty();
293}
294
295bool Doc::hasTargets() const
296{
297 return m_priv && m_priv->extra && !m_priv->extra->m_targets.isEmpty();
298}
299
300const QList<Atom *> &Doc::tableOfContents() const
301{
302 if (m_priv == nullptr) {
303 static const QList<Atom *> empty;
304 return empty;
305 }
306 m_priv->constructExtra();
307 return m_priv->extra->m_tableOfContents;
308}
309
310const QList<int> &Doc::tableOfContentsLevels() const
311{
312 if (m_priv == nullptr) {
313 static const QList<int> empty;
314 return empty;
315 }
316 m_priv->constructExtra();
317 return m_priv->extra->m_tableOfContentsLevels;
318}
319
320const QList<Atom *> &Doc::keywords() const
321{
322 if (m_priv == nullptr) {
323 static const QList<Atom *> empty;
324 return empty;
325 }
326 m_priv->constructExtra();
327 return m_priv->extra->m_keywords;
328}
329
330const QList<Atom *> &Doc::targets() const
331{
332 if (m_priv == nullptr) {
333 static const QList<Atom *> empty;
334 return empty;
335 }
336 m_priv->constructExtra();
337 return m_priv->extra->m_targets;
338}
339
341{
342 return m_priv && m_priv->extra ? &m_priv->extra->m_metaMap : nullptr;
343}
344
346{
347 return m_priv && m_priv->extra ? &m_priv->extra->m_comparesWithMap : nullptr;
348}
349
350void Doc::constructExtra() const
351{
352 if (m_priv)
353 m_priv->constructExtra();
354}
355
356void Doc::initialize(FileResolver& file_resolver)
357{
358 Config &config = Config::instance();
359 DocParser::initialize(config, file_resolver);
360
361 const auto &configMacros = config.subVars(CONFIG_MACRO);
362 for (const auto &macroName : configMacros) {
363 QString macroDotName = CONFIG_MACRO + Config::dot + macroName;
364 Macro macro;
365 macro.numParams = -1;
366 const auto &macroConfigVar = config.get(macroDotName);
367 macro.m_defaultDef = macroConfigVar.asString();
368 if (!macro.m_defaultDef.isEmpty()) {
369 macro.m_defaultDefLocation = macroConfigVar.location();
370 macro.numParams = Config::numParams(macro.m_defaultDef);
371 }
372 bool silent = false;
373
374 const auto &macroDotNames = config.subVars(macroDotName);
375 for (const auto &f : macroDotNames) {
376 const auto &macroSubVar = config.get(macroDotName + Config::dot + f);
377 QString def{macroSubVar.asString()};
378 if (!def.isEmpty()) {
379 macro.m_otherDefs.insert(f, def);
380 int m = Config::numParams(def);
381 if (macro.numParams == -1)
382 macro.numParams = m;
383 // .match definition is a regular expression that contains no params
384 else if (macro.numParams != m && f != QLatin1String("match")) {
385 if (!silent) {
386 QString other = QStringLiteral("default");
387 if (macro.m_defaultDef.isEmpty())
388 other = macro.m_otherDefs.constBegin().key();
389 macroSubVar.location().warning(
390 QStringLiteral("Macro '\\%1' takes inconsistent number of "
391 "arguments (%2 %3, %4 %5)")
392 .arg(macroName, f, QString::number(m), other,
393 QString::number(macro.numParams)));
394 silent = true;
395 }
396 if (macro.numParams < m)
397 macro.numParams = m;
398 }
399 }
400 }
401 if (macro.numParams != -1)
402 m_utilities.macroHash.insert(macroName, macro);
403 }
404}
405
406/*!
407 All the heap allocated variables are deleted.
408 */
410{
411 m_utilities.cmdHash.clear();
412 m_utilities.macroHash.clear();
413}
414
415/*!
416 Replaces any asterisks used as a left margin in the comment \a str with
417 spaces then trims the comment syntax from the start and end of the string,
418 leaving only the text content. Updates the \a location to refer to the
419 location of the content in the original file.
420 */
421void Doc::trimCStyleComment(Location &location, QString &str)
422{
423 QString cleaned;
424 Location m = location;
425 bool metMargin = true;
426 int marginColumn = location.columnNo() + 1;
427 int i;
428
429 for (i = 0; i < str.size(); ++i) {
430 if (m.columnNo() == marginColumn) {
431 // Stop cleaning if the expected asterisk was missing.
432 if (str[i] != '*')
433 break;
434 cleaned += ' ';
435 metMargin = true;
436 } else {
437 if (str[i] == '\n') {
438 // Break if the line ends before any asterisks are found.
439 if (!metMargin)
440 break;
441 metMargin = false;
442 }
443 cleaned += str[i];
444 }
445 m.advance(str[i]);
446 }
447 // Only replace the string if a fully cleaned version was created
448 // to avoid producing incomplete or corrupted strings.
449 if (cleaned.size() == str.size())
450 str = std::move(cleaned);
451
452 // Update the location to refer to the start of the comment text.
453 for (int i = 0; i < 3; ++i)
454 location.advance(str[i]);
455
456 // Remove the comment syntax from the start (leading comment marker
457 // and newline) and end (comment marker).
458 str = str.mid(3, str.size() - 5);
459}
460
461void Doc::quoteFromFile(const Location &location, Quoter &quoter, ResolvedFile resolved_file, CodeMarker *marker)
462{
463 // TODO: quoteFromFile should not care about modifying a stateful
464 // quoter from the outside, instead, it should produce a quoter
465 // that allows the caller to retrieve the required information
466 // about the quoted file.
467 //
468 // When changing the way in which quoting works, this kind of
469 // spread resposability should be removed, together with quoteFromFile.
470 quoter.reset();
471
472 QString code;
473 {
474 QFile input_file{resolved_file.get_path()};
475 if (!input_file.open(QFile::ReadOnly))
476 return;
477 code = DocParser::untabifyEtc(QTextStream{&input_file}.readAll());
478 }
479
480 if (!marker)
481 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: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:85
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:200
Text legaleseText() const
Definition doc.cpp:192
QList< Text > alsoList() const
Definition doc.cpp:280
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:300
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:224
bool hasTableOfContents() const
Definition doc.cpp:285
static void quoteFromFile(const Location &location, Quoter &quoter, ResolvedFile resolved_file, CodeMarker *marker=nullptr)
Definition doc.cpp:461
const QList< Atom * > & keywords() const
Definition doc.cpp:320
~Doc()
Definition doc.cpp:68
const Text & body() const
Definition doc.cpp:114
static void initialize(FileResolver &file_resolver)
Definition doc.cpp:356
bool hasKeywords() const
Definition doc.cpp:290
QStringList omitEnumItemNames() const
Definition doc.cpp:210
const QList< Atom * > & targets() const
Definition doc.cpp:330
QMultiMap< ComparisonCategory, Text > * comparesWithMap() const
Definition doc.cpp:345
const QList< int > & tableOfContentsLevels() const
Definition doc.cpp:310
bool hasTargets() const
Definition doc.cpp:295
Text trimmedBriefText(const QString &className) const
Definition doc.cpp:131
ArgList metaCommandArgs(const QString &metaCommand) const
Definition doc.cpp:275
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:233
void markAutoGenerated()
Marks this documentation as auto-generated by QDoc.
Definition doc.cpp:250
bool isAutoGenerated() const
Returns true if this documentation was auto-generated by QDoc rather than written by an author.
Definition doc.cpp:242
static void terminate()
All the heap allocated variables are deleted.
Definition doc.cpp:409
QList< ArgPair > overloadList() const
Returns the list of arguments passed to the {\overload} command.
Definition doc.cpp:260
TopicList topicsUsed() const
Returns a reference to the list of topic commands used in the current qdoc comment.
Definition doc.cpp:270
QStringMultiMap * metaTagMap() const
Definition doc.cpp:340
QSet< QString > metaCommandsUsed() const
Definition doc.cpp:215
bool isEmpty() const
Definition doc.cpp:109
Doc(const Doc &doc)
Definition doc.cpp:63
void constructExtra() const
Definition doc.cpp:350
const QString & source() const
Definition doc.cpp:103
QStringList enumItemNames() const
Definition doc.cpp:205
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:413
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