9#include <QtCore/qcryptographichash.h>
10#include <QtCore/qfileinfo.h>
11#include <QtCore/qprocess.h>
15Q_LOGGING_CATEGORY(lcQdoc,
"qt.qdoc")
16Q_LOGGING_CATEGORY(lcQdocClang,
"qt.qdoc.clang")
19
20
21
22
26 const_cast<QLoggingCategory &>(lcQdoc()).setEnabled(QtDebugMsg, value);
27 const_cast<QLoggingCategory &>(lcQdocClang()).setEnabled(QtDebugMsg, value);
33 qCDebug(lcQdoc,
"START DEBUGGING: %ls", qUtf16Printable(message));
38 qCDebug(lcQdoc,
"STOP DEBUGGING: %ls", qUtf16Printable(message));
44 return lcQdoc().isEnabled(QtDebugMsg);
48
49
50
51
52
53
54
55
58 return reinterpret_cast<
const INode *>(string.toULongLong());
61
62
63
64
65
66
67
68
69
72 return QString::number(
reinterpret_cast<quintptr>(node));
76
77
78
81 Q_ASSERT(!loc.filePath().isEmpty());
82 QFileInfo fi{loc.filePath()};
83 const auto id = QLatin1String(
"%1_%2_%3").arg(prefix, fi.fileName(), QString::number(loc.lineNo()));
84 return asAsciiPrintable(id);
89
90
91
92
93
94
95
96
99 static QString terminator = QStringLiteral(
".");
100 if (wordPosition == numberOfWords - 1)
103 return comma(wordPosition, numberOfWords);
107
108
109
110
111
112
113
114
115
116
119 if (wordPosition == numberOfWords - 1)
121 if (numberOfWords == 2)
122 return QStringLiteral(
" and ");
123 if (wordPosition == 0 || wordPosition < numberOfWords - 2)
124 return QStringLiteral(
", ");
125 return QStringLiteral(
", and ");
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
159 auto legal_ascii = [](
const uint value) {
160 const uint start_ascii_subset{ 32 };
161 const uint end_ascii_subset{ 126 };
163 return value >= start_ascii_subset && value <= end_ascii_subset;
168 bool has_non_alnum_content{
false };
170 for (
const auto &c : str) {
171 char16_t u = c.unicode();
173 has_non_alnum_content =
true;
174 if (u >=
'A' && u <=
'Z')
176 if ((u >=
'a' && u <=
'z') || (u >=
'0' && u <=
'9')) {
177 result += QLatin1Char(u);
180 result += QLatin1Char(
'-');
184 if (result.endsWith(QLatin1Char(
'-')))
187 if (has_non_alnum_content) {
188 auto title_hash = QString::fromLocal8Bit(
189 QCryptographicHash::hash(str.toUtf8(), QCryptographicHash::Md5).toHex());
190 title_hash.truncate(8);
191 if (!result.isEmpty())
192 result.append(QLatin1Char(
'-'));
193 result.append(title_hash);
201 qsizetype n = str.size();
203 marked.reserve(n * 2 + 30);
204 const QChar *data = str.constData();
205 for (
int i = 0; i != n; ++i) {
206 switch (data[i].unicode()) {
227
228
229static bool runProcess(
const QString &program,
const QStringList &arguments,
230 QByteArray *stdOutIn, QByteArray *stdErrIn)
233 process.start(program, arguments, QProcess::ReadWrite);
234 if (!process.waitForStarted()) {
235 qCDebug(lcQdoc).nospace() <<
"Unable to start " << process.program()
236 <<
": " << process.errorString();
239 process.closeWriteChannel();
240 const bool finished = process.waitForFinished();
241 const QByteArray stdErr = process.readAllStandardError();
245 *stdOutIn = process.readAllStandardOutput();
248 qCDebug(lcQdoc).nospace() << process.program() <<
" timed out: " << stdErr;
253 if (process.exitStatus() != QProcess::NormalExit) {
254 qCDebug(lcQdoc).nospace() << process.program() <<
" crashed: " << stdErr;
258 if (process.exitCode() != 0) {
259 qCDebug(lcQdoc).nospace() << process.program() <<
" exited with "
260 << process.exitCode() <<
": " << stdErr;
268
269
271 return QByteArrayLiteral(
" (framework directory)");
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
294 QStringList arguments;
295 arguments << QStringLiteral(
"-E") << QStringLiteral(
"-x") << QStringLiteral(
"c++")
296 << QStringLiteral(
"-") << QStringLiteral(
"-v");
299 if (!runProcess(compiler, arguments, &stdOut, &stdErr))
301 const QByteArrayList stdErrLines = stdErr.split(
'\n');
302 bool isIncludeDir =
false;
303 for (
const QByteArray &line : stdErrLines) {
305 if (line.startsWith(QByteArrayLiteral(
"End of search list"))) {
306 isIncludeDir =
false;
308 QByteArray prefix(
"-I");
309 QByteArray headerPath{line.trimmed()};
310 if (headerPath.endsWith(frameworkSuffix())) {
311 headerPath.truncate(headerPath.size() - frameworkSuffix().size());
312 prefix = QByteArrayLiteral(
"-F");
314 result.append(QString::fromLocal8Bit(prefix + headerPath));
316 }
else if (line.startsWith(QByteArrayLiteral(
"#include <...> search starts here"))) {
326 QString fileName = QFileInfo(path).fileName();
327 return fileName.startsWith(
"moc_") ||
328 fileName.startsWith(
"qrc_") ||
329 fileName.startsWith(
"ui_");
333
334
335
336
337
338
339
340
341
342
343
344
347 QStringList pieces = linkText.split(
"\\#"_L1);
351 for (
auto &piece : pieces) {
352 QStringList fragmentPieces = piece.split(
'#');
353 next += fragmentPieces.takeFirst();
354 if (!fragmentPieces.isEmpty()) {
356 next = fragmentPieces.first();
358 if (result.count() == 2)
361 if (!next.isEmpty() && result.count() < 2)
368
369
370
371
372
373
376 QString link = project.toLower() + QLatin1Char(
'-') + path;
377 return asAsciiPrintable(link) + QLatin1Char(
'.') + fileExt;
381
382
383
384
385
386
387
388
389
392 const QString suffix = [kind]() {
394 case ExampleFileKind::File:
395 return " Example File"_L1;
396 case ExampleFileKind::Image:
397 return " Image File"_L1;
401 return QFileInfo(fileName).fileName() + suffix;
405
406
407
408
409
410
411
412
413
414
415
416
419 if (files.contains(fileName))
420 return exampleFileTitle(fileName, ExampleFileKind::File);
421 if (images.contains(fileName))
422 return exampleFileTitle(fileName, ExampleFileKind::Image);
The Location class provides a way to mark a location in a file.
Combined button and popup list for selecting options.
This namespace holds QDoc-internal utility methods.
QString uniqueIdentifier(const Location &loc, const QString &prefix)
Returns a unique identifier based on location loc, with a given prefix.
QString exampleFileTitle(const QStringList &files, const QStringList &images, const QString &fileName)
Constructs a title for a file or image page in an example.
static void setDebugEnabled(bool value)
QStringList getInternalIncludePaths(const QString &compiler)
QString exampleFileTitle(const QString &fileName, ExampleFileKind kind)
Constructs a title for a file or image page in an example.
bool isGeneratedFile(const QString &path)
QString asAsciiPrintable(const QString &name)
Returns an ascii-printable representation of str.
QString protect(const QString &string)
const INode * nodeForString(const QString &string)
Converts a string representation of a pointer address to an INode pointer.
void stopDebugging(const QString &message)
static QByteArray frameworkSuffix()
QStringList pathAndFragment(const QString &linkText)
Returns a string list containing the path and fragment components of the given linkText.
QString comma(qsizetype wordPosition, qsizetype numberOfWords)
QString separator(qsizetype wordPosition, qsizetype numberOfWords)
void startDebugging(const QString &message)
static bool runProcess(const QString &program, const QStringList &arguments, QByteArray *stdOutIn, QByteArray *stdErrIn)
QString linkForExampleFile(const QString &path, const QString &project, const QString &fileExt)
Constructs an href link from an example file name.
QString stringForNode(const INode *node)
Converts an INode pointer address to its string representation.