19#include <QtCore/qdebug.h>
20#include <QtCore/qregularexpression.h>
24using namespace Qt::StringLiterals;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
60 QStringList sorted = concepts;
61 std::sort(sorted.begin(), sorted.end(),
62 [](
const QString &a,
const QString &b) {
return a.size() > b.size(); });
64 QHash<QString, QString> targetForDisplay;
65 QStringList displayAlternatives;
66 for (
const QString &concept_name : std::as_const(sorted)) {
67 const QString unqualified = concept_name.section(
"::"_L1, -1);
68 if (targetForDisplay.contains(unqualified))
70 targetForDisplay.insert(unqualified, concept_name);
71 displayAlternatives << QRegularExpression::escape(unqualified);
73 if (displayAlternatives.isEmpty())
76 const QRegularExpression re(
"\\b("_L1 + displayAlternatives.join(
'|'_L1) +
")\\b"_L1);
79 auto it = re.globalMatch(text);
80 while (it.hasNext()) {
81 const QRegularExpressionMatch match = it.next();
82 result += QStringView(text).mid(last, match.capturedStart() - last);
83 const QString display = match.captured(1);
84 result +=
"<@concept target=\""_L1 + targetForDisplay.value(display) +
"\">"_L1
85 + display +
"</@concept>"_L1;
86 last = match.capturedEnd();
88 result += QStringView(text).mid(last);
93
94
95
96
97
101 result.reserve(
int(refs.size()));
102 for (
const auto &s : refs)
103 result.append(QString::fromStdString(s));
108
109
110
111
112
113
114
115
116
122 if (param.template_declaration)
123 result += formatTemplateDeclStorage(*param.template_declaration, TemplateFormat::SingleLine) +
' '_L1;
127 switch (param
.kind) {
129 if (param.concept_name) {
130 const QString fq = QString::fromStdString(*param.concept_name);
131 const QString unqualified = fq.section(
"::"_L1, -1);
132 result +=
"<@concept target=\""_L1 + fq +
"\">"_L1
133 + unqualified +
"</@concept>"_L1;
135 result +=
"typename"_L1;
139 if (!decl
.type.empty())
140 result += typified(QString::fromStdString(decl.type),
false);
142 case RelaxedTemplateParameter::Kind::TemplateTemplateParameter:
143 result +=
"typename"_L1;
147 if (param.is_parameter_pack)
150 if (!decl
.name.empty()) {
151 if (!result.isEmpty() && !result.endsWith(
' '_L1))
153 result += protect(QString::fromStdString(decl.name));
160 result += typified(QString::fromStdString(decl.initializer),
false);
162 result += protect(QString::fromStdString(decl.initializer));
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
187 TemplateFormat format)
189 const bool multiline = (format == TemplateFormat::MultiLine);
191 QString result =
"template <"_L1;
197 for (
const auto ¶m : templateDecl.parameters) {
198 if (param.sfinae_constraint)
201 result += multiline ?
",\n"_L1 :
", "_L1;
205 result += formatTemplateParameter(param);
218
219
220
221
222
223
224
225
229 const auto format = multiline ? TemplateFormat::MultiLine : TemplateFormat::SingleLine;
231 QString content = formatTemplateDeclStorage(*templateDecl, format);
235 result =
"<@template-block>"_L1;
239 if (templateDecl->requires_clause && !templateDecl->requires_clause->empty()) {
240 QString clause = protect(QString::fromStdString(*templateDecl->requires_clause));
241 clause = markupConceptReferences(std::move(clause),
242 toQStringList(templateDecl->referenced_concepts));
243 result +=
" requires "_L1 + clause;
247 result +=
'\n'_L1 +
"</@template-block>"_L1;
255
256
257bool CppCodeMarker::recognizeCode(
const QString & )
263
264
265
266bool CppCodeMarker::recognizeExtension(
const QString &extension)
268 QByteArray ext = extension.toLatin1();
269 return ext ==
"c" || ext ==
"c++" || ext ==
"qdoc" || ext ==
"qtt" || ext ==
"qtx"
270 || ext ==
"cc" || ext ==
"cpp" || ext ==
"cxx" || ext ==
"ch" || ext ==
"h"
271 || ext ==
"h++" || ext ==
"hh" || ext ==
"hpp" || ext ==
"hxx";
275
276
277bool CppCodeMarker::recognizeLanguage(
const QString &lang)
279 return lang == QLatin1String(
"c") || lang == QLatin1String(
"cpp");
283
284
290QString CppCodeMarker::markedUpCode(
const QString &code,
const Node *relative,
293 return addMarkUp(code, relative, location);
296QString CppCodeMarker::markedUpSynopsis(
const Node *node,
const Node * ,
299 const int MaxEnumValues = 6;
306 name = taggedNode(node);
307 if (style != Section::Details)
308 name = linkTag(node, name);
309 name =
"<@name>" + name +
"</@name>";
314 name.prepend(taggedNode(node->parent()) +
"::");
324 synopsis += QLatin1Char(
' ') + name;
329 if (
auto templateDecl = node->templateDecl())
330 synopsis = formatTemplateDecl(&*templateDecl);
333 synopsis += typified(func->returnTypeString(),
true);
336 synopsis += QLatin1Char(
'(');
339 for (
int i = 0; i < parameters
.count(); ++i) {
343 QString name = param.name();
344 QString type = param.type();
345 QString value = param.defaultValue();
346 qsizetype insertPos = param.nameInsertionPoint();
349 synopsis += typified(type.left(insertPos),
false);
350 synopsis +=
"<@param>" + protect(name) +
"</@param>";
351 synopsis += typified(type.mid(insertPos),
false);
354 synopsis += typified(type, trailingSpace);
356 synopsis +=
"<@param>" + protect(name) +
"</@param>";
359 synopsis +=
" = " + protect(value);
362 synopsis += QLatin1Char(
')');
365 synopsis +=
" const";
369 synopsis.prepend(
"virtual ");
371 synopsis.append(
" final");
373 synopsis.append(
" override");
375 synopsis.append(
" = 0");
377 synopsis.append(
" &");
379 synopsis.append(
" &&");
381 if (!func->returnType().isEmpty() && func->returnType() !=
"void")
382 synopsis +=
" : " + typified(func->returnTypeString());
385 synopsis.append(
" &");
387 synopsis.append(
" &&");
388 if (
const auto &req = func->trailingRequiresClause(); req && !req->isEmpty()) {
389 QString clause = protect(*req);
390 clause = markupConceptReferences(std::move(clause),
391 func->referencedConcepts());
392 synopsis.append(
" requires " + clause);
397 enume =
static_cast<
const EnumNode *>(node);
400 synopsis +=
" class";
401 if (!enume->isAnonymous())
402 synopsis +=
" %1"_L1.arg(name);
403 else if (style != Section::Details)
404 synopsis = linkTag(node, synopsis);
408 QStringList documentedItems = enume
->doc().enumItemNames();
409 if (documentedItems.isEmpty()) {
410 const auto &enumItems = enume->items();
411 for (
const auto &item : enumItems)
412 documentedItems << item.name();
414 const QStringList omitItems = enume
->doc().omitEnumItemNames();
415 for (
const auto &item : omitItems)
416 documentedItems.removeAll(item);
418 if (documentedItems.size() > MaxEnumValues) {
420 const QString last = documentedItems.last();
421 documentedItems = documentedItems.mid(0, MaxEnumValues - 1);
422 documentedItems +=
"…";
423 documentedItems += last;
425 synopsis += documentedItems.join(QLatin1String(
", "));
427 if (!documentedItems.isEmpty())
428 synopsis += QLatin1Char(
' ');
429 synopsis += QLatin1Char(
'}');
434 if (
auto templateDecl = node->templateDecl())
435 synopsis += formatTemplateDecl(&*templateDecl);
440 if (
static_cast<
const TypedefNode *>(node)->associatedEnum())
445 auto property =
static_cast<
const PropertyNode *>(node);
446 synopsis = name +
" : " + typified(property->qualifiedDataType());
450 auto property =
static_cast<
const QmlPropertyNode *>(node);
451 synopsis = name +
" : " + typified(property->dataType());
454 case NodeType::Variable:
455 variable =
static_cast<
const VariableNode *>(node);
457 synopsis = name +
" : " + typified(variable->dataType());
459 synopsis = typified(variable->leftType(),
true) + name + protect(variable->rightType());
463 synopsis =
std::move(name);
466 QString extra = CodeMarker::extraSynopsis(node, style);
467 if (!extra.isEmpty()) {
468 extra.prepend(u"<@extra>"_s);
469 extra.append(u"</@extra> "_s);
472 return extra + synopsis;
476
477QString CppCodeMarker::markedUpQmlItem(
const Node *node,
bool summary)
479 QString name = taggedQmlNode(node);
483 name = linkTag(node, name);
485 const auto *pn =
static_cast<
const QmlPropertyNode *>(node);
486 if (pn->isAttached())
487 name.prepend(pn->element() + QLatin1Char(
'.'));
489 name =
"<@name>" + name +
"</@name>";
491 const auto *pn =
static_cast<
const QmlPropertyNode *>(node);
492 synopsis = name +
" : " + typified(pn->dataType());
494 const auto *func =
static_cast<
const FunctionNode *>(node);
495 if (!func->returnType().isEmpty())
496 synopsis = typified(func->returnTypeString(),
true) + name;
499 synopsis += QLatin1Char(
'(');
500 if (!func->parameters().isEmpty()) {
501 const Parameters ¶meters = func->parameters();
502 for (
int i = 0; i < parameters
.count(); ++i) {
505 QString name = parameters
.at(i
).name();
506 QString type = parameters
.at(i
).type();
508 if (!name.isEmpty()) {
509 synopsis += typified(type,
true);
510 paramName =
std::move(name);
512 paramName =
std::move(type);
514 synopsis +=
"<@param>" + protect(paramName) +
"</@param>";
517 synopsis += QLatin1Char(
')');
519 synopsis =
std::move(name);
523 if (!extra.isEmpty()) {
524 extra.prepend(u" <@extra>"_s);
525 extra.append(u"</@extra>"_s);
528 return synopsis + extra;
531QString CppCodeMarker::markedUpName(
const Node *node)
533 QString name = linkTag(node, taggedNode(node));
539QString CppCodeMarker::markedUpEnumValue(
const QString &enumValue,
const Node *relative)
551 if (nativeEnum && nativeEnum->enumNode()
552 && !enumValue.startsWith(
"%1."_L1.arg(nativeEnum->prefix())))
553 return "%1<@op>.</@op>%2"_L1.arg(nativeEnum->prefix(), enumValue);
557 && enumValue.section(
' ', 0, 0).contains(
'.'_L1)) {
558 return "<@op>%1</@op>"_L1.arg(enumValue);
566 parts.prepend(markedUpName(node));
571 if (
static_cast<
const EnumNode *>(relative)->isScoped())
572 parts.append(relative->name());
574 parts.append(enumValue);
575 const auto &delim = (relative->genus() == Genus::QML) ?
"."_L1 :
"::"_L1;
576 return parts.join(
"<@op>%1</@op>"_L1.arg(delim));
579QString CppCodeMarker::addMarkUp(
const QString &in,
const Node * ,
582 static QSet<QString> types{
583 QLatin1String(
"bool"), QLatin1String(
"char"), QLatin1String(
"double"),
584 QLatin1String(
"float"), QLatin1String(
"int"), QLatin1String(
"long"),
585 QLatin1String(
"short"), QLatin1String(
"signed"), QLatin1String(
"unsigned"),
586 QLatin1String(
"uint"), QLatin1String(
"ulong"), QLatin1String(
"ushort"),
587 QLatin1String(
"uchar"), QLatin1String(
"void"), QLatin1String(
"qlonglong"),
588 QLatin1String(
"qulonglong"), QLatin1String(
"qint"), QLatin1String(
"qint8"),
589 QLatin1String(
"qint16"), QLatin1String(
"qint32"), QLatin1String(
"qint64"),
590 QLatin1String(
"quint"), QLatin1String(
"quint8"), QLatin1String(
"quint16"),
591 QLatin1String(
"quint32"), QLatin1String(
"quint64"), QLatin1String(
"qreal"),
592 QLatin1String(
"cond")
595 static QSet<QString> keywords{
596 QLatin1String(
"and"), QLatin1String(
"and_eq"), QLatin1String(
"asm"), QLatin1String(
"auto"),
597 QLatin1String(
"bitand"), QLatin1String(
"bitor"), QLatin1String(
"break"),
598 QLatin1String(
"case"), QLatin1String(
"catch"), QLatin1String(
"class"),
599 QLatin1String(
"compl"), QLatin1String(
"const"), QLatin1String(
"const_cast"),
600 QLatin1String(
"continue"), QLatin1String(
"default"), QLatin1String(
"delete"),
601 QLatin1String(
"do"), QLatin1String(
"dynamic_cast"), QLatin1String(
"else"),
602 QLatin1String(
"enum"), QLatin1String(
"explicit"), QLatin1String(
"export"),
603 QLatin1String(
"extern"), QLatin1String(
"false"), QLatin1String(
"for"),
604 QLatin1String(
"friend"), QLatin1String(
"goto"), QLatin1String(
"if"),
605 QLatin1String(
"include"), QLatin1String(
"inline"), QLatin1String(
"monitor"),
606 QLatin1String(
"mutable"), QLatin1String(
"namespace"), QLatin1String(
"new"),
607 QLatin1String(
"not"), QLatin1String(
"not_eq"), QLatin1String(
"operator"),
608 QLatin1String(
"or"), QLatin1String(
"or_eq"), QLatin1String(
"private"),
609 QLatin1String(
"protected"), QLatin1String(
"public"), QLatin1String(
"register"),
610 QLatin1String(
"reinterpret_cast"), QLatin1String(
"return"), QLatin1String(
"sizeof"),
611 QLatin1String(
"static"), QLatin1String(
"static_cast"), QLatin1String(
"struct"),
612 QLatin1String(
"switch"), QLatin1String(
"template"), QLatin1String(
"this"),
613 QLatin1String(
"throw"), QLatin1String(
"true"), QLatin1String(
"try"),
614 QLatin1String(
"typedef"), QLatin1String(
"typeid"), QLatin1String(
"typename"),
615 QLatin1String(
"union"), QLatin1String(
"using"), QLatin1String(
"virtual"),
616 QLatin1String(
"volatile"), QLatin1String(
"wchar_t"), QLatin1String(
"while"),
617 QLatin1String(
"xor"), QLatin1String(
"xor_eq"), QLatin1String(
"synchronized"),
619 QLatin1String(
"signals"), QLatin1String(
"slots"), QLatin1String(
"emit")
631 static const QRegularExpression classRegExp(QRegularExpression::anchoredPattern(
"Qt?(?:[A-Z3]+[a-z][A-Za-z]*|t)"));
632 static const QRegularExpression functionRegExp(QRegularExpression::anchoredPattern(
"q([A-Z][a-z]+)+"));
633 static const QRegularExpression findFunctionRegExp(QStringLiteral(
"^\\s*\\("));
636 auto readChar = [&]() {
648 if (ch.isLetter() || ch ==
'_') {
654 }
while (!atEOF && (ch.isLetterOrNumber() || ch ==
'_'));
656 if (classRegExp.match(ident).hasMatch()) {
657 tag = QStringLiteral(
"type");
658 }
else if (functionRegExp.match(ident).hasMatch()) {
659 tag = QStringLiteral(
"func");
661 }
else if (types.contains(ident)) {
662 tag = QStringLiteral(
"type");
663 }
else if (keywords.contains(ident)) {
664 tag = QStringLiteral(
"keyword");
665 }
else if (braceDepth == 0 && parenDepth == 0) {
666 if (code.indexOf(findFunctionRegExp, i - 1) == i - 1)
667 tag = QStringLiteral(
"func");
670 }
else if (ch.isDigit()) {
674 }
while (!atEOF && (ch.isLetterOrNumber() || ch ==
'.' || ch ==
'\''));
675 tag = QStringLiteral(
"number");
677 switch (ch.unicode()) {
697 tag = QStringLiteral(
"op");
703 while (!atEOF && ch !=
'"') {
710 tag = QStringLiteral(
"string");
715 while (!atEOF && ch !=
'\n') {
721 tag = QStringLiteral(
"preprocessor");
727 while (!atEOF && ch !=
'\'') {
734 tag = QStringLiteral(
"char");
749 if (!atEOF && ch ==
':') {
752 tag = QStringLiteral(
"op");
758 if (!atEOF && ch ==
'/') {
762 }
while (!atEOF && ch !=
'\n');
763 tag = QStringLiteral(
"comment");
764 }
else if (ch ==
'*') {
765 bool metAster =
false;
766 bool metAsterSlash =
false;
771 while (!metAsterSlash) {
776 else if (metAster && ch ==
'/')
777 metAsterSlash =
true;
783 tag = QStringLiteral(
"comment");
785 tag = QStringLiteral(
"op");
804 text = QStringView{code}.mid(start, finish - start);
807 if (!tag.isEmpty()) {
808 out += QStringLiteral(
"<@");
811 out += QStringLiteral(
" target=\"");
813 out += QStringLiteral(
"()\"");
815 out += QStringLiteral(
">");
818 appendProtectedString(&out, text);
820 if (!tag.isEmpty()) {
821 out += QStringLiteral(
"</@");
823 out += QStringLiteral(
">");
827 if (start < code.size()) {
828 appendProtectedString(&out, QStringView{code}.mid(start));
The Atom class is the fundamental unit for representing documents internally.
AtomType
\value AnnotatedList \value AutoLink \value BaseName \value BriefLeft \value BriefRight \value C \val...
This node is used to represent any kind of function being documented.
bool isMacroWithoutParams() const
const Parameters & parameters() const
bool isPureVirtual() const override
bool isNonvirtual() const
The Location class provides a way to mark a location in a file.
Interface implemented by Node subclasses that can refer to a C++ enum.
virtual const NativeEnum * nativeEnum() const =0
Encapsulates information about native (C++) enum values.
The Parameter class describes one function parameter.
A class for containing the elements of one documentation section.
static QStringList toQStringList(const std::vector< std::string > &refs)
static QString markupConceptReferences(QString text, const QStringList &concepts)
constexpr std::size_t MultilineTemplateParamThreshold
Combined button and popup list for selecting options.
The Node class is the base class for all the nodes in QDoc's parse tree.
const Doc & doc() const
Returns a reference to the node's Doc data member.
bool isQmlNode() const
Returns true if this node's Genus value is QML.
bool isEnumType(Genus g) const
bool isHeader() const
Returns true if the node type is HeaderFile.
NodeType nodeType() const override
Returns this node's type.
virtual bool isMacro() const
returns true if either FunctionNode::isMacroWithParams() or FunctionNode::isMacroWithoutParams() retu...
bool isEnumType() const
Returns true if the node type is Enum.
Aggregate * parent() const
Returns the node's parent pointer, that is, the aggregate under which the node is documented.
bool isProxyNode() const
Returns true if the node type is Proxy.
bool isFunction(Genus g=Genus::DontCare) const
Returns true if this is a FunctionNode and its Genus is set to g.
bool isProperty() const
Returns true if the node type is Property.
bool isRelatedNonmember() const
Returns true if this is a related nonmember of something.
Aggregate * declarationParent() const
Returns the aggregate in whose C++ scope the node was declared, or null if the node was not adopted b...
bool isQmlProperty() const
Returns true if the node type is QmlProperty.
A class for parsing and managing a function parameter list.
const Parameter & at(int i) const
std::size_t visibleParameterCount() const
Returns the number of template parameters that are visible in rendered output — SFINAE-annotated para...
ValuedDeclaration valued_declaration
@ NonTypeTemplateParameter
@ TemplateTemplateParameter