summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakeshi KOMIYA <i.tkomiya@gmail.com>2020-11-03 11:29:02 +0900
committerGitHub <noreply@github.com>2020-11-03 11:29:02 +0900
commit8575b434bbe16409b9fe282a021c4dc0db762bbc (patch)
tree6fdb9ca354e92e1fe28efb6fbf9fdabf45e77f15
parent487b8436c6e8dc596db4b8d4d06e9145105a2ac2 (diff)
parent0e98e9b1a8ade24acf1d91f59aa90e8b1e179b19 (diff)
downloadsphinx-git-8575b434bbe16409b9fe282a021c4dc0db762bbc.tar.gz
Merge pull request #8075 from tk0miya/6914_detailed_warning_for_missing_ref
Fix #6914: Emit a detailed warning when failed to resolve :ref:
-rw-r--r--CHANGES4
-rw-r--r--doc/extdev/appapi.rst9
-rw-r--r--sphinx/domains/std.py17
-rw-r--r--sphinx/events.py1
-rw-r--r--sphinx/transforms/post_transforms/__init__.py5
-rw-r--r--tests/roots/test-domain-py-xref-warning/conf.py0
-rw-r--r--tests/roots/test-domain-py-xref-warning/index.rst7
-rw-r--r--tests/test_domain_py.py8
8 files changed, 48 insertions, 3 deletions
diff --git a/CHANGES b/CHANGES
index b59dc7cd6..99e5cdaf9 100644
--- a/CHANGES
+++ b/CHANGES
@@ -13,6 +13,10 @@ Deprecated
Features added
--------------
+* #6914: Add a new event :event:`warn-missing-reference` to custom warning
+ messages when failed to resolve a cross-reference
+* #6914: Emit a detailed warning when failed to resolve a ``:ref:`` reference
+
Bugs fixed
----------
diff --git a/doc/extdev/appapi.rst b/doc/extdev/appapi.rst
index df3eb3d67..9f2c10676 100644
--- a/doc/extdev/appapi.rst
+++ b/doc/extdev/appapi.rst
@@ -186,6 +186,7 @@ type for that event::
13. apply post-transforms (by priority): docutils.document -> docutils.document
14. event.doctree-resolved(app, doctree, docname)
- (for any reference node that fails to resolve) event.missing-reference(env, node, contnode)
+ - (for any reference node that fails to resolve) event.warn-missing-reference(domain, node)
15. Generate output files
16. event.build-finished(app, exception)
@@ -284,6 +285,14 @@ Here is a more detailed list of these events.
.. versionadded:: 0.5
+.. event:: warn-missing-reference (app, domain, node)
+
+ Emitted when a cross-reference to an object cannot be resolved even after
+ :event:`missing-reference`. If the event handler can emit warnings for
+ the missing reference, it should return ``True``.
+
+ .. versionadded:: 3.4
+
.. event:: doctree-resolved (app, doctree, docname)
Emitted when a doctree has been "resolved" by the environment, that is, all
diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py
index 39f67b54e..7ea468404 100644
--- a/sphinx/domains/std.py
+++ b/sphinx/domains/std.py
@@ -610,8 +610,6 @@ class StandardDomain(Domain):
dangling_warnings = {
'term': 'term not in glossary: %(target)s',
- 'ref': 'undefined label: %(target)s (if the link has no caption '
- 'the label must precede a section header)',
'numref': 'undefined label: %(target)s',
'keyword': 'unknown keyword: %(target)s',
'doc': 'unknown document: %(target)s',
@@ -1107,8 +1105,23 @@ class StandardDomain(Domain):
RemovedInSphinx40Warning, stacklevel=2)
+def warn_missing_reference(app: "Sphinx", domain: Domain, node: pending_xref) -> bool:
+ if domain.name != 'std' or node['reftype'] != 'ref':
+ return None
+ else:
+ target = node['reftarget']
+ if target not in domain.anonlabels: # type: ignore
+ msg = __('undefined label: %s')
+ else:
+ msg = __('Failed to create a cross reference. A title or caption not found: %s')
+
+ logger.warning(msg % target, location=node, type='ref', subtype=node['reftype'])
+ return True
+
+
def setup(app: "Sphinx") -> Dict[str, Any]:
app.add_domain(StandardDomain)
+ app.connect('warn-missing-reference', warn_missing_reference)
return {
'version': 'builtin',
diff --git a/sphinx/events.py b/sphinx/events.py
index 82a52d762..214654706 100644
--- a/sphinx/events.py
+++ b/sphinx/events.py
@@ -46,6 +46,7 @@ core_events = {
'doctree-read': 'the doctree before being pickled',
'env-merge-info': 'env, read docnames, other env instance',
'missing-reference': 'env, node, contnode',
+ 'warn-missing-reference': 'domain, node',
'doctree-resolved': 'doctree, docname',
'env-updated': 'env',
'html-collect-pages': 'builder',
diff --git a/sphinx/transforms/post_transforms/__init__.py b/sphinx/transforms/post_transforms/__init__.py
index 7dc14af52..6633d6434 100644
--- a/sphinx/transforms/post_transforms/__init__.py
+++ b/sphinx/transforms/post_transforms/__init__.py
@@ -166,7 +166,10 @@ class ReferencesResolver(SphinxPostTransform):
warn = False
if not warn:
return
- if domain and typ in domain.dangling_warnings:
+
+ if self.app.emit_firstresult('warn-missing-reference', domain, node):
+ return
+ elif domain and typ in domain.dangling_warnings:
msg = domain.dangling_warnings[typ]
elif node.get('refdomain', 'std') not in ('', 'std'):
msg = (__('%s:%s reference target not found: %%(target)s') %
diff --git a/tests/roots/test-domain-py-xref-warning/conf.py b/tests/roots/test-domain-py-xref-warning/conf.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/roots/test-domain-py-xref-warning/conf.py
diff --git a/tests/roots/test-domain-py-xref-warning/index.rst b/tests/roots/test-domain-py-xref-warning/index.rst
new file mode 100644
index 000000000..6f2cab795
--- /dev/null
+++ b/tests/roots/test-domain-py-xref-warning/index.rst
@@ -0,0 +1,7 @@
+test-domain-py-xref-warning
+===========================
+
+.. _existing-label:
+
+:ref:`no-label`
+:ref:`existing-label`
diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py
index ceea51508..d81b406c2 100644
--- a/tests/test_domain_py.py
+++ b/tests/test_domain_py.py
@@ -859,3 +859,11 @@ def test_noindexentry(app):
assert_node(doctree, (addnodes.index, desc, addnodes.index, desc))
assert_node(doctree[0], addnodes.index, entries=[('single', 'f (built-in class)', 'f', '', None)])
assert_node(doctree[2], addnodes.index, entries=[])
+
+
+@pytest.mark.sphinx('dummy', testroot='domain-py-xref-warning')
+def test_warn_missing_reference(app, status, warning):
+ app.build()
+ assert 'index.rst:6: WARNING: undefined label: no-label' in warning.getvalue()
+ assert ('index.rst:6: WARNING: Failed to create a cross reference. A title or caption not found: existing-label'
+ in warning.getvalue())