4#ifdef QDOC_TEMPLATE_GENERATOR_ENABLED
6#include "linkresolver.h"
9#include "hrefresolver.h"
10#include "ir/contentblock.h"
12#include "qdocdatabase.h"
13#include "qdoclogging.h"
15using namespace Qt::Literals::StringLiterals;
19static Genus genusFromString(
const QString &s)
29 return Genus::DontCare;
32static bool isBrokenAutolink(
const IR::InlineContent &inline_)
34 return inline_.type == IR::InlineType::Link
35 && inline_.link.has_value()
36 && inline_.link->state == IR::LinkState::Broken
37 && inline_.link->origin == IR::LinkOrigin::Auto;
41
42
43
44
45LinkResolver::LinkResolver(QDocDatabase *qdb,
const HrefResolver &hrefResolver,
46 const LinkResolverConfig &config)
47 : m_qdb(qdb), m_hrefResolver(hrefResolver), m_config(config)
52
53
54
55
56
57
58
59void LinkResolver::resolve(QList<IR::ContentBlock> &blocks,
const Node *relative)
61 for (
auto &block : blocks)
62 resolveBlock(block, relative);
66
67
68
69void LinkResolver::resolveBlock(IR::ContentBlock &block,
const Node *relative)
71 resolveInlines(block.inlineContent, relative);
72 for (
auto &child : block.children)
73 resolveBlock(child, relative);
77
78
79
80
81void LinkResolver::resolveInlines(QList<IR::InlineContent> &inlines,
const Node *relative)
83 for (
auto &inline_ : inlines) {
84 if (inline_.type == IR::InlineType::Link && !inline_.href.isEmpty())
85 resolveLink(inline_, relative);
87 if (isBrokenAutolink(inline_)) {
88 qCDebug(lcQdoc) <<
"Autolink degraded to text:" << inline_.href;
89 inline_.type = IR::InlineType::Text;
90 inline_.text = inline_.plainText();
92 inline_.children.clear();
94 inline_.attributes = QJsonObject();
98 if (!inline_.children.isEmpty())
99 resolveInlines(inline_.children, relative);
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125void LinkResolver::resolveLink(IR::InlineContent &link,
const Node *relative)
127 Q_ASSERT(link.link.has_value());
129 const QString &target = link.href;
132 if (target.startsWith(
"http:"_L1) || target.startsWith(
"https:"_L1)
133 || target.startsWith(
"ftp:"_L1) || target.startsWith(
"file:"_L1)
134 || target.startsWith(
"mailto:"_L1)) {
135 link.link->state = IR::LinkState::External;
141 const Genus genus = genusFromString(
142 link.attributes.value(
"linkGenus"_L1).toString());
143 const QString &moduleName =
144 link.attributes.value(
"linkModule"_L1).toString();
145 const Node *targetNode =
146 m_qdb->findNodeForTarget(target, relative, genus, moduleName);
149 if (link.link->origin == IR::LinkOrigin::Auto) {
150 if (m_config.autolinkErrors && relative)
151 relative->doc().location().warning(
152 u"Can't autolink to '%1'"_s.arg(target));
154 if (!m_config.noLinkErrors && relative)
155 relative->doc().location().warning(
156 u"Can't link to '%1'"_s.arg(target));
159 link.link->state = IR::LinkState::Broken;
167 if (targetNode->isDeprecated() && relative
168 && relative->parent() != targetNode && !relative->isDeprecated()) {
170 link.link->state = IR::LinkState::Suppressed;
175 QString url = targetNode->url();
177 auto result = m_hrefResolver.hrefForNode(targetNode, relative);
178 if (std::get_if<HrefSuppressReason>(&result)) {
180 link.link->state = IR::LinkState::Suppressed;
183 url = std::get<QString>(std::move(result));
184 }
else if (url.isEmpty()) {
186 link.link->state = IR::LinkState::Ignored;
191 link.link->state = IR::LinkState::Resolved;