chiark / gitweb /
doxygen: as usual, I found more Doxygen bugs while fixing other stuff.
authorVladimír Vondruš <mosra@centrum.cz>
Thu, 13 Sep 2018 11:16:23 +0000 (13:16 +0200)
committerVladimír Vondruš <mosra@centrum.cz>
Thu, 13 Sep 2018 13:58:13 +0000 (15:58 +0200)
This usual thing in Markdown files, for example:

    Hello world
    ###########

is parsed as a paragraph and a 11th level heading with no title.
UHHMAZING, isn't it. Because of that, I'm no longer asserting on too
large heading levels but instead trying to provide helpful warning
messages for the user.

doxygen/dox2html5.py
doxygen/test/contents_sections_headings/Doxyfile [moved from doxygen/test/contents_section_in_function/Doxyfile with 87% similarity]
doxygen/test/contents_sections_headings/File.h [moved from doxygen/test/contents_section_in_function/File.h with 63% similarity]
doxygen/test/contents_sections_headings/File_8h.html [moved from doxygen/test/contents_section_in_function/File_8h.html with 73% similarity]
doxygen/test/contents_sections_headings/index.html [new file with mode: 0644]
doxygen/test/contents_sections_headings/input.dox [new file with mode: 0644]
doxygen/test/contents_sections_headings/warnings.html [moved from doxygen/test/contents_typography/warnings.html with 84% similarity]
doxygen/test/contents_typography/index.html
doxygen/test/contents_typography/input.dox
doxygen/test/test_contents.py

index 7f3e8bb2cc1cb858710f422024ff6673a596d448..4a6456a6b289358b681685f7d0e251cd5d16392d 100755 (executable)
@@ -732,37 +732,36 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET.
             assert element.tag == 'para' # is inside a paragraph :/
             has_block_elements = True
 
-            # Top-level description
-            if state.parsing_toplevel_desc:
-                if i.attrib['level'] == '1':
-                    tag = 'h2'
-                elif i.attrib['level'] == '2':
-                    tag = 'h3'
-                elif i.attrib['level'] == '3':
-                    tag = 'h4'
-                elif i.attrib['level'] == '4':
-                    tag = 'h5'
-                else: # pragma: no cover
-                    assert False
+            # Do not print anything if there are no contents
+            if not i.text:
+                logging.warning("{}: a Markdown heading underline was apparently misparsed by Doxygen, prefix the headings with # instead (or better, use @section for properly generated TOC)".format(state.current))
 
-                # Emit this warning only in top-level desc, TOC is not
-                # generated for function/enum/... descriptions
-                logging.warning("{}: prefer @section over Markdown heading for properly generated TOC".format(state.current))
-
-            # Function/enum/... descriptions are inside <h3> for function
-            # header, which is inside <h2> for detailed definition section, so
-            # it needs to be <h4> and below
             else:
-                if i.attrib['level'] == '1':
-                    tag = 'h4'
-                elif i.attrib['level'] == '2':
-                    tag = 'h5'
-                elif i.attrib['level'] in ['3', '4']:
-                    tag = 'h6' # there is no <h7>
-                else: # pragma: no cover
-                    assert False
+                h_tag_level = int(i.attrib['level'])
+                assert h_tag_level > 0
+
+                # Top-level description can have 5 levels (first level used for
+                # page title), so it needs to be <h2> and below
+                if state.parsing_toplevel_desc:
+                    h_tag_level += 1
+                    if h_tag_level > 6:
+                        h_tag_level = 6
+                        logging.warning("{}: more than five levels of Markdown headings for top-level docs are not supported, stopping at <h6>".format(state.current))
+
+                    # Emit this warning only in top-level desc, TOC is not
+                    # generated for function/enum/... descriptions
+                    logging.warning("{}: prefer @section over Markdown heading for properly generated TOC".format(state.current))
+
+                # Function/enum/... descriptions are inside <h3> for function
+                # header, which is inside <h2> for detailed definition section,
+                # so it needs to be <h4> and below
+                else:
+                    h_tag_level += 3
+                    if h_tag_level > 6:
+                        h_tag_level = 6
+                        logging.warning("{}: more than three levels of Markdown headings in member descriptions are not supported, stopping at <h6>".format(state.current))
 
-            out.parsed += '<{0}>{1}</{0}>'.format(tag, html.escape(i.text))
+                out.parsed += '<h{0}>{1}</h{0}>'.format(h_tag_level, html.escape(i.text))
 
         elif i.tag == 'para':
             assert element.tag != 'para' # should be top-level block element
similarity index 87%
rename from doxygen/test/contents_section_in_function/Doxyfile
rename to doxygen/test/contents_sections_headings/Doxyfile
index 49e476ec24dca650c3a4ee46e65724f1d09fdffe..b74ee57cb625a994fd2b46d9e3fbbc125ad5d058 100644 (file)
@@ -1,4 +1,4 @@
-INPUT                   = File.h
+INPUT                   = File.h input.dox
 QUIET                   = YES
 GENERATE_HTML           = NO
 GENERATE_LATEX          = NO
similarity index 63%
rename from doxygen/test/contents_section_in_function/File.h
rename to doxygen/test/contents_sections_headings/File.h
index 33a7dbc43035831cb61cf91ff99f40b976d54322..3690b455134e36d5c1b0bd7b676ce21faa854091 100644 (file)
@@ -11,8 +11,6 @@
 
 ### A third-level header
 
-#### A fourth-level header
-
 @section foo-usage Usage
 
 This is usage.
@@ -29,3 +27,14 @@ Mooore.
 @return Does not return anything.
 */
 void foo(int bar);
+
+/**
+@brief This produces warnings
+
+#### Markdown heading 4 that's rendered the same as 3
+
+Markdown heading, underlined, is misparsed
+##########################################
+
+*/
+void bar(int foo);
similarity index 73%
rename from doxygen/test/contents_section_in_function/File_8h.html
rename to doxygen/test/contents_sections_headings/File_8h.html
index 3a6c4d8615d6058f5da3d5068fbb30fd73dffa78..3d41564375690de80435cd1c74561ff4d46d9552 100644 (file)
               <span class="m-dox-wrap-bumper">void <a href="#adc5bb4b0f2fddd234994abbe97abb8b1" class="m-dox">foo</a>(</span><span class="m-dox-wrap">int bar)</span>
             </dt>
             <dd>A function.</dd>
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#ac03b94e5ed1aeeba4c9d31498e9a767a" class="m-dox">bar</a>(</span><span class="m-dox-wrap">int foo)</span>
+            </dt>
+            <dd>This produces warnings.</dd>
           </dl>
         </section>
         <section>
                 </tr>
               </tfoot>
             </table>
-<h4>A top-level header</h4><h5>A second-level header</h5><h6>A third-level header</h6><h6>A fourth-level header</h6><h4 id="foo-usage">Usage</h4><p>This is usage.</p><h5 id="foo-usage-more">More</h5><p>A subsection.</p><h6 id="foo-usage-more-more">More.</h6><p>Mooore.</p>
+<h4>A top-level header</h4><h5>A second-level header</h5><h6>A third-level header</h6><h4 id="foo-usage">Usage</h4><p>This is usage.</p><h5 id="foo-usage-more">More</h5><p>A subsection.</p><h6 id="foo-usage-more-more">More.</h6><p>Mooore.</p>
+          </div></section>
+          <section class="m-dox-details" id="ac03b94e5ed1aeeba4c9d31498e9a767a"><div>
+            <h3>
+              <span class="m-dox-wrap-bumper">void </span><span class="m-dox-wrap"><span class="m-dox-wrap-bumper"><a href="#ac03b94e5ed1aeeba4c9d31498e9a767a" class="m-dox-self">bar</a>(</span><span class="m-dox-wrap">int foo)</span></span>
+            </h3>
+            <p>This produces warnings.</p>
+<h6>Markdown heading 4 that&#x27;s rendered the same as 3</h6><p>Markdown heading, underlined, is misparsed</p>
           </div></section>
         </section>
       </div>
diff --git a/doxygen/test/contents_sections_headings/index.html b/doxygen/test/contents_sections_headings/index.html
new file mode 100644 (file)
index 0000000..207ac68
--- /dev/null
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>My Project</title>
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+  <link rel="stylesheet" href="m-dark+doxygen.compiled.css" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+  <div class="m-container">
+    <div class="m-row">
+      <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Project</a>
+    </div>
+  </div>
+</nav></header>
+<main><article>
+  <div class="m-container m-container-inflatable">
+    <div class="m-row">
+      <div class="m-col-l-10 m-push-l-1">
+        <h1>
+          My Project
+        </h1>
+<section id="section"><h2><a href="#section">Page section</a></h2><p>Text.</p><section id="subsection"><h3><a href="#subsection">Page subsection</a></h3><p>Text!</p><section id="subsubsection"><h4><a href="#subsubsection">Sub-sub section</a></h4><p>Reference to <a href="index.html#subsection" class="m-dox">a page subsection</a> and <a href="index.html#subsubsection" class="m-dox">Sub-sub section</a>.</p></section></section></section>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/doxygen/test/contents_sections_headings/input.dox b/doxygen/test/contents_sections_headings/input.dox
new file mode 100644 (file)
index 0000000..14d93a4
--- /dev/null
@@ -0,0 +1,34 @@
+/** @mainpage
+
+@section section Page section
+
+Text.
+
+@subsection subsection Page subsection
+
+Text!
+
+@subsubsection subsubsection Sub-sub section
+
+Reference to @ref subsection "a page subsection" and @ref subsubsection.
+
+*/
+
+/** @page warnings Content that produces warnings
+
+# Markdown heading 1
+
+## Markdown heading 2
+
+### Markdown heading 3
+
+#### Markdown heading 4
+
+##### Markdown heading 5
+
+###### Markdown heading 6 that's rendered the same as 5
+
+Markdown heading, underlined, is misparsed
+##########################################
+
+*/
similarity index 84%
rename from doxygen/test/contents_typography/warnings.html
rename to doxygen/test/contents_sections_headings/warnings.html
index b1d8baffebfc8fbcd48a7fda0a52f6f87f5672b7..eef8cc98540a8766c8f4c879b4cd1362f749d3b6 100644 (file)
@@ -22,7 +22,7 @@
         <h1>
           Content that produces warnings
         </h1>
-<h2>Markdown heading 1</h2><h3>Markdown heading 2</h3><h4>Markdown heading 3</h4><h5>Markdown heading 4</h5>
+<h2>Markdown heading 1</h2><h3>Markdown heading 2</h3><h4>Markdown heading 3</h4><h5>Markdown heading 4</h5><h6>Markdown heading 5</h6><h6>Markdown heading 6 that&#x27;s rendered the same as 5</h6><p>Markdown heading, underlined, is misparsed</p>
       </div>
     </div>
   </div>
index ccbce771a5b13b77139d5d054488241b2e6dab9a..c8e529b8d10e43303efa260390f89b4320392754 100644 (file)
         <h1>
           My Project
         </h1>
-<section id="section"><h2><a href="#section">Page section</a></h2><blockquote><p>A blockquote.</p></blockquote><pre>Preformatted text.
-</pre><p>Paragraph<br />with<br />explicit<br />line<br />breaks.</p><pre>Differently
+<blockquote><p>A blockquote.</p></blockquote><pre>Preformatted text.
+</pre><p>Paragraph<br />with<br />explicit<br />line<br />breaks.</p><section id="section"><h2><a href="#section">Page section</a></h2><pre>Differently
   preformatted
-text.</pre><section id="subsection"><h3><a href="#subsection">Page subsection</a></h3><ul><li>Unordered</li><li>list</li><li>of<ul><li>nested</li><li>items</li></ul></li><li>and back</li></ul><section id="subsubsection"><h4><a href="#subsubsection">Sub-sub section</a></h4><ol><li>Ordered</li><li>list</li><li>of<ol><li>nested</li><li>items</li></ol></li><li>and back</li></ol><p><a name="an-anchor"></a> This is a <code>typewriter text</code>, <em>emphasis</em> and <strong>bold</strong>. <em>Emphasis with <code>typewriter</code> and <strong>bold</strong> nested.</em> <a href="http://google.com">http:/<wbr />/<wbr />google.com</a> and <a href="http://google.com">URL</a>. <small>Small <em>text</em>.</small> En-dash &ndash; and em-dash &mdash;. Reference to a <a href="index.html#subsection" class="m-dox">Page subsection</a>. Named reference with special characters in title: <a href="warnings.html" class="m-dox">&raquo; Warnings &laquo;</a>. Reference with escaped characters in&nbsp;title: <a href="index.html#an-anchor" class="m-dox">&lt;anchor&gt;</a>.</p><p>Empty elements:</p><pre></pre><hr/><p>Above is a horizontal line.</p></section></section></section>
+text.</pre><ul><li>Unordered</li><li>list</li><li>of<ul><li>nested</li><li>items</li></ul></li><li>and back</li></ul><ol><li>Ordered</li><li>list</li><li>of<ol><li>nested</li><li>items</li></ol></li><li>and back</li></ol><p><a name="an-anchor"></a> This is a <code>typewriter text</code>, <em>emphasis</em> and <strong>bold</strong>. <em>Emphasis with <code>typewriter</code> and <strong>bold</strong> nested.</em> <a href="http://google.com">http:/<wbr />/<wbr />google.com</a> and <a href="http://google.com">URL</a>. <small>Small <em>text</em>.</small> En-dash &ndash; and em-dash &mdash;. Reference to a <a href="index.html#section" class="m-dox">Page section</a>. Named reference with special characters in title: <a href="index.html#section" class="m-dox">&raquo; Warnings &laquo;</a>. Reference with escaped characters in&nbsp;title: <a href="index.html#an-anchor" class="m-dox">&lt;anchor&gt;</a>.</p><p>Empty elements:</p><pre></pre><hr/><p>Above is a horizontal line.</p></section>
       </div>
     </div>
   </div>
index 86d248def7bffc1922dfd8611ab184d694569add..bf3ec4841c91d4673f0baa333bb8668b8fba96dc 100644 (file)
@@ -1,19 +1,17 @@
 /** @mainpage
 
-@section section Page section
-
 > A blockquote.
 
     Preformatted text.
 
 Paragraph \n with \n explicit \n line \n breaks.
 
+@section section Page section
+
 <pre>Differently
   preformatted
 text.</pre>
 
-@subsection subsection Page subsection
-
 -   Unordered
 -   list
 -   of
@@ -21,8 +19,6 @@ text.</pre>
     -   items
 -   and back
 
-@subsubsection subsubsection Sub-sub section
-
 1.  Ordered
 2.  list
 3.  of
@@ -35,8 +31,8 @@ text.</pre>
 This is a `typewriter text`, *emphasis* and **bold**. <em>Emphasis with
 <tt>typewriter</tt> and <strong>bold</strong> nested.</em> http://google.com
 and [URL](http://google.com). <small>Small *text*.</small> En-dash -- and
-em-dash ---. Reference to a @ref subsection. Named reference with special
-characters in title: @ref warnings "&raquo; Warnings &laquo;". Reference with
+em-dash ---. Reference to a @ref section. Named reference with special
+characters in title: @ref section "&raquo; Warnings &laquo;". Reference with
 escaped characters in&nbsp;title: @ref an-anchor "<anchor>".
 
 Empty elements: <em></em> <tt></tt> <strong></strong> <pre></pre> <small></small>
@@ -46,15 +42,3 @@ Empty elements: <em></em> <tt></tt> <strong></strong> <pre></pre> <small></small
 Above is a horizontal line.
 
 */
-
-/** @page warnings Content that produces warnings
-
-# Markdown heading 1
-
-## Markdown heading 2
-
-### Markdown heading 3
-
-#### Markdown heading 4
-
-*/
index 841a5793946bade70865843089130012946a0b9e..721db559876fd612ae690ab88e136fdfed0e2e98 100644 (file)
@@ -42,10 +42,6 @@ class Typography(IntegrationTestCase):
         self.run_dox2html5(wildcard='indexpage.xml')
         self.assertEqual(*self.actual_expected_contents('index.html'))
 
-    def test_warnings(self):
-        self.run_dox2html5(wildcard='warnings.xml')
-        self.assertEqual(*self.actual_expected_contents('warnings.html'))
-
 class Blocks(IntegrationTestCase):
     def __init__(self, *args, **kwargs):
         super().__init__(__file__, 'blocks', *args, **kwargs)
@@ -301,11 +297,19 @@ class SectionUnderscoreOne(IntegrationTestCase):
         self.run_dox2html5(wildcard='indexpage.xml')
         self.assertEqual(*self.actual_expected_contents('index.html'))
 
-class SectionInFunction(IntegrationTestCase):
+class SectionsHeadings(IntegrationTestCase):
     def __init__(self, *args, **kwargs):
-        super().__init__(__file__, 'section_in_function', *args, **kwargs)
+        super().__init__(__file__, 'sections_headings', *args, **kwargs)
 
     def test(self):
+        self.run_dox2html5(wildcard='indexpage.xml')
+        self.assertEqual(*self.actual_expected_contents('index.html'))
+
+    def test_warnings(self):
+        self.run_dox2html5(wildcard='warnings.xml')
+        self.assertEqual(*self.actual_expected_contents('warnings.html'))
+
+    def test_functions(self):
         self.run_dox2html5(wildcard='File_8h.xml')
         self.assertEqual(*self.actual_expected_contents('File_8h.html'))