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 if (link.link->state != IR::LinkState::Unresolved)
132 const QString &target = link.href;
135 if (target.startsWith(
"http:"_L1) || target.startsWith(
"https:"_L1)
136 || target.startsWith(
"ftp:"_L1) || target.startsWith(
"file:"_L1)
137 || target.startsWith(
"mailto:"_L1)) {
138 link.link->state = IR::LinkState::External;
144 const Genus genus = genusFromString(
145 link.attributes.value(
"linkGenus"_L1).toString());
146 const QString &moduleName =
147 link.attributes.value(
"linkModule"_L1).toString();
148 const Node *targetNode =
149 m_qdb->findNodeForTarget(target, relative, genus, moduleName);
152 if (link.link->origin == IR::LinkOrigin::Auto) {
153 if (m_config.autolinkErrors && relative)
154 relative->doc().location().warning(
155 u"Can't autolink to '%1'"_s.arg(target));
157 if (!m_config.noLinkErrors && relative)
158 relative->doc().location().warning(
159 u"Can't link to '%1'"_s.arg(target));
162 link.link->state = IR::LinkState::Broken;
171 if (targetNode->isDeprecated() && relative
172 && relative->parent() != targetNode && !relative->isDeprecated()) {
174 link.link->state = IR::LinkState::Suppressed;
179 QString url = targetNode->url();
181 auto result = m_hrefResolver.hrefForNode(targetNode, relative);
182 if (std::get_if<HrefSuppressReason>(&result)) {
184 link.link->state = IR::LinkState::Suppressed;
187 url = std::get<QString>(std::move(result));
188 }
else if (url.isEmpty()) {
190 link.link->state = IR::LinkState::Ignored;
195 link.link->state = IR::LinkState::Resolved;