diff --git a/src/cmd/godoc/godoc.go b/src/cmd/godoc/godoc.go index b72aad56c08..57ef9f37782 100644 --- a/src/cmd/godoc/godoc.go +++ b/src/cmd/godoc/godoc.go @@ -356,6 +356,7 @@ func example_htmlFunc(funcName string, examples []*doc.Example, fset *token.File // (use tabs, no comment highlight, etc). play := "" if eg.Play != nil && *showPlayground { + ast.SortImports(fset, eg.Play) var buf bytes.Buffer err := (&printer.Config{Mode: printer.TabIndent, Tabwidth: 8}).Fprint(&buf, fset, eg.Play) if err != nil { diff --git a/src/pkg/go/doc/example.go b/src/pkg/go/doc/example.go index 5c51ecef34f..e5752bb15a1 100644 --- a/src/pkg/go/doc/example.go +++ b/src/pkg/go/doc/example.go @@ -145,8 +145,9 @@ func playExample(file *ast.File, body *ast.BlockStmt) *ast.File { // Use unresolved identifiers to determine the imports used by this // example. The heuristic assumes package names match base import - // paths. (Should be good enough most of the time.) - imports := make(map[string]string) // [name]path + // paths for imports w/o renames (should be good enough most of the time). + namedImports := make(map[string]string) // [name]path + var blankImports []ast.Spec // _ imports for _, s := range file.Imports { p, err := strconv.Unquote(s.Path.Value) if err != nil { @@ -154,14 +155,18 @@ func playExample(file *ast.File, body *ast.BlockStmt) *ast.File { } n := path.Base(p) if s.Name != nil { - if s.Name.Name == "." { + n = s.Name.Name + switch n { + case "_": + blankImports = append(blankImports, s) + continue + case ".": // We can't resolve dot imports (yet). return nil } - n = s.Name.Name } if unresolved[n] { - imports[n] = p + namedImports[n] = p delete(unresolved, n) } } @@ -172,13 +177,19 @@ func playExample(file *ast.File, body *ast.BlockStmt) *ast.File { return nil } - // Filter out comments that are outside the function body. + // Include documentation belonging to blank imports. var comments []*ast.CommentGroup - for _, c := range file.Comments { - if c.Pos() < body.Pos() || c.Pos() >= body.End() { - continue + for _, s := range blankImports { + if c := s.(*ast.ImportSpec).Doc; c != nil { + comments = append(comments, c) + } + } + + // Include comments that are inside the function body. + for _, c := range file.Comments { + if body.Pos() <= c.Pos() && c.End() <= body.End() { + comments = append(comments, c) } - comments = append(comments, c) } // Strip "Output:" commment and adjust body end position. @@ -190,13 +201,14 @@ func playExample(file *ast.File, body *ast.BlockStmt) *ast.File { Lparen: 1, // Need non-zero Lparen and Rparen so that printer Rparen: 1, // treats this as a factored import. } - for n, p := range imports { + for n, p := range namedImports { s := &ast.ImportSpec{Path: &ast.BasicLit{Value: strconv.Quote(p)}} if path.Base(p) != n { s.Name = ast.NewIdent(n) } importDecl.Specs = append(importDecl.Specs, s) } + importDecl.Specs = append(importDecl.Specs, blankImports...) // Synthesize main function. funcDecl := &ast.FuncDecl{ @@ -213,7 +225,7 @@ func playExample(file *ast.File, body *ast.BlockStmt) *ast.File { } } -// playExample takes a whole file example and synthesizes a new *ast.File +// playExampleFile takes a whole file example and synthesizes a new *ast.File // such that the example is function main in package main. func playExampleFile(file *ast.File) *ast.File { // Strip copyright comment if present.