diff --git a/internal/godocfx/parse.go b/internal/godocfx/parse.go index 6f269116abc..39ae0431a1f 100644 --- a/internal/godocfx/parse.go +++ b/internal/godocfx/parse.go @@ -155,6 +155,7 @@ func parse(glob string, workingDir string, optionalExtraFiles []string) (*result // independently. for _, pi := range pkgInfos { link := newLinker(pi.pkg.Imports, pi.importRenames) + topLevelDecls := pkgsite.TopLevelDecls(pi.doc) pkgItem := &item{ UID: pi.doc.ImportPath, Name: pi.doc.ImportPath, @@ -181,7 +182,7 @@ func parse(glob string, workingDir string, optionalExtraFiles []string) (*result Type: "const", Summary: c.Doc, Langs: onlyGo, - Syntax: syntax{Content: pkgsite.PrintType(pi.fset, c.Decl, toURL)}, + Syntax: syntax{Content: pkgsite.PrintType(pi.fset, c.Decl, toURL, topLevelDecls)}, }) } for _, v := range pi.doc.Vars { @@ -197,7 +198,7 @@ func parse(glob string, workingDir string, optionalExtraFiles []string) (*result Type: "variable", Summary: v.Doc, Langs: onlyGo, - Syntax: syntax{Content: pkgsite.PrintType(pi.fset, v.Decl, toURL)}, + Syntax: syntax{Content: pkgsite.PrintType(pi.fset, v.Decl, toURL, topLevelDecls)}, }) } for _, t := range pi.doc.Types { @@ -211,7 +212,7 @@ func parse(glob string, workingDir string, optionalExtraFiles []string) (*result Type: "type", Summary: t.Doc, Langs: onlyGo, - Syntax: syntax{Content: pkgsite.PrintType(pi.fset, t.Decl, toURL)}, + Syntax: syntax{Content: pkgsite.PrintType(pi.fset, t.Decl, toURL, topLevelDecls)}, Examples: processExamples(t.Examples, pi.fset), } // Note: items are added as page.Children, rather than @@ -230,7 +231,7 @@ func parse(glob string, workingDir string, optionalExtraFiles []string) (*result Type: "const", Summary: c.Doc, Langs: onlyGo, - Syntax: syntax{Content: pkgsite.PrintType(pi.fset, c.Decl, toURL)}, + Syntax: syntax{Content: pkgsite.PrintType(pi.fset, c.Decl, toURL, topLevelDecls)}, }) } for _, v := range t.Vars { @@ -246,7 +247,7 @@ func parse(glob string, workingDir string, optionalExtraFiles []string) (*result Type: "variable", Summary: v.Doc, Langs: onlyGo, - Syntax: syntax{Content: pkgsite.PrintType(pi.fset, v.Decl, toURL)}, + Syntax: syntax{Content: pkgsite.PrintType(pi.fset, v.Decl, toURL, topLevelDecls)}, }) } @@ -336,7 +337,6 @@ func (l *linker) linkify(s string) string { prefix += "*" } - // If s does not have a dot, it's in this package. if !strings.Contains(s, ".") { // If s is not exported, it's probably a builtin. if !token.IsExported(s) { diff --git a/third_party/pkgsite/print_type.go b/third_party/pkgsite/print_type.go index 1bb39b2129b..25c5e0bac09 100644 --- a/third_party/pkgsite/print_type.go +++ b/third_party/pkgsite/print_type.go @@ -36,8 +36,8 @@ import ( // 4. Use scanner.Scanner to find every identifier (in the same order as step // 2). If there is a link for the identifier, insert it. Otherwise, print // the plain doc. -func PrintType(fset *token.FileSet, decl ast.Decl, toURL func(string, string) string) string { - anchorLinksMap := generateAnchorLinks(decl, toURL) +func PrintType(fset *token.FileSet, decl ast.Decl, toURL func(string, string) string, topLevelDecls map[interface{}]bool) string { + anchorLinksMap := generateAnchorLinks(decl, toURL, topLevelDecls) // Convert the map (keyed by *ast.Ident) to a slice of URLs (or no URL). // // This relies on the ast.Inspect and scanner.Scanner both @@ -149,7 +149,7 @@ func stringBasicLitSize(s string) string { // generateAnchorLinks returns a mapping of *ast.Ident objects to the URL // that the identifier should link to. -func generateAnchorLinks(decl ast.Decl, toURL func(string, string) string) map[*ast.Ident]string { +func generateAnchorLinks(decl ast.Decl, toURL func(string, string) string, topLevelDecls map[interface{}]bool) map[*ast.Ident]string { m := map[*ast.Ident]string{} ignore := map[ast.Node]bool{} ast.Inspect(decl, func(node ast.Node) bool { @@ -175,8 +175,7 @@ func generateAnchorLinks(decl ast.Decl, toURL func(string, string) string) map[* case *ast.Ident: if node.Obj == nil && doc.IsPredeclared(node.Name) { m[node] = toURL("builtin", node.Name) - } else if node.Obj != nil && node.Obj.Kind != ast.Var { - // TODO: && topLevelDecls[node.Obj.Decl] + } else if node.Obj != nil && topLevelDecls[node.Obj.Decl] { m[node] = toURL("", node.Name) } case *ast.FuncDecl: @@ -196,3 +195,45 @@ func generateAnchorLinks(decl ast.Decl, toURL func(string, string) string) map[* }) return m } + +// TopLevelDecls returns the top level declarations in the package. +func TopLevelDecls(pkg *doc.Package) map[interface{}]bool { + topLevelDecls := map[interface{}]bool{} + forEachPackageDecl(pkg, func(decl ast.Decl) { + topLevelDecls[decl] = true + if gd, _ := decl.(*ast.GenDecl); gd != nil { + for _, sp := range gd.Specs { + topLevelDecls[sp] = true + } + } + }) + return topLevelDecls +} + +// forEachPackageDecl iterates though every top-level declaration in a package. +func forEachPackageDecl(pkg *doc.Package, fnc func(decl ast.Decl)) { + for _, c := range pkg.Consts { + fnc(c.Decl) + } + for _, v := range pkg.Vars { + fnc(v.Decl) + } + for _, f := range pkg.Funcs { + fnc(f.Decl) + } + for _, t := range pkg.Types { + fnc(t.Decl) + for _, c := range t.Consts { + fnc(c.Decl) + } + for _, v := range t.Vars { + fnc(v.Decl) + } + for _, f := range t.Funcs { + fnc(f.Decl) + } + for _, m := range t.Methods { + fnc(m.Decl) + } + } +}