I am trying to read the assocated Doc comments on a struct type using Go’s parser and ast packages. In this example, the code simply uses itself as the source.
package main
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
)
// FirstType docs
type FirstType struct {
// FirstMember docs
FirstMember string
}
// SecondType docs
type SecondType struct {
// SecondMember docs
SecondMember string
}
// Main docs
func main() {
fset := token.NewFileSet() // positions are relative to fset
d, err := parser.ParseDir(fset, "./", nil, parser.ParseComments)
if err != nil {
fmt.Println(err)
return
}
for _, f := range d {
ast.Inspect(f, func(n ast.Node) bool {
switch x := n.(type) {
case *ast.FuncDecl:
fmt.Printf("%s:\tFuncDecl %s\t%s\n", fset.Position(n.Pos()), x.Name, x.Doc)
case *ast.TypeSpec:
fmt.Printf("%s:\tTypeSpec %s\t%s\n", fset.Position(n.Pos()), x.Name, x.Doc)
case *ast.Field:
fmt.Printf("%s:\tField %s\t%s\n", fset.Position(n.Pos()), x.Names, x.Doc)
}
return true
})
}
}
The comment docs for the func and fields are output no problem, but for some reason the ‘FirstType docs’ and ‘SecondType docs’ are nowhere to be found. What am I missing? Go version is 1.1.2.
(To run the above, save it into a main.go file, and go run main.go
)
You need to use the
go/doc
package to extract documentation from the ast:Great question!
Looking at the source code of
go/doc
, we can see that it has to deal with this same case inreadType
function. There, it says:Notice in particular how it needs to deal with the case where the AST does not have a doc attached to the TypeSpec. To do this, it falls back on the
GenDecl
. This gives us a clue as to how we might use the AST directly to parse doc comments for structs. Adapting the for loop in the question code to add a case for*ast.GenDecl
:Running this gives us:
And, hey!
We've printed out the long-lost
FirstType docs
andSecondType docs
! But this is unsatisfactory. Why is the doc not attached to theTypeSpec
? Thego/doc/reader.go
file goes to extraordinary lengths to circumvent this issue, actually generating a fakeGenDecl
and passing it to thereadType
function mentioned earlier, if there is no documentation associated with the struct declaration!But why all this?
Imagine we changed the type definitions from code in the question slightly (defining structs like this is not common, but still valid Go):
Run the code (including the case for
ast.GenDecl
) and we get:That's right
Now the struct type definitions have their docs, and the
GenDecl
has its own documentation, too. In the first case, posted in the question, the doc was attached toGenDecl
, since the AST sees the individual struct type definitions of "contractions" of the parenthesized-version of type definitions, and wants to handle all definitions the same, whether they are grouped or not. The same thing would happen with variable definitions, as in:So if you wish to parse comments with pure AST, you need to be aware that this is how it works. But the preferred method, as @mjibson suggested, is to use
go/doc
. Good luck!