summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorJake Leahy <jake@leahy.dev>2023-07-17 03:46:18 +1000
committerGitHub <noreply@github.com>2023-07-16 19:46:18 +0200
commit17915d93bfb50aaff6c4bf77fe25707705e557c8 (patch)
tree733c75bfc3aca4f8b412e6940abc3b8eb30f744c
parent50d435cd3941f6c7f71a2e2b91cfa40a5a4efcb9 (diff)
downloadNim-17915d93bfb50aaff6c4bf77fe25707705e557c8.tar.gz
Fix non-toplevel fields in objects not getting rendered (#22266)
* Add example object into testproject

The proc is there to check the case of an identDef being inside an identDef (We do want to render those even if they are not exported)

* Add `inside` set to `TSrcGen` which allows us to see what context we are in

This is done instead of adding another inXyz bool parameter

We then use this to know if we are inside an object when rendering an nkIdentDefs (To know if we need to skip rendering it)

* Update test files
-rw-r--r--compiler/renderer.nim95
-rw-r--r--nimdoc/testproject/expected/testproject.html23
-rw-r--r--nimdoc/testproject/expected/testproject.idx1
-rw-r--r--nimdoc/testproject/expected/theindex.html4
-rw-r--r--nimdoc/testproject/testproject.nim8
5 files changed, 106 insertions, 25 deletions
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index 3f237c932..ac4ff2a77 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -31,6 +31,10 @@ type
     length*: int16
     sym*: PSym
 
+  Section = enum
+    GenericParams
+    ObjectDef
+
   TRenderTokSeq* = seq[TRenderTok]
   TSrcGen* = object
     indent*: int
@@ -45,7 +49,7 @@ type
     pendingWhitespace: int
     comStack*: seq[PNode]  # comment stack
     flags*: TRenderFlags
-    inGenericParams: bool
+    inside: set[Section] # Keeps track of contexts we are in
     checkAnon: bool        # we're in a context that can contain sfAnon
     inPragma: int
     when defined(nimpretty):
@@ -73,6 +77,16 @@ proc isKeyword*(i: PIdent): bool =
       (i.id <= ord(tokKeywordHigh) - ord(tkSymbol)):
     result = true
 
+proc isExported(n: PNode): bool =
+  ## Checks if an ident is exported.
+  ## This is meant to be used with idents in nkIdentDefs.
+  case n.kind
+  of nkPostfix:
+    n[0].ident.s == "*" and n[1].kind == nkIdent
+  of nkPragmaExpr:
+    n[0].isExported()
+  else: false
+
 proc renderDefinitionName*(s: PSym, noQuotes = false): string =
   ## Returns the definition name of the symbol.
   ##
@@ -85,6 +99,25 @@ proc renderDefinitionName*(s: PSym, noQuotes = false): string =
   else:
     result = '`' & x & '`'
 
+template inside(g: var TSrcGen, section: Section, body: untyped) =
+  ## Runs `body` with `section` included in `g.inside`.
+  ## Removes it at the end of the body if `g` wasn't inside it
+  ## before the template.
+  let wasntInSection = section notin g.inside
+  g.inside.incl section
+  body
+  if wasntInSection:
+    g.inside.excl section
+
+template outside(g: var TSrcGen, section: Section, body: untyped) =
+  ## Temporarily removes `section` from `g.inside`. Adds it back
+  ## at the end of the body if `g` was inside it before the template
+  let wasInSection = section in g.inside
+  g.inside.excl section
+  body
+  if wasInSection:
+    g.inside.incl section
+
 const
   IndentWidth = 2
   longIndentWid = IndentWidth * 2
@@ -121,7 +154,7 @@ proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags; config: ConfigRef) =
   g.flags = renderFlags
   g.pendingNL = -1
   g.pendingWhitespace = -1
-  g.inGenericParams = false
+  g.inside = {}
   g.config = config
 
 proc addTok(g: var TSrcGen, kind: TokType, s: string; sym: PSym = nil) =
@@ -831,14 +864,12 @@ proc gproc(g: var TSrcGen, n: PNode) =
 
   if n[patternPos].kind != nkEmpty:
     gpattern(g, n[patternPos])
-  let oldInGenericParams = g.inGenericParams
-  g.inGenericParams = true
-  if renderNoBody in g.flags and n[miscPos].kind != nkEmpty and
-      n[miscPos][1].kind != nkEmpty:
-    gsub(g, n[miscPos][1])
-  else:
-    gsub(g, n[genericParamsPos])
-  g.inGenericParams = oldInGenericParams
+  g.inside(GenericParams):
+    if renderNoBody in g.flags and n[miscPos].kind != nkEmpty and
+        n[miscPos][1].kind != nkEmpty:
+      gsub(g, n[miscPos][1])
+    else:
+      gsub(g, n[genericParamsPos])
   gsub(g, n[paramsPos])
   if renderNoPragmas notin g.flags:
     gsub(g, n[pragmasPos])
@@ -916,7 +947,7 @@ proc gasm(g: var TSrcGen, n: PNode) =
     gsub(g, n[1])
 
 proc gident(g: var TSrcGen, n: PNode) =
-  if g.inGenericParams and n.kind == nkSym:
+  if GenericParams in g.inside and n.kind == nkSym:
     if sfAnon in n.sym.flags or
       (n.typ != nil and tfImplicitTypeParam in n.typ.flags): return
 
@@ -1304,14 +1335,31 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
     gsub(g, n, pragmasPos)
     put(g, tkColon, ":")
     gsub(g, n, bodyPos)
-  of nkConstDef, nkIdentDefs:
+  of nkIdentDefs:
+    # Skip if this is a property in a type and its not exported
+    # (While also not allowing rendering of non exported fields)
+    if ObjectDef in g.inside and (not n[0].isExported() and renderNonExportedFields notin g.flags):
+      return
+    # We render the identDef without being inside the section incase we render something like
+    # y: proc (x: string) # (We wouldn't want to check if x is exported)
+    g.outside(ObjectDef):
+      gcomma(g, n, 0, -3)
+      if n.len >= 2 and n[^2].kind != nkEmpty:
+        putWithSpace(g, tkColon, ":")
+        gsub(g, n[^2], c)
+      elif n.referencesUsing and renderExpandUsing in g.flags:
+        putWithSpace(g, tkColon, ":")
+        gsub(g, newSymNode(n.origUsingType), c)
+
+      if n.len >= 1 and n[^1].kind != nkEmpty:
+        put(g, tkSpaces, Space)
+        putWithSpace(g, tkEquals, "=")
+        gsub(g, n[^1], c)
+  of nkConstDef:
     gcomma(g, n, 0, -3)
     if n.len >= 2 and n[^2].kind != nkEmpty:
       putWithSpace(g, tkColon, ":")
       gsub(g, n[^2], c)
-    elif n.referencesUsing and renderExpandUsing in g.flags:
-      putWithSpace(g, tkColon, ":")
-      gsub(g, newSymNode(n.origUsingType), c)
 
     if n.len >= 1 and n[^1].kind != nkEmpty:
       put(g, tkSpaces, Space)
@@ -1468,20 +1516,19 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
   of nkObjectTy:
     if n.len > 0:
       putWithSpace(g, tkObject, "object")
-      gsub(g, n[0])
-      gsub(g, n[1])
-      gcoms(g)
-      gsub(g, n[2])
+      g.inside(ObjectDef):
+        gsub(g, n[0])
+        gsub(g, n[1])
+        gcoms(g)
+        gsub(g, n[2])
     else:
       put(g, tkObject, "object")
   of nkRecList:
     indentNL(g)
     for i in 0..<n.len:
-      if n[i].kind == nkIdentDefs and n[i][0].skipPragmaExpr.kind == nkPostfix or
-                        renderNonExportedFields in g.flags:
-        optNL(g)
-        gsub(g, n[i], c)
-        gcoms(g)
+      optNL(g)
+      gsub(g, n[i], c)
+      gcoms(g)
     dedent(g)
     putNL(g)
   of nkOfInherit:
diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html
index a5c9b6af2..78a730e59 100644
--- a/nimdoc/testproject/expected/testproject.html
+++ b/nimdoc/testproject/expected/testproject.html
@@ -56,6 +56,12 @@
     <ul class="simple simple-toc-section">
       <li><a class="reference" href="#A" title="A {.inject.} = enum
   aA">A</a></li>
+<li><a class="reference" href="#AnotherObject" title="AnotherObject = object
+  case x*: bool
+  of true:
+      y*: proc (x: string)
+
+  of false:">AnotherObject</a></li>
 <li><a class="reference" href="#B" title="B {.inject.} = enum
   bB">B</a></li>
 <li><a class="reference" href="#Foo" title="Foo = enum
@@ -370,6 +376,21 @@
     
   </dd>
 </div>
+<div id="AnotherObject">
+  <dt><pre><a href="testproject.html#AnotherObject"><span class="Identifier">AnotherObject</span></a> <span class="Other">=</span> <span class="Keyword">object</span>
+  <span class="Keyword">case</span> <span class="Identifier">x</span><span class="Operator">*</span><span class="Other">:</span> <span class="Identifier">bool</span>
+  <span class="Keyword">of</span> <span class="Identifier">true</span><span class="Other">:</span>
+      <span class="Identifier">y</span><span class="Operator">*</span><span class="Other">:</span> <span class="Keyword">proc</span> <span class="Other">(</span><span class="Identifier">x</span><span class="Other">:</span> <span class="Identifier">string</span><span class="Other">)</span>
+
+  <span class="Keyword">of</span> <span class="Identifier">false</span><span class="Other">:</span>
+    
+  </pre></dt>
+  <dd>
+    
+    
+    
+  </dd>
+</div>
 <div id="B">
   <dt><pre><a href="testproject.html#B"><span class="Identifier">B</span></a> {.<span class="Identifier">inject</span>.} <span class="Other">=</span> <span class="Keyword">enum</span>
   <span class="Identifier">bB</span></pre></dt>
@@ -424,7 +445,7 @@
 <div id="T19396">
   <dt><pre><a href="testproject.html#T19396"><span class="Identifier">T19396</span></a> <span class="Other">=</span> <span class="Keyword">object</span>
   <span class="Identifier">a</span><span class="Operator">*</span><span class="Other">:</span> <span class="Identifier">int</span>
-</pre></dt>
+  </pre></dt>
   <dd>
     
     
diff --git a/nimdoc/testproject/expected/testproject.idx b/nimdoc/testproject/expected/testproject.idx
index c29223a83..ac9bbb2ce 100644
--- a/nimdoc/testproject/expected/testproject.idx
+++ b/nimdoc/testproject/expected/testproject.idx
@@ -66,5 +66,6 @@ nim	anything	testproject.html#anything	proc anything()		387
 nim	T19396	testproject.html#T19396	object T19396		392
 nim	somePragma	testproject.html#somePragma.t	template somePragma()		396
 nim	MyObject	testproject.html#MyObject	object MyObject		400
+nim	AnotherObject	testproject.html#AnotherObject	object AnotherObject		405
 nimgrp	bar	testproject.html#bar-procs-all	proc		31
 nimgrp	baz	testproject.html#baz-procs-all	proc		34
diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html
index 24e3cff1c..70916f7e0 100644
--- a/nimdoc/testproject/expected/theindex.html
+++ b/nimdoc/testproject/expected/theindex.html
@@ -52,6 +52,10 @@
 <li><a class="reference external"
           data-doc-search-tag="utils: template aEnum(): untyped" href="subdir/subdir_b/utils.html#aEnum.t">utils: template aEnum(): untyped</a></li>
           </ul></dd>
+<dt><a name="AnotherObject" href="#AnotherObject"><span>AnotherObject:</span></a></dt><dd><ul class="simple">
+<li><a class="reference external"
+          data-doc-search-tag="testproject: object AnotherObject" href="testproject.html#AnotherObject">testproject: object AnotherObject</a></li>
+          </ul></dd>
 <dt><a name="anything" href="#anything"><span>anything:</span></a></dt><dd><ul class="simple">
 <li><a class="reference external"
           data-doc-search-tag="testproject: proc anything()" href="testproject.html#anything">testproject: proc anything()</a></li>
diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim
index d08a12544..d2d3fef3f 100644
--- a/nimdoc/testproject/testproject.nim
+++ b/nimdoc/testproject/testproject.nim
@@ -400,3 +400,11 @@ type # bug #21483
    MyObject* = object
       someString*: string ## This is a string
       annotated* {.somePragma.}: string ## This is an annotated string
+
+type
+  AnotherObject* = object
+    case x*: bool
+    of true:
+      y*: proc (x: string)
+    of false:
+      hidden: string