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 a reference to the list of topic commands used in the
235 current qdoc comment. Normally there is only one, but there
236 can be multiple \e{qmlproperty} commands, for example.
237 */
239{
240 return m_priv == nullptr ? TopicList() : m_priv->m_topics;
241}
242
243ArgList Doc::metaCommandArgs(const QString &metacommand) const
244{
245 return m_priv == nullptr ? ArgList() : m_priv->m_metaCommandMap.value(metacommand);
246}
247
249{
250 return m_priv == nullptr ? QList<Text>() : m_priv->m_alsoList;
251}
252
254{
255 return m_priv && m_priv->extra && !m_priv->extra->m_tableOfContents.isEmpty();
256}
257
258bool Doc::hasKeywords() const
259{
260 return m_priv && m_priv->extra && !m_priv->extra->m_keywords.isEmpty();
261}
262
263bool Doc::hasTargets() const
264{
265 return m_priv && m_priv->extra && !m_priv->extra->m_targets.isEmpty();
266}
267
268const QList<Atom *> &Doc::tableOfContents() const
269{
270 m_priv->constructExtra();
271 return m_priv->extra->m_tableOfContents;
272}
273
274const QList<int> &Doc::tableOfContentsLevels() const
275{
276 m_priv->constructExtra();
277 return m_priv->extra->m_tableOfContentsLevels;
278}
279
280const QList<Atom *> &Doc::keywords() const
281{
282 m_priv->constructExtra();
283 return m_priv->extra->m_keywords;
284}
285
286const QList<Atom *> &Doc::targets() const
287{
288 m_priv->constructExtra();
289 return m_priv->extra->m_targets;
290}
291
293{
294 return m_priv && m_priv->extra ? &m_priv->extra->m_metaMap : nullptr;
295}
296
298{
299 return m_priv && m_priv->extra ? &m_priv->extra->m_comparesWithMap : nullptr;
300}
301
302void Doc::constructExtra() const
303{
304 if (m_priv)
305 m_priv->constructExtra();
306}
307
308void Doc::initialize(FileResolver& file_resolver)
309{
310 Config &config = Config::instance();
311 DocParser::initialize(config, file_resolver);
312
313 const auto &configMacros = config.subVars(CONFIG_MACRO);
314 for (const auto &macroName : configMacros) {
315 QString macroDotName = CONFIG_MACRO + Config::dot + macroName;
316 Macro macro;
317 macro.numParams = -1;
318 const auto &macroConfigVar = config.get(macroDotName);
319 macro.m_defaultDef = macroConfigVar.asString();
320 if (!macro.m_defaultDef.isEmpty()) {
321 macro.m_defaultDefLocation = macroConfigVar.location();
322 macro.numParams = Config::numParams(macro.m_defaultDef);
323 }
324 bool silent = false;
325
326 const auto &macroDotNames = config.subVars(macroDotName);
327 for (const auto &f : macroDotNames) {
328 const auto &macroSubVar = config.get(macroDotName + Config::dot + f);
329 QString def{macroSubVar.asString()};
330 if (!def.isEmpty()) {
331 macro.m_otherDefs.insert(f, def);
332 int m = Config::numParams(def);
333 if (macro.numParams == -1)
334 macro.numParams = m;
335 // .match definition is a regular expression that contains no params
336 else if (macro.numParams != m && f != QLatin1String("match")) {
337 if (!silent) {
338 QString other = QStringLiteral("default");
339 if (macro.m_defaultDef.isEmpty())
340 other = macro.m_otherDefs.constBegin().key();
341 macroSubVar.location().warning(
342 QStringLiteral("Macro '\\%1' takes inconsistent number of "
343 "arguments (%2 %3, %4 %5)")
344 .arg(macroName, f, QString::number(m), other,
345 QString::number(macro.numParams)));
346 silent = true;
347 }
348 if (macro.numParams < m)
349 macro.numParams = m;
350 }
351 }
352 }
353 if (macro.numParams != -1)
354 m_utilities.macroHash.insert(macroName, macro);
355 }
356}
357
358/*!
359 All the heap allocated variables are deleted.
360 */
362{
363 m_utilities.cmdHash.clear();
364 m_utilities.macroHash.clear();
365}
366
367/*!
368 Trims the deadwood out of \a str. i.e., this function
369 cleans up \a str.
370 */
371void Doc::trimCStyleComment(Location &location, QString &str)
372{
373 QString cleaned;
374 Location m = location;
375 bool metAsterColumn = true;
376 int asterColumn = location.columnNo() + 1;
377 int i;
378
379 for (i = 0; i < str.size(); ++i) {
380 if (m.columnNo() == asterColumn) {
381 if (str[i] != '*')
382 break;
383 cleaned += ' ';
384 metAsterColumn = true;
385 } else {
386 if (str[i] == '\n') {
387 if (!metAsterColumn)
388 break;
389 metAsterColumn = false;
390 }
391 cleaned += str[i];
392 }
393 m.advance(str[i]);
394 }
395 if (cleaned.size() == str.size())
396 str = cleaned;
397
398 for (int i = 0; i < 3; ++i)
399 location.advance(str[i]);
400 str = str.mid(3, str.size() - 5);
401}
402
403void Doc::quoteFromFile(const Location &location, Quoter &quoter, ResolvedFile resolved_file)
404{
405 // TODO: quoteFromFile should not care about modifying a stateful
406 // quoter from the outside, instead, it should produce a quoter
407 // that allows the caller to retrieve the required information
408 // about the quoted file.
409 //
410 // When changing the way in which quoting works, this kind of
411 // spread resposability should be removed, together with quoteFromFile.
412 quoter.reset();
413
414 QString code;
415 {
416 QFile input_file{resolved_file.get_path()};
417 if (!input_file.open(QFile::ReadOnly))
418 return;
419 code = DocParser::untabifyEtc(QTextStream{&input_file}.readAll());
420 }
421
422 CodeMarker *marker = CodeMarker::markerForFileName(resolved_file.get_path());
423 quoter.quoteFromFile(resolved_file.get_path(), code, marker->markedUpCode(code, nullptr, location));
424}
425
426QT_END_NAMESPACE
The Atom class is the fundamental unit for representing documents internally.
Definition atom.h:18
AtomType type() const
Return the type of this atom.
Definition atom.h:149
@ BriefRight
Definition atom.h:26
@ LegaleseRight
Definition atom.h:58
@ String
Definition atom.h:92
@ BriefLeft
Definition atom.h:25
@ LegaleseLeft
Definition atom.h:57
@ C
Definition atom.h:27
@ AutoLink
Definition atom.h:22
const Atom * next() const
Return the next atom in the atom list.
Definition atom.h:146
The Config class contains the configuration variables for controlling how qdoc produces documentation...
Definition config.h:84
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
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:248
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:268
static void quoteFromFile(const Location &location, Quoter &quoter, ResolvedFile resolved_file)
Definition doc.cpp:403
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:253
const QList< Atom * > & keywords() const
Definition doc.cpp:280
~Doc()
Definition doc.cpp:69
const Text & body() const
Definition doc.cpp:115
static void initialize(FileResolver &file_resolver)
Definition doc.cpp:308
bool hasKeywords() const
Definition doc.cpp:258
QStringList omitEnumItemNames() const
Definition doc.cpp:205
const QList< Atom * > & targets() const
Definition doc.cpp:286
QMultiMap< ComparisonCategory, Text > * comparesWithMap() const
Definition doc.cpp:297
const QList< int > & tableOfContentsLevels() const
Definition doc.cpp:274
bool hasTargets() const
Definition doc.cpp:263
Text trimmedBriefText(const QString &className) const
Definition doc.cpp:126
ArgList metaCommandArgs(const QString &metaCommand) const
Definition doc.cpp:243
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:361
TopicList topicsUsed() const
Returns a reference to the list of topic commands used in the current qdoc comment.
Definition doc.cpp:238
QStringMultiMap * metaTagMap() const
Definition doc.cpp:292
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:302
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:15
int columnNo() const
Returns the current column number.
Definition location.h:44
void reset()
Definition quoter.cpp:106
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:362
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