summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndrey Makarov <ph.makarov@gmail.com>2023-04-02 11:32:36 +0300
committerGitHub <noreply@github.com>2023-04-02 10:32:36 +0200
commit63b4b3c5b8c930ffc271c5e4e1a446e8616b2571 (patch)
treee5c589c3477f1f0beebae87e510b8b522ffcc830
parent0c6f14af048c4bd61c91552af79c003dfd34601e (diff)
downloadNim-63b4b3c5b8c930ffc271c5e4e1a446e8616b2571.tar.gz
Fix nim doc crash with group referencing & include (#21600)
This fixes a regression introduced in #20990 . When a group referencing
is used and one of the overloaded symbols is in `include`d file, then
`nim doc` crashes. The fix is in distinguishing (the index of) module
and file where the symbol is defined, and using only module as the
key in hash table for group referencing.
-rw-r--r--compiler/docgen.nim17
-rw-r--r--lib/packages/docutils/rst.nim14
-rw-r--r--nimdoc/testproject/expected/subdir/subdir_b/utils.html13
-rw-r--r--nimdoc/testproject/expected/subdir/subdir_b/utils.idx3
-rw-r--r--nimdoc/testproject/expected/theindex.html2
-rw-r--r--nimdoc/testproject/subdir/subdir_b/utils_helpers.nim5
6 files changed, 40 insertions, 14 deletions
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 8105cc807..4a8e38054 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -112,13 +112,16 @@ type
 proc add(dest: var ItemPre, rst: PRstNode) = dest.add ItemFragment(isRst: true, rst: rst)
 proc add(dest: var ItemPre, str: string) = dest.add ItemFragment(isRst: false, str: str)
 
-proc addRstFileIndex(d: PDoc, info: lineinfos.TLineInfo): rstast.FileIndex =
+proc addRstFileIndex(d: PDoc, fileIndex: lineinfos.FileIndex): rstast.FileIndex =
   let invalid = rstast.FileIndex(-1)
-  result = d.nimToRstFid.getOrDefault(info.fileIndex, default = invalid)
+  result = d.nimToRstFid.getOrDefault(fileIndex, default = invalid)
   if result == invalid:
-    let fname = toFullPath(d.conf, info)
+    let fname = toFullPath(d.conf, fileIndex)
     result = addFilename(d.sharedState, fname)
-    d.nimToRstFid[info.fileIndex] = result
+    d.nimToRstFid[fileIndex] = result
+
+proc addRstFileIndex(d: PDoc, info: lineinfos.TLineInfo): rstast.FileIndex =
+  addRstFileIndex(d, info.fileIndex)
 
 proc cmpDecimalsIgnoreCase(a, b: string): int =
   ## For sorting with correct handling of cases like 'uint8' and 'uint16'.
@@ -1060,7 +1063,8 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
       fileIndex: addRstFileIndex(d, nameNode.info))
   addAnchorNim(d.sharedState, external = false, refn = symbolOrId,
                tooltip = detailedName, langSym = rstLangSymbol,
-               priority = symbolPriority(k), info = lineinfo)
+               priority = symbolPriority(k), info = lineinfo,
+               module = addRstFileIndex(d, FileIndex d.module.position))
 
   let renderFlags =
     if nonExports: {renderNoBody, renderNoComments, renderDocComments, renderSyms,
@@ -1451,7 +1455,8 @@ proc finishGenerateDoc*(d: var PDoc) =
                                   isGroup: true),
                        priority = symbolPriority(k),
                        # select index `0` just to have any meaningful warning:
-                       info = overloadChoices[0].info)
+                       info = overloadChoices[0].info,
+                       module = addRstFileIndex(d, FileIndex d.module.position))
 
   if optGenIndexOnly in d.conf.globalOptions:
     return
diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim
index b3b1fb9c0..6d05a2454 100644
--- a/lib/packages/docutils/rst.nim
+++ b/lib/packages/docutils/rst.nim
@@ -350,7 +350,7 @@ type
     footnoteAnchor = "footnote anchor",
     headlineAnchor = "implicitly-generated headline anchor"
   AnchorSubst = object
-    info: TLineInfo         # where the anchor was defined
+    info: TLineInfo         # the file where the anchor was defined
     priority: int
     case kind: range[arInternalRst .. arNim]
     of arInternalRst:
@@ -360,6 +360,7 @@ type
       anchorTypeExt: RstAnchorKind
       refnameExt: string
     of arNim:
+      module: FileIndex     # anchor's module (generally not the same as file)
       tooltip: string       # displayed tooltip for Nim-generated anchors
       langSym: LangSymbol
       refname: string     # A reference name that will be inserted directly
@@ -520,6 +521,9 @@ proc getFilename(filenames: RstFileTable, fid: FileIndex): string =
 proc getFilename(s: PRstSharedState, subst: AnchorSubst): string =
   getFilename(s.filenames, subst.info.fileIndex)
 
+proc getModule(s: PRstSharedState, subst: AnchorSubst): string =
+  result = getFilename(s.filenames, subst.module)
+
 proc currFilename(s: PRstSharedState): string =
   getFilename(s.filenames, s.currFileIdx)
 
@@ -830,7 +834,7 @@ proc addAnchorExtRst(s: var PRstSharedState, key: string, refn: string,
 
 proc addAnchorNim*(s: var PRstSharedState, external: bool, refn: string, tooltip: string,
                    langSym: LangSymbol, priority: int,
-                   info: TLineInfo) =
+                   info: TLineInfo, module: FileIndex) =
   ## Adds an anchor `refn`, which follows
   ## the rule `arNim` (i.e. a symbol in ``*.nim`` file)
   s.anchors.mgetOrPut(langSym.name, newSeq[AnchorSubst]()).add(
@@ -859,7 +863,7 @@ proc findMainAnchorNim(s: PRstSharedState, signature: PRstNode,
   for subst in substitutions:
     if subst.kind == arNim:
       if match(subst.langSym, langSym):
-        let key: GroupKey = (subst.langSym.symKind, getFilename(s, subst))
+        let key: GroupKey = (subst.langSym.symKind, getModule(s, subst))
         found.mgetOrPut(key, newSeq[AnchorSubst]()).add subst
   for key, sList in found:
     if sList.len == 1:
@@ -880,7 +884,7 @@ proc findMainAnchorNim(s: PRstSharedState, signature: PRstNode,
             break
         doAssert(foundGroup,
                  "docgen has not generated the group for $1 (file $2)" % [
-                 langSym.name, getFilename(s, sList[0]) ])
+                 langSym.name, getModule(s, sList[0]) ])
 
 proc findMainAnchorRst(s: PRstSharedState, linkText: string, info: TLineInfo):
                       seq[AnchorSubst] =
@@ -3552,7 +3556,7 @@ proc loadIdxFile(s: var PRstSharedState, origFilename: string) =
         langSym = langSymbolGroup(kind=entry.linkTitle, name=entry.keyword)
       addAnchorNim(s, external = true, refn = refn, tooltip = entry.linkDesc,
                    langSym = langSym, priority = -4, # lowest
-                   info=info)
+                   info = info, module = info.fileIndex)
   doAssert s.idxImports[origFilename].title != ""
 
 proc preparePass2*(s: var PRstSharedState, mainNode: PRstNode, importdoc = true) =
diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html
index ee2618ab3..cfdac5310 100644
--- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html
+++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html
@@ -106,6 +106,7 @@
   <li><a class="reference" href="#fn2" title="fn2()">fn2()</a></li>
 <li><a class="reference" href="#fn2%2Cint" title="fn2(x: int)">fn2(x: int)</a></li>
 <li><a class="reference" href="#fn2%2Cint%2Cfloat" title="fn2(x: int; y: float)">fn2(x: int; y: float)</a></li>
+<li><a class="reference" href="#fn2%2Cint%2Cfloat%2Cfloat" title="fn2(x: int; y: float; z: float)">fn2(x: int; y: float; z: float)</a></li>
 
 </ul>
 <ul class="simple nested-toc-section">fn3
@@ -215,7 +216,7 @@
 <ol class="simple"><li>Other case value</li>
 <li>Second case.</li>
 </ol>
-<p>Ref group <a class="reference internal nimdoc" title="proc fn2 (3 overloads)" href="#fn2-procs-all">fn2</a> or specific function like <a class="reference internal nimdoc" title="proc fn2()" href="#fn2">fn2()</a> or <a class="reference internal nimdoc" title="proc fn2(x: int)" href="#fn2,int">fn2( int )</a> or <a class="reference internal nimdoc" title="proc fn2(x: int; y: float)" href="#fn2,int,float">fn2(int, float)</a>.</p>
+<p>Ref group <a class="reference internal nimdoc" title="proc fn2 (4 overloads)" href="#fn2-procs-all">fn2</a> or specific function like <a class="reference internal nimdoc" title="proc fn2()" href="#fn2">fn2()</a> or <a class="reference internal nimdoc" title="proc fn2(x: int)" href="#fn2,int">fn2( int )</a> or <a class="reference internal nimdoc" title="proc fn2(x: int; y: float)" href="#fn2,int,float">fn2(int, float)</a>.</p>
 <p>Ref generics like this: <a class="reference internal nimdoc" title="proc binarySearch[T, K](a: openArray[T]; key: K;
                    cmp: proc (x: T; y: K): int {.closure.}): int" href="#binarySearch,openArray[T],K,proc(T,K)">binarySearch</a> or <a class="reference internal nimdoc" title="proc binarySearch[T, K](a: openArray[T]; key: K;
                    cmp: proc (x: T; y: K): int {.closure.}): int" href="#binarySearch,openArray[T],K,proc(T,K)">binarySearch(openArray[T], K, proc (T, K))</a> or <a class="reference internal nimdoc" title="proc binarySearch[T, K](a: openArray[T]; key: K;
@@ -229,7 +230,7 @@
 <p>Group ref. with capital letters works: <a class="reference internal nimdoc" title="proc fN11 (2 overloads)" href="#fN11-procs-all">fN11</a> or <a class="reference internal nimdoc" title="proc fN11 (2 overloads)" href="#fN11-procs-all">fn11</a> </p>
 Ref. <a class="reference internal nimdoc" title="proc `[]`[T](x: G[T]): T" href="#[],G[T]">[]</a> is the same as <a class="reference internal nimdoc" title="proc `[]`[T](x: G[T]): T" href="#[],G[T]">proc `[]`(G[T])</a> because there are no overloads. The full form: <a class="reference internal nimdoc" title="proc `[]`[T](x: G[T]): T" href="#[],G[T]">proc `[]`*[T](x: G[T]): T</a>Ref. <a class="reference internal nimdoc" title="proc `[]=`[T](a: var G[T]; index: int; value: T)" href="#[]=,G[T],int,T">[]=</a> aka <a class="reference internal nimdoc" title="proc `[]=`[T](a: var G[T]; index: int; value: T)" href="#[]=,G[T],int,T">`[]=`(G[T], int, T)</a>.Ref. <a class="reference internal nimdoc" title="proc $ (2 overloads)" href="#$-procs-all">$</a> aka <a class="reference internal nimdoc" title="proc $ (2 overloads)" href="#$-procs-all">proc $</a> or <a class="reference internal nimdoc" title="proc $ (2 overloads)" href="#$-procs-all">proc `$`</a>.Ref. <a class="reference internal nimdoc" title="proc `$`[T](a: ref SomeType): string" href="#$,ref.SomeType">$(a: ref SomeType)</a>.Ref. <a class="reference internal nimdoc" title="iterator fooBar(a: seq[SomeType]): int" href="#fooBar.i,seq[SomeType]">foo_bar</a> aka <a class="reference internal nimdoc" title="iterator fooBar(a: seq[SomeType]): int" href="#fooBar.i,seq[SomeType]">iterator foo_bar_</a>.Ref. <a class="reference internal nimdoc" title="proc fn[T; U, V: SomeFloat]()" href="#fn">fn[T; U,V: SomeFloat]()</a>.Ref. <a class="reference internal nimdoc" title="proc `'big`(a: string): SomeType" href="#'big,string">'big</a> or <a class="reference internal nimdoc" title="proc `'big`(a: string): SomeType" href="#'big,string">func `'big`</a> or <a class="reference internal nimdoc" title="proc `'big`(a: string): SomeType" href="#'big,string">`'big`(string)</a>.
 <h1><a class="toc-backref" id="pandoc-markdown" href="#pandoc-markdown">Pandoc Markdown</a></h1><p>Now repeat all the auto links of above in Pandoc Markdown Syntax.</p>
-<p>Ref group <a class="reference internal nimdoc" title="proc fn2 (3 overloads)" href="#fn2-procs-all">fn2</a> or specific function like <a class="reference internal nimdoc" title="proc fn2()" href="#fn2">fn2()</a> or <a class="reference internal nimdoc" title="proc fn2(x: int)" href="#fn2,int">fn2(  int  )</a> or <a class="reference internal nimdoc" title="proc fn2(x: int; y: float)" href="#fn2,int,float">fn2(int, float)</a>.</p>
+<p>Ref group <a class="reference internal nimdoc" title="proc fn2 (4 overloads)" href="#fn2-procs-all">fn2</a> or specific function like <a class="reference internal nimdoc" title="proc fn2()" href="#fn2">fn2()</a> or <a class="reference internal nimdoc" title="proc fn2(x: int)" href="#fn2,int">fn2(  int  )</a> or <a class="reference internal nimdoc" title="proc fn2(x: int; y: float)" href="#fn2,int,float">fn2(int, float)</a>.</p>
 <p>Ref generics like this: <a class="reference internal nimdoc" title="proc binarySearch[T, K](a: openArray[T]; key: K;
                    cmp: proc (x: T; y: K): int {.closure.}): int" href="#binarySearch,openArray[T],K,proc(T,K)">binarySearch</a> or <a class="reference internal nimdoc" title="proc binarySearch[T, K](a: openArray[T]; key: K;
                    cmp: proc (x: T; y: K): int {.closure.}): int" href="#binarySearch,openArray[T],K,proc(T,K)">binarySearch(openArray[T], K, proc (T, K))</a> or <a class="reference internal nimdoc" title="proc binarySearch[T, K](a: openArray[T]; key: K;
@@ -394,6 +395,14 @@ Ref. <a class="reference internal nimdoc" title="proc `[]`[T](x: G[T]): T" href=
     
   </dd>
 </div>
+<div id="fn2,int,float,float">
+  <dt><pre><span class="Keyword">proc</span> <a href="#fn2%2Cint%2Cfloat%2Cfloat"><span class="Identifier">fn2</span></a><span class="Other">(</span><span class="Identifier">x</span><span class="Other">:</span> <span class="Identifier">int</span><span class="Other">;</span> <span class="Identifier">y</span><span class="Other">:</span> <span class="Identifier">float</span><span class="Other">;</span> <span class="Identifier">z</span><span class="Other">:</span> <span class="Identifier">float</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">forbids</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
+  <dd>
+    
+    
+    
+  </dd>
+</div>
 
 </div>
 <div id="fn3-procs-all">
diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.idx b/nimdoc/testproject/expected/subdir/subdir_b/utils.idx
index 81c2103e4..81b27bcb9 100644
--- a/nimdoc/testproject/expected/subdir/subdir_b/utils.idx
+++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.idx
@@ -1,5 +1,6 @@
 nimTitle	utils	subdir/subdir_b/utils.html	module subdir/subdir_b/utils		0
 nim	funWithGenerics	subdir/subdir_b/utils.html#funWithGenerics,T,U	proc funWithGenerics[T, U: SomeFloat](a: T; b: U)		1
+nim	fn2	subdir/subdir_b/utils.html#fn2,int,float,float	proc fn2(x: int; y: float; z: float)		5
 nim	enumValueA	subdir/subdir_b/utils.html#enumValueA	SomeType.enumValueA		45
 nim	enumValueB	subdir/subdir_b/utils.html#enumValueB	SomeType.enumValueB		45
 nim	enumValueC	subdir/subdir_b/utils.html#enumValueC	SomeType.enumValueC		45
@@ -34,7 +35,7 @@ nim	fn	subdir/subdir_b/utils.html#fn	proc fn[T; U, V: SomeFloat]()		160
 nim	`'big`	subdir/subdir_b/utils.html#'big,string	proc `'big`(a: string): SomeType		164
 nimgrp	$	subdir/subdir_b/utils.html#$-procs-all	proc		148
 nimgrp	fn11	subdir/subdir_b/utils.html#fN11-procs-all	proc		85
-nimgrp	fn2	subdir/subdir_b/utils.html#fn2-procs-all	proc		57
+nimgrp	fn2	subdir/subdir_b/utils.html#fn2-procs-all	proc		5
 nimgrp	f	subdir/subdir_b/utils.html#f-procs-all	proc		130
 heading	This is now a header	subdir/subdir_b/utils.html#this-is-now-a-header	 This is now a header		0
 heading	Next header	subdir/subdir_b/utils.html#this-is-now-a-header-next-header	  Next header		0
diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html
index f9488eb2d..fd4666bf9 100644
--- a/nimdoc/testproject/expected/theindex.html
+++ b/nimdoc/testproject/expected/theindex.html
@@ -175,6 +175,8 @@
           data-doc-search-tag="utils: proc fn2(x: int)" href="subdir/subdir_b/utils.html#fn2%2Cint">utils: proc fn2(x: int)</a></li>
           <li><a class="reference external"
           data-doc-search-tag="utils: proc fn2(x: int; y: float)" href="subdir/subdir_b/utils.html#fn2%2Cint%2Cfloat">utils: proc fn2(x: int; y: float)</a></li>
+          <li><a class="reference external"
+          data-doc-search-tag="utils: proc fn2(x: int; y: float; z: float)" href="subdir/subdir_b/utils.html#fn2%2Cint%2Cfloat%2Cfloat">utils: proc fn2(x: int; y: float; z: float)</a></li>
           </ul></dd>
 <dt><a name="fn3" href="#fn3"><span>fn3:</span></a></dt><dd><ul class="simple">
 <li><a class="reference external"
diff --git a/nimdoc/testproject/subdir/subdir_b/utils_helpers.nim b/nimdoc/testproject/subdir/subdir_b/utils_helpers.nim
index 2c45ffb83..d3f5edd29 100644
--- a/nimdoc/testproject/subdir/subdir_b/utils_helpers.nim
+++ b/nimdoc/testproject/subdir/subdir_b/utils_helpers.nim
@@ -1 +1,6 @@
 proc funWithGenerics*[T, U: SomeFloat](a: T, b: U) = discard
+
+# We check that presence of overloaded `fn2` here does not break
+# referencing in the "parent" file (the one that includes this one)
+proc fn2*(x: int, y: float, z: float) =
+  discard