@@ -4,13 +4,13 @@ import (
4
4
"bytes"
5
5
"fmt"
6
6
"go/ast"
7
- "go/build"
8
7
"go/printer"
9
8
"go/token"
10
9
"go/types"
11
10
"strings"
12
11
13
- "golang.org/x/tools/go/loader"
12
+ "golang.org/x/tools/go/ast/astutil"
13
+ "golang.org/x/tools/go/packages"
14
14
)
15
15
16
16
func findTypeSpec (decl * ast.GenDecl , pos token.Pos ) * ast.TypeSpec {
@@ -35,7 +35,7 @@ func findVarSpec(decl *ast.GenDecl, pos token.Pos) *ast.ValueSpec {
35
35
return nil
36
36
}
37
37
38
- func formatNode (n ast.Node , obj types.Object , prog * loader. Program ) string {
38
+ func formatNode (n ast.Node , obj types.Object , prog * packages. Package ) string {
39
39
//fmt.Printf("formatting %T node\n", n)
40
40
var nc ast.Node
41
41
// Render a copy of the node with no documentation.
@@ -113,7 +113,7 @@ func formatNode(n ast.Node, obj types.Object, prog *loader.Program) string {
113
113
}
114
114
115
115
// IdentDoc attempts to get the documentation for a *ast.Ident.
116
- func IdentDoc (ctx * build. Context , id * ast.Ident , info * loader. PackageInfo , prog * loader. Program ) (* Doc , error ) {
116
+ func IdentDoc (id * ast.Ident , info * types. Info , prog * packages. Package ) (* Doc , error ) {
117
117
// get definition of identifier
118
118
obj := info .ObjectOf (id )
119
119
@@ -128,17 +128,17 @@ func IdentDoc(ctx *build.Context, id *ast.Ident, info *loader.PackageInfo, prog
128
128
}
129
129
130
130
pkgPath , pkgName := "" , ""
131
- if obj .Pkg () != nil {
132
- pkgPath = obj . Pkg () .Path ()
133
- pkgName = obj . Pkg () .Name ()
131
+ if op := obj .Pkg (); op != nil {
132
+ pkgPath = op .Path ()
133
+ pkgName = op .Name ()
134
134
}
135
135
136
136
// handle packages imported under a different name
137
137
if p , ok := obj .(* types.PkgName ); ok {
138
- return PackageDoc (ctx , prog . Fset , "" , p .Imported ().Path ()) // SRCDIR TODO TODO
138
+ return PackageDoc (prog , p .Imported ().Path ())
139
139
}
140
140
141
- _ , nodes , _ := prog . PathEnclosingInterval ( obj .Pos (), obj .Pos ())
141
+ _ , nodes := pathEnclosingInterval ( prog , obj .Pos (), obj .Pos ())
142
142
if len (nodes ) == 0 {
143
143
// special case - builtins
144
144
doc , decl := findInBuiltin (obj .Name (), obj , prog )
@@ -231,6 +231,42 @@ func IdentDoc(ctx *build.Context, id *ast.Ident, info *loader.PackageInfo, prog
231
231
return doc , nil
232
232
}
233
233
234
+ // pathEnclosingInterval returns the types.Info of the package and ast.Node that
235
+ // contain source interval [start, end), and all the node's ancestors
236
+ // up to the AST root. It searches the ast.Files of initPkg and the packages it imports.
237
+ //
238
+ // Modified from golang.org/x/tools/go/loader.
239
+ func pathEnclosingInterval (initPkg * packages.Package , start , end token.Pos ) (* types.Info , []ast.Node ) {
240
+ pkgs := []* packages.Package {initPkg }
241
+ for _ , pkg := range initPkg .Imports {
242
+ pkgs = append (pkgs , pkg )
243
+ }
244
+
245
+ for _ , pkg := range pkgs {
246
+ for _ , f := range pkg .Syntax {
247
+ if f .Pos () == token .NoPos {
248
+ // This can happen if the parser saw
249
+ // too many errors and bailed out.
250
+ // (Use parser.AllErrors to prevent that.)
251
+ continue
252
+ }
253
+ if ! tokenFileContainsPos (pkg .Fset .File (f .Pos ()), start ) {
254
+ continue
255
+ }
256
+ if path , _ := astutil .PathEnclosingInterval (f , start , end ); path != nil {
257
+ return pkg .TypesInfo , path
258
+ }
259
+ }
260
+ }
261
+ return nil , nil
262
+ }
263
+
264
+ func tokenFileContainsPos (f * token.File , pos token.Pos ) bool {
265
+ p := int (pos )
266
+ base := f .Base ()
267
+ return base <= p && p < base + f .Size ()
268
+ }
269
+
234
270
func stripVendorFromImportPath (ip string ) string {
235
271
vendor := "/vendor/"
236
272
l := len (vendor )
0 commit comments