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