Code Examples
package main
import (
"fmt"
"go/ast"
"go/doc"
"go/parser"
"go/token"
)
func main() {
// src and test are two source files that make up
// a package whose documentation will be computed.
const src = `
// This is the package comment.
package p
import "fmt"
// This comment is associated with the Greet function.
func Greet(who string) {
fmt.Printf("Hello, %s!\n", who)
}
`
const test = `
package p_test
// This comment is associated with the ExampleGreet_world example.
func ExampleGreet_world() {
Greet("world")
}
`
// Create the AST by parsing src and test.
fset := token.NewFileSet()
files := []*ast.File{
mustParse(fset, "src.go", src),
mustParse(fset, "src_test.go", test),
}
// Compute package documentation with examples.
p, err := doc.NewFromFiles(fset, files, "example.com/p")
if err != nil {
panic(err)
}
fmt.Printf("package %s - %s", p.Name, p.Doc)
fmt.Printf("func %s - %s", p.Funcs[0].Name, p.Funcs[0].Doc)
fmt.Printf(" ⤷ example with suffix %q - %s", p.Funcs[0].Examples[0].Suffix, p.Funcs[0].Examples[0].Doc)
}
func mustParse(fset *token.FileSet, filename, src string) *ast.File {
f, err := parser.ParseFile(fset, filename, src, parser.ParseComments)
if err != nil {
panic(err)
}
return f
}
Package-Level Type Names (total 12, in which 8 are exported)
/* sort exporteds by: | */
An Example represents an example function found in a test source file.Codeast.NodeComments[]*ast.CommentGroup // example function doc string // expect empty output // name of the item being exemplified (including optional suffix) // original source code order // expected output // a whole program version of the example // example suffix, without leading '_' (only populated by NewFromFiles)Unorderedbool
func Examples(testFiles ...*ast.File) []*Example
func classifyExamples(p *Package, examples []*Example)
Func is the documentation for a func declaration.Decl*ast.FuncDeclDocstring Examples is a sorted list of examples associated with this
function or method. Examples are extracted from _test.go files
provided to NewFromFiles. // embedding level; 0 means not embeddedNamestring // original receiver "T" or "*T" methods
(for functions, these fields have the respective zero value) // actual receiver "T" or "*T" possibly followed by type parameters [P1, ..., Pn]
func customizeRecv(f *Func, recvTypeName string, embeddedIsPtr bool, level int) *Func
func filterFuncs(a []*Func, f Filter) []*Func
func sortedFuncs(m methodSet, allMethods bool) []*Func
func customizeRecv(f *Func, recvTypeName string, embeddedIsPtr bool, level int) *Func
func filterFuncs(a []*Func, f Filter) []*Func
func (*Package).collectFuncs(funcs []*Func)
A Note represents a marked comment starting with "MARKER(uid): note body".
Any note with a marker of 2 or more upper case [A-Z] letters and a uid of
at least one character is recognized. The ":" following the uid is optional.
Notes are collected in the Package.Notes map indexed by the notes marker. // note body text // position range of the comment containing the marker // position range of the comment containing the marker // uid found with the marker
func noteBodies(notes []*Note) []string
Package is the documentation for an entire package. Deprecated: For backward compatibility Bugs is still populated,
but all new code should use Notes instead. declarationsDocstring Examples is a sorted list of examples associated with
the package. Examples are extracted from _test.go files
provided to NewFromFiles.Filenames[]stringFuncs[]*FuncImportPathstringImports[]stringNamestringNotesmap[string][]*NoteTypes[]*TypeVars[]*ValueimportByNamemap[string]stringsymsmap[string]bool Filter eliminates documentation for names that don't pass through the filter f.
TODO(gri): Recognize "Type.Method" as a name. HTML returns formatted HTML for the doc comment text.
To customize details of the HTML, use [Package.Printer]
to obtain a [comment.Printer], and configure it
before calling its HTML method. Markdown returns formatted Markdown for the doc comment text.
To customize details of the Markdown, use [Package.Printer]
to obtain a [comment.Printer], and configure it
before calling its Markdown method. Parser returns a doc comment parser configured
for parsing doc comments from package p.
Each call returns a new parser, so that the caller may
customize it before use. Printer returns a doc comment printer configured
for printing doc comments from package p.
Each call returns a new printer, so that the caller may
customize it before use. Synopsis returns a cleaned version of the first sentence in text.
That sentence ends after the first period followed by space and not
preceded by exactly one uppercase letter, or at the first paragraph break.
The result string has no \n, \r, or \t characters and uses only single
spaces between words. If text starts with any of the [IllegalPrefixes],
the result is the empty string. Text returns formatted text for the doc comment text,
wrapped to 80 Unicode code points and using tabs for
code block indentation.
To customize details of the formatting, use [Package.Printer]
to obtain a [comment.Printer], and configure it
before calling its Text method.(*Package) collectFuncs(funcs []*Func)(*Package) collectTypes(types []*Type)(*Package) collectValues(values []*Value) lookupPackage returns the import path identified by name
in the given package. If name uniquely identifies a single import,
then lookupPackage returns that import.
If multiple packages are imported as name, importPath returns "", false.
Otherwise, if name is the name of p itself, importPath returns "", true,
to signal a reference to p.
Otherwise, importPath returns "", false. lookupSym reports whether the package has a given symbol or method.
If recv == "", HasSym reports whether the package has a top-level
const, func, type, or var named name.
If recv != "", HasSym reports whether the package has a type
named recv with a method named name.
func New(pkg *ast.Package, importPath string, mode Mode) *Package
func NewFromFiles(fset *token.FileSet, files []*ast.File, importPath string, opts ...any) (*Package, error)
func classifyExamples(p *Package, examples []*Example)
Type is the documentation for a type declaration. associated declarations // sorted list of constants of (mostly) this typeDecl*ast.GenDeclDocstring Examples is a sorted list of examples associated with
this type. Examples are extracted from _test.go files
provided to NewFromFiles. // sorted list of functions returning this type // sorted list of methods (including embedded ones) of this typeNamestring // sorted list of variables of (mostly) this type
func filterTypes(a []*Type, f Filter) []*Type
func sortedTypes(m map[string]*namedType, allMethods bool) []*Type
func filterTypes(a []*Type, f Filter) []*Type
func (*Package).collectTypes(types []*Type)
A methodSet describes a set of methods. Entries where Decl == nil are conflict
entries (more than one method with the same name at the same embedding level). add adds method m to the method set; m is ignored if the method set
already contains a method with the same name at the same or a higher
level than m. set creates the corresponding Func for f and adds it to mset.
If there are multiple f's with the same name, set keeps the first
one with documentation; conflicts are ignored. The boolean
specifies whether to leave the AST untouched.
func sortedFuncs(m methodSet, allMethods bool) []*Func
A namedType represents a named unqualified (package local, or possibly
predeclared) type. The namedType for a type name is always found via
reader.lookupType. // nil if declaration hasn't been seen yet // doc comment for type // true if the embedded type is a pointerfuncsmethodSet // true if this type is embedded // true if this type is a structmethodsmethodSet // type name associated declarations // consts and vars
func sortedTypes(m map[string]*namedType, allMethods bool) []*Type
reader accumulates documentation for a single package.
It modifies the AST: Comments (declaration documentation)
that have been collected by the reader are set to nil
in the respective AST nodes so that they are not printed
twice (once when printing the documentation and once when
printing the corresponding AST node). package properties // package documentation, if anyfilenames[]stringfixmapmap[string][]*ast.InterfaceTypefuncsmethodSet // if set, package contains a dot importimportByNamemap[string]string importsmodeModenotesmap[string][]*Note // sort order of const and var declarations (when we can't use a name) support for package-local shadowing of predeclared typestypesmap[string]*namedType declarations // consts and vars cleanupTypes removes the association of functions and methods with
types that have no declaration. Instead, these functions and methods
are shown at the package level. It also removes types with missing
declarations or which are not visible. collectEmbeddedMethods collects the embedded methods of typ in mset. computeMethodSets determines the actual method sets for each type encountered. fileExports removes unexported declarations from src in place.(*reader) filterDecl(decl ast.Decl) bool filterFieldList removes unexported fields (field names) from the field list
in place and reports whether fields were removed. Anonymous fields are
recorded with the parent type. filterType is called with the types of
all remaining fields. filterParamList applies filterType to each parameter type in fields.(*reader) filterSpec(spec ast.Spec) bool(*reader) filterSpecList(list []ast.Spec, tok token.Token) []ast.Spec filterType strips any unexported struct fields or method types from typ
in place. If fields (or methods) have been removed, the corresponding
struct or interface type has the Incomplete field set to true. isPredeclared reports whether n denotes a predeclared type.(*reader) isVisible(name string) bool lookupType returns the base type with the given name.
If the base type has not been encountered yet, a new
type with the given name but no associated declaration
is added to the type map.(*reader) readDoc(comment *ast.CommentGroup) readFile adds the AST for a source file to the reader. readFunc processes a func or method declaration. readNote collects a single note from a sequence of comments. readNotes extracts notes from comments.
A note must start at the beginning of a comment with "MARKER(uid):"
and is followed by the note body (e.g., "// BUG(gri): fix this").
The note ends at the end of the comment group or at the start of
another note in the same comment group, whichever comes first.(*reader) readPackage(pkg *ast.Package, mode Mode) readType processes a type declaration. readValue processes a const or var declaration. recordAnonymousField registers fieldType as the type of an
anonymous field in the parent type. If the field is imported
(qualified name) or the parent is nil, the field is ignored.
The function returns the field name.(*reader) remember(predecl string, typ *ast.InterfaceType)
Package-Level Functions (total 51, in which 7 are exported)
Examples returns the examples found in testFiles, sorted by Name field.
The Order fields record the order in which the examples were encountered.
The Suffix field is not populated when Examples is called directly, it is
only populated by [NewFromFiles] for examples it finds in _test.go files.
Playable Examples must be in a package whose name ends in "_test".
An Example is "playable" (the Play field is non-nil) in either of these
circumstances:
- The example function is self-contained: the function references only
identifiers from other packages (or predeclared identifiers, such as
"int") and the test file does not include a dot import.
- The entire test file is the example: the file contains exactly one
example function, zero test, fuzz test, or benchmark function, and at
least one top-level function, type, variable, or constant declaration
other than the example function.
IsPredeclared reports whether s is a predeclared identifier.
New computes the package documentation for the given package AST.
New takes ownership of the AST pkg and may edit or overwrite it.
To have the [Examples] fields populated, use [NewFromFiles] and include
the package's _test.go files.
NewFromFiles computes documentation for a package.
The package is specified by a list of *ast.Files and corresponding
file set, which must not be nil.
NewFromFiles uses all provided files when computing documentation,
so it is the caller's responsibility to provide only the files that
match the desired build context. "go/build".Context.MatchFile can
be used for determining whether a file matches a build context with
the desired GOOS and GOARCH values, and other build constraints.
The import path of the package is specified by importPath.
Examples found in _test.go files are associated with the corresponding
type, function, method, or the package, based on their name.
If the example has a suffix in its name, it is set in the
[Example.Suffix] field. [Examples] with malformed names are skipped.
Optionally, a single extra argument of type [Mode] can be provided to
control low-level aspects of the documentation extraction behavior.
NewFromFiles takes ownership of the AST files and may edit them,
unless the PreserveAST Mode bit is on.
Synopsis returns a cleaned version of the first sentence in text.
Deprecated: New programs should use [Package.Synopsis] instead,
which handles links in text properly.
ToHTML converts comment text to formatted HTML.
Deprecated: ToHTML cannot identify documentation links
in the doc comment, because they depend on knowing what
package the text came from, which is not included in this API.
Given the *[doc.Package] p where text was found,
ToHTML(w, text, nil) can be replaced by:
w.Write(p.HTML(text))
which is in turn shorthand for:
w.Write(p.Printer().HTML(p.Parser().Parse(text)))
If words may be non-nil, the longer replacement is:
parser := p.Parser()
parser.Words = words
w.Write(p.Printer().HTML(parser.Parse(d)))
ToText converts comment text to formatted text.
Deprecated: ToText cannot identify documentation links
in the doc comment, because they depend on knowing what
package the text came from, which is not included in this API.
Given the *[doc.Package] p where text was found,
ToText(w, text, "", "\t", 80) can be replaced by:
w.Write(p.Text(text))
In the general case, ToText(w, text, prefix, codePrefix, width)
can be replaced by:
d := p.Parser().Parse(text)
pr := p.Printer()
pr.TextPrefix = prefix
pr.TextCodePrefix = codePrefix
pr.TextWidth = width
w.Write(pr.Text(d))
See the documentation for [Package.Text] and [comment.Printer.Text]
for more details.
assumedPackageName returns the assumed package name
for a given import path. This is a copy of
golang.org/x/tools/internal/imports.ImportPathToAssumedName.
baseTypeName returns the name of the base type of x (or "")
and whether the type is imported or not.
classifyExamples classifies examples and assigns them to the Examples field
of the relevant Func, Type, or Package that the example is associated with.
The classification process is ambiguous in some cases:
- ExampleFoo_Bar matches a type named Foo_Bar
or a method named Foo.Bar.
- ExampleFoo_bar matches a type named Foo_bar
or Foo (with a "bar" suffix).
Examples with malformed names are not associated with anything.
clean replaces each sequence of space, \r, or \t characters
with a single space and removes any trailing and leading spaces.
copyConstType returns a copy of typ with position pos.
typ must be a valid constant type.
In practice, only (possibly qualified) identifiers are possible.
findDeclsAndUnresolved returns all the top-level declarations mentioned in
the body, and a set of unresolved symbols (those that appear in the body but
have no declaration in the program).
topDecls maps objects to the top-level declaration declaring them (not
necessarily obj.Decl, as obj.Decl will be a Spec for GenDecls, but
topDecls[obj] will be the GenDecl itself).
findImportGroupStarts finds the start positions of each sequence of import
specs that are not separated by a blank line.
Helper for findImportGroupStarts to ease testing.
firstSentence returns the first sentence in s.
The sentence ends after the first period followed by space and
not preceded by exactly one uppercase letter.
hasExportedName reports whether list contains any exported names.
isTest tells whether name looks like a test, example, fuzz test, or
benchmark. It is a Test (say) if there is a character after Test that is not
a lower-case letter. (We don't want Testiness.)
lastComment returns the last comment inside the provided block.
lookupTypeParam searches for type parameters named name within the tparams
field list, returning the relevant identifier if found, or nil if not.
nameWithoutInst returns name if name has no brackets. If name contains
brackets, then it returns name with all the contents between (and including)
the outermost left and right bracket removed.
Adapted from debug/gosym/symtab.go:Sym.nameWithoutInst.
noteBodies returns a list of note body strings given a list of notes.
This is only used to populate the deprecated Package.Bugs field.
playExample synthesizes a new *ast.File based on the provided
file with the provided function body as the body of main.
playExampleFile takes a whole file example and synthesizes a new *ast.File
such that the example is function main in package main.
simpleImporter returns a (dummy) package object named by the last path
component of the provided package path (as is the convention for packages).
This is sufficient to resolve package identifiers without doing an actual
import. It never returns an error.
splitExampleName attempts to split example name s at index i,
and reports if that produces a valid split. The suffix may be
absent. Otherwise, it must start with a lower-case letter and
be preceded by '_'.
One of i == len(s) or s[i] == '_' must be true.
stripOutputComment finds and removes the "Output:" or "Unordered output:"
comment from body and comments, and adjusts the body block's end position.
updateIdentList replaces all unexported identifiers with underscore
and reports whether at least one exported name exists.
Package-Level Variables (total 9, in which 1 is exported)
IllegalPrefixes is a list of lower-case prefixes that identify
a comment as not being a doc comment.
This helps to avoid misinterpreting the common mistake
of a copyright notice immediately before a package statement
as being a doc comment.
Package-Level Constants (total 3, all are exported)
AllDecls says to extract documentation for all package-level
declarations, not just exported ones.
AllMethods says to show all embedded methods, not just the ones of
invisible (unexported) anonymous fields.
PreserveAST says to leave the AST unmodified. Originally, pieces of
the AST such as function bodies were nil-ed out to save memory in
godoc, but not all programs want that behavior.
The pages are generated with Goldsv0.7.6. (GOOS=linux GOARCH=amd64)