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)
547 if (nativeEnum && nativeEnum->enumNode()
548 && !enumValue.startsWith(
"%1."_L1.arg(nativeEnum->prefix())))
549 return "%1<@op>.</@op>%2"_L1.arg(nativeEnum->prefix(), enumValue);
553 && enumValue.section(
' ', 0, 0).contains(
'.'_L1)) {
554 return "<@op>%1</@op>"_L1.arg(enumValue);
562 parts.prepend(markedUpName(node));
567 if (
static_cast<
const EnumNode *>(relative)->isScoped())
568 parts.append(relative->name());
570 parts.append(enumValue);
571 const auto &delim = (relative->genus() == Genus::QML) ?
"."_L1 :
"::"_L1;
572 return parts.join(
"<@op>%1</@op>"_L1.arg(delim));
575QString CppCodeMarker::addMarkUp(
const QString &in,
const Node * ,
578 static QSet<QString> types{
579 QLatin1String(
"bool"), QLatin1String(
"char"), QLatin1String(
"double"),
580 QLatin1String(
"float"), QLatin1String(
"int"), QLatin1String(
"long"),
581 QLatin1String(
"short"), QLatin1String(
"signed"), QLatin1String(
"unsigned"),
582 QLatin1String(
"uint"), QLatin1String(
"ulong"), QLatin1String(
"ushort"),
583 QLatin1String(
"uchar"), QLatin1String(
"void"), QLatin1String(
"qlonglong"),
584 QLatin1String(
"qulonglong"), QLatin1String(
"qint"), QLatin1String(
"qint8"),
585 QLatin1String(
"qint16"), QLatin1String(
"qint32"), QLatin1String(
"qint64"),
586 QLatin1String(
"quint"), QLatin1String(
"quint8"), QLatin1String(
"quint16"),
587 QLatin1String(
"quint32"), QLatin1String(
"quint64"), QLatin1String(
"qreal"),
588 QLatin1String(
"cond")
591 static QSet<QString> keywords{
592 QLatin1String(
"and"), QLatin1String(
"and_eq"), QLatin1String(
"asm"), QLatin1String(
"auto"),
593 QLatin1String(
"bitand"), QLatin1String(
"bitor"), QLatin1String(
"break"),
594 QLatin1String(
"case"), QLatin1String(
"catch"), QLatin1String(
"class"),
595 QLatin1String(
"compl"), QLatin1String(
"const"), QLatin1String(
"const_cast"),
596 QLatin1String(
"continue"), QLatin1String(
"default"), QLatin1String(
"delete"),
597 QLatin1String(
"do"), QLatin1String(
"dynamic_cast"), QLatin1String(
"else"),
598 QLatin1String(
"enum"), QLatin1String(
"explicit"), QLatin1String(
"export"),
599 QLatin1String(
"extern"), QLatin1String(
"false"), QLatin1String(
"for"),
600 QLatin1String(
"friend"), QLatin1String(
"goto"), QLatin1String(
"if"),
601 QLatin1String(
"include"), QLatin1String(
"inline"), QLatin1String(
"monitor"),
602 QLatin1String(
"mutable"), QLatin1String(
"namespace"), QLatin1String(
"new"),
603 QLatin1String(
"not"), QLatin1String(
"not_eq"), QLatin1String(
"operator"),
604 QLatin1String(
"or"), QLatin1String(
"or_eq"), QLatin1String(
"private"),
605 QLatin1String(
"protected"), QLatin1String(
"public"), QLatin1String(
"register"),
606 QLatin1String(
"reinterpret_cast"), QLatin1String(
"return"), QLatin1String(
"sizeof"),
607 QLatin1String(
"static"), QLatin1String(
"static_cast"), QLatin1String(
"struct"),
608 QLatin1String(
"switch"), QLatin1String(
"template"), QLatin1String(
"this"),
609 QLatin1String(
"throw"), QLatin1String(
"true"), QLatin1String(
"try"),
610 QLatin1String(
"typedef"), QLatin1String(
"typeid"), QLatin1String(
"typename"),
611 QLatin1String(
"union"), QLatin1String(
"using"), QLatin1String(
"virtual"),
612 QLatin1String(
"volatile"), QLatin1String(
"wchar_t"), QLatin1String(
"while"),
613 QLatin1String(
"xor"), QLatin1String(
"xor_eq"), QLatin1String(
"synchronized"),
615 QLatin1String(
"signals"), QLatin1String(
"slots"), QLatin1String(
"emit")
627 static const QRegularExpression classRegExp(QRegularExpression::anchoredPattern(
"Qt?(?:[A-Z3]+[a-z][A-Za-z]*|t)"));
628 static const QRegularExpression functionRegExp(QRegularExpression::anchoredPattern(
"q([A-Z][a-z]+)+"));
629 static const QRegularExpression findFunctionRegExp(QStringLiteral(
"^\\s*\\("));
632 auto readChar = [&]() {
644 if (ch.isLetter() || ch ==
'_') {
650 }
while (!atEOF && (ch.isLetterOrNumber() || ch ==
'_'));
652 if (classRegExp.match(ident).hasMatch()) {
653 tag = QStringLiteral(
"type");
654 }
else if (functionRegExp.match(ident).hasMatch()) {
655 tag = QStringLiteral(
"func");
657 }
else if (types.contains(ident)) {
658 tag = QStringLiteral(
"type");
659 }
else if (keywords.contains(ident)) {
660 tag = QStringLiteral(
"keyword");
661 }
else if (braceDepth == 0 && parenDepth == 0) {
662 if (code.indexOf(findFunctionRegExp, i - 1) == i - 1)
663 tag = QStringLiteral(
"func");
666 }
else if (ch.isDigit()) {
670 }
while (!atEOF && (ch.isLetterOrNumber() || ch ==
'.' || ch ==
'\''));
671 tag = QStringLiteral(
"number");
673 switch (ch.unicode()) {
693 tag = QStringLiteral(
"op");
699 while (!atEOF && ch !=
'"') {
706 tag = QStringLiteral(
"string");
711 while (!atEOF && ch !=
'\n') {
717 tag = QStringLiteral(
"preprocessor");
723 while (!atEOF && ch !=
'\'') {
730 tag = QStringLiteral(
"char");
745 if (!atEOF && ch ==
':') {
748 tag = QStringLiteral(
"op");
754 if (!atEOF && ch ==
'/') {
758 }
while (!atEOF && ch !=
'\n');
759 tag = QStringLiteral(
"comment");
760 }
else if (ch ==
'*') {
761 bool metAster =
false;
762 bool metAsterSlash =
false;
767 while (!metAsterSlash) {
772 else if (metAster && ch ==
'/')
773 metAsterSlash =
true;
779 tag = QStringLiteral(
"comment");
781 tag = QStringLiteral(
"op");
800 text = QStringView{code}.mid(start, finish - start);
803 if (!tag.isEmpty()) {
804 out += QStringLiteral(
"<@");
807 out += QStringLiteral(
" target=\"");
809 out += QStringLiteral(
"()\"");
811 out += QStringLiteral(
">");
814 appendProtectedString(&out, text);
816 if (!tag.isEmpty()) {
817 out += QStringLiteral(
"</@");
819 out += QStringLiteral(
">");
823 if (start < code.size()) {
824 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.
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.
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