diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 85e2dc9a930..631192b3b74 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -771,7 +771,7 @@ def check_consistency(self) -> None: # Call _check_toc_parents here rather than in _get_toctree_ancestors() # because that method is called multiple times per document and would # lead to duplicate warnings. - _check_toc_parents(self.toctree_includes) + _check_toc_parents(self.toctree_includes, self.config.root_doc) # call check-consistency for all extensions self.domains._check_consistency() @@ -819,19 +819,28 @@ def _traverse_toctree( traversed.add(sub_docname) -def _check_toc_parents(toctree_includes: dict[str, list[str]]) -> None: +def _check_toc_parents(toctree_includes: dict[str, list[str]], root_doc: str) -> None: + """Checks if document is referenced in multiple toctrees. + Based on the current implementation of `global_toctree_for_doc`, + it considers only the descendants of root_doc and not the whole graph. + """ toc_parents: dict[str, list[str]] = {} - for parent, children in toctree_includes.items(): - for child in children: - toc_parents.setdefault(child, []).append(parent) + def _find_toc_parents_dfs(node: str) -> None: + for child in toctree_includes.get(node, []): + toc_parents.setdefault(child, []).append(node) + is_child_already_visited = len(toc_parents[child]) > 1 + if not is_child_already_visited: + _find_toc_parents_dfs(child) + + _find_toc_parents_dfs(root_doc) for doc, parents in sorted(toc_parents.items()): if len(parents) > 1: logger.info( __( 'document is referenced in multiple toctrees: %s, selecting: %s <- %s' ), - parents, + sorted(parents), max(parents), doc, location=doc, diff --git a/tests/roots/test-toctree-multiple-parents/pdfindex.rst b/tests/roots/test-toctree-multiple-parents/pdfindex.rst new file mode 100644 index 00000000000..3802732bed3 --- /dev/null +++ b/tests/roots/test-toctree-multiple-parents/pdfindex.rst @@ -0,0 +1,7 @@ +test-toctree-multiple-parents +============================= + +.. literalinclude:: relation_graph.txt + +.. toctree:: + delta diff --git a/tests/roots/test-toctree-multiple-parents/relation_graph.txt b/tests/roots/test-toctree-multiple-parents/relation_graph.txt index a610eac2622..909de7a9a1e 100644 --- a/tests/roots/test-toctree-multiple-parents/relation_graph.txt +++ b/tests/roots/test-toctree-multiple-parents/relation_graph.txt @@ -1,5 +1,5 @@ - index - / \ + index pdfindex + / \ / alpha delta \ / bravo / diff --git a/tests/test_builders/test_build.py b/tests/test_builders/test_build.py index 5f396cc48af..3b19826a438 100644 --- a/tests/test_builders/test_build.py +++ b/tests/test_builders/test_build.py @@ -106,6 +106,9 @@ def test_multiple_parents_toctree(app): assert ( "document is referenced in multiple toctrees: ['bravo', 'delta'], selecting: delta <- charlie" ) in app.status.getvalue() + assert ( + "document is referenced in multiple toctrees: ['index', 'pdfindex'], selecting: pdfindex <- delta" + ) not in app.status.getvalue() @pytest.mark.usefixtures('_http_teapot')