diff --git a/CHANGES b/CHANGES index c8b08a6fd..9b9b30018 100644 --- a/CHANGES +++ b/CHANGES @@ -35,6 +35,8 @@ Incompatible changes * Footer "Continued on next page" of LaTeX longtable's now not framed (refs: #3497) * #3529: The arguments of ``BuildEnvironment.__init__`` is changed * #3082: Use latexmk for pdf (and dvi) targets (Unix-like platforms only) +* #3558: Emit warnings if footnotes and citations are not referenced. The + warnings can be suppressed by ``suppress_warnings``. Features removed ---------------- diff --git a/doc/config.rst b/doc/config.rst index 15a9a339b..3bc6bebb7 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -236,6 +236,7 @@ General configuration * ref.keyword * ref.option * ref.citation + * ref.footnote * ref.doc * misc.highlighting_failure * toc.secnum @@ -255,6 +256,10 @@ General configuration Added ``epub.unknown_project_files`` + .. versionchanged:: 1.6 + + Added ``ref.footnote`` + .. confval:: needs_sphinx If set to a ``major.minor`` version string like ``'1.1'``, Sphinx will diff --git a/sphinx/io.py b/sphinx/io.py index 2e1e25599..636167332 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -18,6 +18,7 @@ from sphinx.transforms import ( ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences, DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, SortIds, AutoNumbering, AutoIndexUpgrader, FilterSystemMessages, + UnreferencedFootnotesDetector ) from sphinx.transforms.compact_bullet_list import RefOnlyBulletListTransform from sphinx.transforms.i18n import ( @@ -92,7 +93,7 @@ class SphinxStandaloneReader(SphinxBaseReader): Locale, CitationReferences, DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, AutoNumbering, AutoIndexUpgrader, SortIds, RemoveTranslatableInline, PreserveTranslatableMessages, FilterSystemMessages, - RefOnlyBulletListTransform] + RefOnlyBulletListTransform, UnreferencedFootnotesDetector] class SphinxI18nReader(SphinxBaseReader): @@ -106,7 +107,8 @@ class SphinxI18nReader(SphinxBaseReader): transforms = [ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences, DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, AutoNumbering, SortIds, RemoveTranslatableInline, - FilterSystemMessages, RefOnlyBulletListTransform] + FilterSystemMessages, RefOnlyBulletListTransform, + UnreferencedFootnotesDetector] def __init__(self, *args, **kwargs): # type: (Any, Any) -> None diff --git a/sphinx/transforms/__init__.py b/sphinx/transforms/__init__.py index b7306bb2d..bfe52413f 100644 --- a/sphinx/transforms/__init__.py +++ b/sphinx/transforms/__init__.py @@ -277,6 +277,32 @@ class ExtraTranslatableNodes(SphinxTransform): node['translatable'] = True +class UnreferencedFootnotesDetector(SphinxTransform): + """ + detect unreferenced footnotes and citations, and emit warnings + """ + default_priority = 200 + + def apply(self): + for node in self.document.footnotes: + if node['names'][0] not in self.document.footnote_refs: + logger.warning('Footnote [%s] is not referenced.', node['names'][0], + type='ref', subtype='footnote', + location=node) + + for node in self.document.autofootnotes: + if not any(ref['auto'] == node['auto'] for ref in self.document.autofootnote_refs): + logger.warning('Footnote [#] is not referenced.', + type='ref', subtype='footnote', + location=node) + + for node in self.document.citations: + if node['names'][0] not in self.document.citation_refs: + logger.warning('Citation [%s] is not referenced.', node['names'][0], + type='ref', subtype='citation', + location=node) + + class FilterSystemMessages(SphinxTransform): """Filter system messages from a doctree.""" default_priority = 999