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.
This commit is contained in:
Andrey Makarov
2023-04-02 11:32:36 +03:00
committed by GitHub
parent 0c6f14af04
commit 63b4b3c5b8
6 changed files with 40 additions and 14 deletions

View File

@@ -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

View File

@@ -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) =

View File

@@ -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;
@@ -392,6 +393,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>

View File

@@ -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

View File

@@ -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"

View File

@@ -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