diff options
Diffstat (limited to 'src/pkg/go/doc')
-rw-r--r-- | src/pkg/go/doc/comment.go | 5 | ||||
-rw-r--r-- | src/pkg/go/doc/doc.go | 12 | ||||
-rw-r--r-- | src/pkg/go/doc/doc_test.go | 2 | ||||
-rw-r--r-- | src/pkg/go/doc/example.go | 270 | ||||
-rw-r--r-- | src/pkg/go/doc/example_test.go | 111 | ||||
-rw-r--r-- | src/pkg/go/doc/exports.go | 2 | ||||
-rw-r--r-- | src/pkg/go/doc/reader.go | 113 | ||||
-rw-r--r-- | src/pkg/go/doc/synopsis.go | 41 | ||||
-rw-r--r-- | src/pkg/go/doc/synopsis_test.go | 5 | ||||
-rw-r--r-- | src/pkg/go/doc/testdata/a.0.golden | 11 | ||||
-rw-r--r-- | src/pkg/go/doc/testdata/a.1.golden | 11 | ||||
-rw-r--r-- | src/pkg/go/doc/testdata/a.2.golden | 11 | ||||
-rw-r--r-- | src/pkg/go/doc/testdata/a0.go | 9 | ||||
-rw-r--r-- | src/pkg/go/doc/testdata/a1.go | 4 | ||||
-rw-r--r-- | src/pkg/go/doc/testdata/benchmark.go | 4 | ||||
-rw-r--r-- | src/pkg/go/doc/testdata/e.go | 2 | ||||
-rw-r--r-- | src/pkg/go/doc/testdata/error2.1.golden | 2 | ||||
-rw-r--r-- | src/pkg/go/doc/testdata/error2.go | 2 | ||||
-rw-r--r-- | src/pkg/go/doc/testdata/template.txt | 7 | ||||
-rw-r--r-- | src/pkg/go/doc/testdata/testing.1.golden | 2 | ||||
-rw-r--r-- | src/pkg/go/doc/testdata/testing.go | 4 |
21 files changed, 543 insertions, 87 deletions
diff --git a/src/pkg/go/doc/comment.go b/src/pkg/go/doc/comment.go index 6f0edd4ba..c4b7e6ae6 100644 --- a/src/pkg/go/doc/comment.go +++ b/src/pkg/go/doc/comment.go @@ -174,7 +174,7 @@ func unindent(block []string) { } // heading returns the trimmed line if it passes as a section heading; -// otherwise it returns the empty string. +// otherwise it returns the empty string. func heading(line string) string { line = strings.TrimSpace(line) if len(line) == 0 { @@ -229,7 +229,8 @@ type block struct { var nonAlphaNumRx = regexp.MustCompile(`[^a-zA-Z0-9]`) func anchorID(line string) string { - return nonAlphaNumRx.ReplaceAllString(line, "_") + // Add a "hdr-" prefix to avoid conflicting with IDs used for package symbols. + return "hdr-" + nonAlphaNumRx.ReplaceAllString(line, "_") } // ToHTML converts comment text to formatted HTML. diff --git a/src/pkg/go/doc/doc.go b/src/pkg/go/doc/doc.go index 9c606315d..65b1b83eb 100644 --- a/src/pkg/go/doc/doc.go +++ b/src/pkg/go/doc/doc.go @@ -17,7 +17,16 @@ type Package struct { ImportPath string Imports []string Filenames []string - Bugs []string + // DEPRECATED. For backward compatibility Bugs is still populated, + // but all new code should use Notes instead. + Bugs []string + + // Notes such as TODO(userid): or SECURITY(userid): + // along the lines of BUG(userid). Any marker with 2 or more upper + // case [A-Z] letters is recognised. + // BUG is explicitly not included in these notes but will + // be in a subsequent change when the Bugs field above is removed. + Notes map[string][]string // declarations Consts []*Value @@ -89,6 +98,7 @@ func New(pkg *ast.Package, importPath string, mode Mode) *Package { Imports: sortedKeys(r.imports), Filenames: r.filenames, Bugs: r.bugs, + Notes: r.notes, Consts: sortedValues(r.values, token.CONST), Types: sortedTypes(r.types, mode&AllMethods != 0), Vars: sortedValues(r.values, token.VAR), diff --git a/src/pkg/go/doc/doc_test.go b/src/pkg/go/doc/doc_test.go index f957ede4a..8043038b4 100644 --- a/src/pkg/go/doc/doc_test.go +++ b/src/pkg/go/doc/doc_test.go @@ -123,7 +123,7 @@ func test(t *testing.T, mode Mode) { } // compare - if bytes.Compare(got, want) != 0 { + if !bytes.Equal(got, want) { t.Errorf("package %s\n\tgot:\n%s\n\twant:\n%s", pkg.Name, got, want) } } diff --git a/src/pkg/go/doc/example.go b/src/pkg/go/doc/example.go index a7e0e250a..693ad5b94 100644 --- a/src/pkg/go/doc/example.go +++ b/src/pkg/go/doc/example.go @@ -9,21 +9,29 @@ package doc import ( "go/ast" "go/token" + "path" "regexp" "sort" + "strconv" "strings" "unicode" "unicode/utf8" ) +// An Example represents an example function found in a source files. type Example struct { - Name string // name of the item being exemplified - Doc string // example function doc string - Code ast.Node - Comments []*ast.CommentGroup - Output string // expected output + Name string // name of the item being exemplified + Doc string // example function doc string + Code ast.Node + Play *ast.File // a whole program version of the example + Comments []*ast.CommentGroup + Output string // expected output + EmptyOutput bool // expect empty output + Order int // original source code order } +// Examples returns the examples found in the files, sorted by Name field. +// The Order fields record the order in which the examples were encountered. func Examples(files ...*ast.File) []*Example { var list []*Example for _, file := range files { @@ -52,12 +60,16 @@ func Examples(files ...*ast.File) []*Example { if f.Doc != nil { doc = f.Doc.Text() } + output, hasOutput := exampleOutput(f.Body, file.Comments) flist = append(flist, &Example{ - Name: name[len("Example"):], - Doc: doc, - Code: f.Body, - Comments: file.Comments, - Output: exampleOutput(f, file.Comments), + Name: name[len("Example"):], + Doc: doc, + Code: f.Body, + Play: playExample(file, f.Body), + Comments: file.Comments, + Output: output, + EmptyOutput: output == "" && hasOutput, + Order: len(flist), }) } if !hasTests && numDecl > 1 && len(flist) == 1 { @@ -65,6 +77,7 @@ func Examples(files ...*ast.File) []*Example { // other top-level declarations, and no tests or // benchmarks, use the whole file as the example. flist[0].Code = file + flist[0].Play = playExampleFile(file) } list = append(list, flist...) } @@ -74,26 +87,22 @@ func Examples(files ...*ast.File) []*Example { var outputPrefix = regexp.MustCompile(`(?i)^[[:space:]]*output:`) -func exampleOutput(fun *ast.FuncDecl, comments []*ast.CommentGroup) string { - // find the last comment in the function - var last *ast.CommentGroup - for _, cg := range comments { - if cg.Pos() < fun.Pos() { - continue - } - if cg.End() > fun.End() { - break - } - last = cg - } - if last != nil { +// Extracts the expected output and whether there was a valid output comment +func exampleOutput(b *ast.BlockStmt, comments []*ast.CommentGroup) (output string, ok bool) { + if _, last := lastComment(b, comments); last != nil { // test that it begins with the correct prefix text := last.Text() if loc := outputPrefix.FindStringIndex(text); loc != nil { - return strings.TrimSpace(text[loc[1]:]) + text = text[loc[1]:] + // Strip zero or more spaces followed by \n or a single space. + text = strings.TrimLeft(text, " ") + if len(text) > 0 && text[0] == '\n' { + text = text[1:] + } + return text, true } } - return "" // no suitable comment found + return "", false // no suitable comment found } // isTest tells whether name looks like a test, example, or benchmark. @@ -115,3 +124,214 @@ type exampleByName []*Example func (s exampleByName) Len() int { return len(s) } func (s exampleByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s exampleByName) Less(i, j int) bool { return s[i].Name < s[j].Name } + +// playExample synthesizes a new *ast.File based on the provided +// file with the provided function body as the body of main. +func playExample(file *ast.File, body *ast.BlockStmt) *ast.File { + if !strings.HasSuffix(file.Name.Name, "_test") { + // We don't support examples that are part of the + // greater package (yet). + return nil + } + + // Find top-level declarations in the file. + topDecls := make(map[*ast.Object]bool) + for _, decl := range file.Decls { + switch d := decl.(type) { + case *ast.FuncDecl: + topDecls[d.Name.Obj] = true + case *ast.GenDecl: + for _, spec := range d.Specs { + switch s := spec.(type) { + case *ast.TypeSpec: + topDecls[s.Name.Obj] = true + case *ast.ValueSpec: + for _, id := range s.Names { + topDecls[id.Obj] = true + } + } + } + } + } + + // Find unresolved identifiers and uses of top-level declarations. + unresolved := make(map[string]bool) + usesTopDecl := false + var inspectFunc func(ast.Node) bool + inspectFunc = func(n ast.Node) bool { + // For selector expressions, only inspect the left hand side. + // (For an expression like fmt.Println, only add "fmt" to the + // set of unresolved names, not "Println".) + if e, ok := n.(*ast.SelectorExpr); ok { + ast.Inspect(e.X, inspectFunc) + return false + } + if id, ok := n.(*ast.Ident); ok { + if id.Obj == nil { + unresolved[id.Name] = true + } else if topDecls[id.Obj] { + usesTopDecl = true + } + } + return true + } + ast.Inspect(body, inspectFunc) + if usesTopDecl { + // We don't support examples that are not self-contained (yet). + return nil + } + + // Remove predeclared identifiers from unresolved list. + for n := range unresolved { + if predeclaredTypes[n] || predeclaredConstants[n] || predeclaredFuncs[n] { + delete(unresolved, n) + } + } + + // Use unresolved identifiers to determine the imports used by this + // example. The heuristic assumes package names match base import + // 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 { + continue + } + n := path.Base(p) + if s.Name != nil { + n = s.Name.Name + switch n { + case "_": + blankImports = append(blankImports, s) + continue + case ".": + // We can't resolve dot imports (yet). + return nil + } + } + if unresolved[n] { + namedImports[n] = p + delete(unresolved, n) + } + } + + // If there are other unresolved identifiers, give up because this + // synthesized file is not going to build. + if len(unresolved) > 0 { + return nil + } + + // Include documentation belonging to blank imports. + var comments []*ast.CommentGroup + 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) + } + } + + // Strip "Output:" commment and adjust body end position. + body, comments = stripOutputComment(body, comments) + + // Synthesize import declaration. + importDecl := &ast.GenDecl{ + Tok: token.IMPORT, + Lparen: 1, // Need non-zero Lparen and Rparen so that printer + Rparen: 1, // treats this as a factored import. + } + 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{ + Name: ast.NewIdent("main"), + Type: &ast.FuncType{}, + Body: body, + } + + // Synthesize file. + return &ast.File{ + Name: ast.NewIdent("main"), + Decls: []ast.Decl{importDecl, funcDecl}, + Comments: comments, + } +} + +// 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. + comments := file.Comments + if len(comments) > 0 && strings.HasPrefix(comments[0].Text(), "Copyright") { + comments = comments[1:] + } + + // Copy declaration slice, rewriting the ExampleX function to main. + var decls []ast.Decl + for _, d := range file.Decls { + if f, ok := d.(*ast.FuncDecl); ok && isTest(f.Name.Name, "Example") { + // Copy the FuncDecl, as it may be used elsewhere. + newF := *f + newF.Name = ast.NewIdent("main") + newF.Body, comments = stripOutputComment(f.Body, comments) + d = &newF + } + decls = append(decls, d) + } + + // Copy the File, as it may be used elsewhere. + f := *file + f.Name = ast.NewIdent("main") + f.Decls = decls + f.Comments = comments + return &f +} + +// stripOutputComment finds and removes an "Output:" commment from body +// and comments, and adjusts the body block's end position. +func stripOutputComment(body *ast.BlockStmt, comments []*ast.CommentGroup) (*ast.BlockStmt, []*ast.CommentGroup) { + // Do nothing if no "Output:" comment found. + i, last := lastComment(body, comments) + if last == nil || !outputPrefix.MatchString(last.Text()) { + return body, comments + } + + // Copy body and comments, as the originals may be used elsewhere. + newBody := &ast.BlockStmt{ + Lbrace: body.Lbrace, + List: body.List, + Rbrace: last.Pos(), + } + newComments := make([]*ast.CommentGroup, len(comments)-1) + copy(newComments, comments[:i]) + copy(newComments[i:], comments[i+1:]) + return newBody, newComments +} + +// lastComment returns the last comment inside the provided block. +func lastComment(b *ast.BlockStmt, c []*ast.CommentGroup) (i int, last *ast.CommentGroup) { + pos, end := b.Pos(), b.End() + for j, cg := range c { + if cg.Pos() < pos { + continue + } + if cg.End() > end { + break + } + i, last = j, cg + } + return +} diff --git a/src/pkg/go/doc/example_test.go b/src/pkg/go/doc/example_test.go new file mode 100644 index 000000000..b70efd93d --- /dev/null +++ b/src/pkg/go/doc/example_test.go @@ -0,0 +1,111 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package doc_test + +import ( + "bytes" + "go/doc" + "go/format" + "go/parser" + "go/token" + "strings" + "testing" +) + +const exampleTestFile = ` +package foo_test + +import ( + "fmt" + "log" + "os/exec" +) + +func ExampleHello() { + fmt.Println("Hello, world!") + // Output: Hello, world! +} + +func ExampleImport() { + out, err := exec.Command("date").Output() + if err != nil { + log.Fatal(err) + } + fmt.Printf("The date is %s\n", out) +} +` + +var exampleTestCases = []struct { + Name, Play, Output string +}{ + { + Name: "Hello", + Play: exampleHelloPlay, + Output: "Hello, world!\n", + }, + { + Name: "Import", + Play: exampleImportPlay, + }, +} + +const exampleHelloPlay = `package main + +import ( + "fmt" +) + +func main() { + fmt.Println("Hello, world!") +} +` +const exampleImportPlay = `package main + +import ( + "fmt" + "log" + "os/exec" +) + +func main() { + out, err := exec.Command("date").Output() + if err != nil { + log.Fatal(err) + } + fmt.Printf("The date is %s\n", out) +} +` + +func TestExamples(t *testing.T) { + fs := token.NewFileSet() + file, err := parser.ParseFile(fs, "test.go", strings.NewReader(exampleTestFile), parser.ParseComments) + if err != nil { + t.Fatal(err) + } + for i, e := range doc.Examples(file) { + c := exampleTestCases[i] + if e.Name != c.Name { + t.Errorf("got Name == %q, want %q", e.Name, c.Name) + } + if w := c.Play; w != "" { + var g string // hah + if e.Play == nil { + g = "<nil>" + } else { + b := new(bytes.Buffer) + if err := format.Node(b, fs, e.Play); err != nil { + t.Fatal(err) + } + g = b.String() + } + if g != w { + t.Errorf("%s: got Play == %q, want %q", c.Name, g, w) + } + } + if g, w := e.Output, c.Output; g != w { + t.Errorf("%s: got Output == %q, want %q", c.Name, g, w) + } + } +} diff --git a/src/pkg/go/doc/exports.go b/src/pkg/go/doc/exports.go index 146be5d87..ff01285d4 100644 --- a/src/pkg/go/doc/exports.go +++ b/src/pkg/go/doc/exports.go @@ -107,7 +107,7 @@ func (r *reader) filterParamList(fields *ast.FieldList) { // 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. +// struct or interface type has the Incomplete field set to true. // func (r *reader) filterType(parent *namedType, typ ast.Expr) { switch t := typ.(type) { diff --git a/src/pkg/go/doc/reader.go b/src/pkg/go/doc/reader.go index 5eaae37b7..dd6a57299 100644 --- a/src/pkg/go/doc/reader.go +++ b/src/pkg/go/doc/reader.go @@ -46,7 +46,7 @@ func (mset methodSet) set(f *ast.FuncDecl) { // since it has documentation, assume f is simply another // implementation and ignore it. This does not happen if the // caller is using go/build.ScanDir to determine the list of - // files implementing a package. + // files implementing a package. return } // function doesn't exist or has no documentation; use f @@ -149,6 +149,7 @@ type reader struct { doc string // package documentation, if any filenames []string bugs []string + notes map[string][]string // declarations imports map[string]int @@ -400,10 +401,23 @@ func (r *reader) readFunc(fun *ast.FuncDecl) { } var ( - bug_markers = regexp.MustCompile("^/[/*][ \t]*BUG\\(.*\\):[ \t]*") // BUG(uid): - bug_content = regexp.MustCompile("[^ \n\r\t]+") // at least one non-whitespace char + noteMarker = regexp.MustCompile(`^/[/*][ \t]*([A-Z][A-Z]+)\(.+\):[ \t]*(.*)`) // MARKER(uid) + noteContent = regexp.MustCompile(`[^ \n\r\t]+`) // at least one non-whitespace char ) +func readNote(c *ast.CommentGroup) (marker, annotation string) { + text := c.List[0].Text + if m := noteMarker.FindStringSubmatch(text); m != nil { + if btxt := m[2]; noteContent.MatchString(btxt) { + // non-empty MARKER comment; collect comment without the MARKER prefix + list := append([]*ast.Comment(nil), c.List...) // make a copy + list[0].Text = m[2] + return m[1], (&ast.CommentGroup{List: list}).Text() + } + } + return "", "" +} + // readFile adds the AST for a source file to the reader. // func (r *reader) readFile(src *ast.File) { @@ -469,16 +483,12 @@ func (r *reader) readFile(src *ast.File) { } } - // collect BUG(...) comments + // collect MARKER(...): annotations for _, c := range src.Comments { - text := c.List[0].Text - if m := bug_markers.FindStringIndex(text); m != nil { - // found a BUG comment; maybe empty - if btxt := text[m[1]:]; bug_content.MatchString(btxt) { - // non-empty BUG comment; collect comment without BUG prefix - list := append([]*ast.Comment(nil), c.List...) // make a copy - list[0].Text = text[m[1]:] - r.bugs = append(r.bugs, (&ast.CommentGroup{List: list}).Text()) + if marker, text := readNote(c); marker != "" { + r.notes[marker] = append(r.notes[marker], text) + if marker == "BUG" { + r.bugs = append(r.bugs, text) } } } @@ -492,9 +502,10 @@ func (r *reader) readPackage(pkg *ast.Package, mode Mode) { r.mode = mode r.types = make(map[string]*namedType) r.funcs = make(methodSet) + r.notes = make(map[string][]string) // sort package files before reading them so that the - // result result does not depend on map iteration order + // result does not depend on map iteration order i := 0 for filename := range pkg.Files { r.filenames[i] = filename @@ -515,29 +526,6 @@ func (r *reader) readPackage(pkg *ast.Package, mode Mode) { // ---------------------------------------------------------------------------- // Types -var predeclaredTypes = map[string]bool{ - "bool": true, - "byte": true, - "complex64": true, - "complex128": true, - "error": true, - "float32": true, - "float64": true, - "int": true, - "int8": true, - "int16": true, - "int32": true, - "int64": true, - "rune": true, - "string": true, - "uint": true, - "uint8": true, - "uint16": true, - "uint32": true, - "uint64": true, - "uintptr": true, -} - func customizeRecv(f *Func, recvTypeName string, embeddedIsPtr bool, level int) *Func { if f == nil || f.Decl == nil || f.Decl.Recv == nil || len(f.Decl.Recv.List) != 1 { return f // shouldn't happen, but be safe @@ -620,7 +608,7 @@ func (r *reader) computeMethodSets() { // 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. -// +// func (r *reader) cleanupTypes() { for _, t := range r.types { visible := r.isVisible(t.name) @@ -772,3 +760,54 @@ func sortedFuncs(m methodSet, allMethods bool) []*Func { ) return list } + +// ---------------------------------------------------------------------------- +// Predeclared identifiers + +var predeclaredTypes = map[string]bool{ + "bool": true, + "byte": true, + "complex64": true, + "complex128": true, + "error": true, + "float32": true, + "float64": true, + "int": true, + "int8": true, + "int16": true, + "int32": true, + "int64": true, + "rune": true, + "string": true, + "uint": true, + "uint8": true, + "uint16": true, + "uint32": true, + "uint64": true, + "uintptr": true, +} + +var predeclaredFuncs = map[string]bool{ + "append": true, + "cap": true, + "close": true, + "complex": true, + "copy": true, + "delete": true, + "imag": true, + "len": true, + "make": true, + "new": true, + "panic": true, + "print": true, + "println": true, + "real": true, + "recover": true, +} + +var predeclaredConstants = map[string]bool{ + "false": true, + "iota": true, + "nil": true, + "true": true, +} diff --git a/src/pkg/go/doc/synopsis.go b/src/pkg/go/doc/synopsis.go index 2192d78c0..2d1817439 100644 --- a/src/pkg/go/doc/synopsis.go +++ b/src/pkg/go/doc/synopsis.go @@ -4,7 +4,10 @@ package doc -import "unicode" +import ( + "strings" + "unicode" +) // firstSentenceLen returns the length of the first sentence in s. // The sentence ends after the first period followed by space and @@ -24,17 +27,12 @@ func firstSentenceLen(s string) int { return len(s) } -// Synopsis returns a cleaned version of the first sentence in s. -// That sentence ends after the first period followed by space and -// not preceded by exactly one uppercase letter. The result string -// has no \n, \r, or \t characters and uses only single spaces between -// words. -// -func Synopsis(s string) string { - n := firstSentenceLen(s) +// clean replaces each sequence of space, \n, \r, or \t characters +// with a single space and removes any trailing and leading spaces. +func clean(s string) string { var b []byte p := byte(' ') - for i := 0; i < n; i++ { + for i := 0; i < len(s); i++ { q := s[i] if q == '\n' || q == '\r' || q == '\t' { q = ' ' @@ -50,3 +48,26 @@ func Synopsis(s string) string { } return string(b) } + +// Synopsis returns a cleaned version of the first sentence in s. +// That sentence ends after the first period followed by space and +// not preceded by exactly one uppercase letter. The result string +// has no \n, \r, or \t characters and uses only single spaces between +// words. If s starts with any of the IllegalPrefixes, the result +// is the empty string. +// +func Synopsis(s string) string { + s = clean(s[0:firstSentenceLen(s)]) + for _, prefix := range IllegalPrefixes { + if strings.HasPrefix(strings.ToLower(s), prefix) { + return "" + } + } + return s +} + +var IllegalPrefixes = []string{ + "copyright", + "all rights", + "author", +} diff --git a/src/pkg/go/doc/synopsis_test.go b/src/pkg/go/doc/synopsis_test.go index dfc6598af..fd7081a07 100644 --- a/src/pkg/go/doc/synopsis_test.go +++ b/src/pkg/go/doc/synopsis_test.go @@ -28,6 +28,11 @@ var tests = []struct { {"P. Q. ", 8, "P. Q."}, {"Package Καλημέρα κόσμε.", 36, "Package Καλημέρα κόσμε."}, {"Package こんにちは 世界\n", 31, "Package こんにちは 世界"}, + {"Package foo does bar.", 21, "Package foo does bar."}, + {"Copyright 2012 Google, Inc. Package foo does bar.", 27, ""}, + {"All Rights reserved. Package foo does bar.", 20, ""}, + {"All rights reserved. Package foo does bar.", 20, ""}, + {"Authors: foo@bar.com. Package foo does bar.", 21, ""}, } func TestSynopsis(t *testing.T) { diff --git a/src/pkg/go/doc/testdata/a.0.golden b/src/pkg/go/doc/testdata/a.0.golden index 24db02d34..ae3756c84 100644 --- a/src/pkg/go/doc/testdata/a.0.golden +++ b/src/pkg/go/doc/testdata/a.0.golden @@ -8,6 +8,17 @@ FILENAMES testdata/a0.go testdata/a1.go +BUGS .Bugs is now deprecated, please use .Notes instead + // bug0 + // bug1 + BUGS // bug0 // bug1 + +SECBUGS + // sec hole 0 need to fix asap + +TODOS + // todo0 + // todo1 diff --git a/src/pkg/go/doc/testdata/a.1.golden b/src/pkg/go/doc/testdata/a.1.golden index 24db02d34..ae3756c84 100644 --- a/src/pkg/go/doc/testdata/a.1.golden +++ b/src/pkg/go/doc/testdata/a.1.golden @@ -8,6 +8,17 @@ FILENAMES testdata/a0.go testdata/a1.go +BUGS .Bugs is now deprecated, please use .Notes instead + // bug0 + // bug1 + BUGS // bug0 // bug1 + +SECBUGS + // sec hole 0 need to fix asap + +TODOS + // todo0 + // todo1 diff --git a/src/pkg/go/doc/testdata/a.2.golden b/src/pkg/go/doc/testdata/a.2.golden index 24db02d34..ae3756c84 100644 --- a/src/pkg/go/doc/testdata/a.2.golden +++ b/src/pkg/go/doc/testdata/a.2.golden @@ -8,6 +8,17 @@ FILENAMES testdata/a0.go testdata/a1.go +BUGS .Bugs is now deprecated, please use .Notes instead + // bug0 + // bug1 + BUGS // bug0 // bug1 + +SECBUGS + // sec hole 0 need to fix asap + +TODOS + // todo0 + // todo1 diff --git a/src/pkg/go/doc/testdata/a0.go b/src/pkg/go/doc/testdata/a0.go index dc552989e..71af470ee 100644 --- a/src/pkg/go/doc/testdata/a0.go +++ b/src/pkg/go/doc/testdata/a0.go @@ -6,3 +6,12 @@ package a //BUG(uid): bug0 + +//TODO(uid): todo0 + +// A note with some spaces after it, should be ignored (watch out for +// emacs modes that remove trailing whitespace). +//NOTE(uid): + +// SECBUG(uid): sec hole 0 +// need to fix asap diff --git a/src/pkg/go/doc/testdata/a1.go b/src/pkg/go/doc/testdata/a1.go index 098776c1b..9fad1e09b 100644 --- a/src/pkg/go/doc/testdata/a1.go +++ b/src/pkg/go/doc/testdata/a1.go @@ -6,3 +6,7 @@ package a //BUG(uid): bug1 + +//TODO(uid): todo1 + +//TODO(): ignored diff --git a/src/pkg/go/doc/testdata/benchmark.go b/src/pkg/go/doc/testdata/benchmark.go index 0aded5bb4..905e49644 100644 --- a/src/pkg/go/doc/testdata/benchmark.go +++ b/src/pkg/go/doc/testdata/benchmark.go @@ -13,7 +13,7 @@ import ( ) var matchBenchmarks = flag.String("test.bench", "", "regular expression to select benchmarks to run") -var benchTime = flag.Float64("test.benchtime", 1, "approximate run time for each benchmark, in seconds") +var benchTime = flag.Duration("test.benchtime", 1*time.Second, "approximate run time for each benchmark") // An internal type but exported because it is cross-package; part of the implementation // of go test. @@ -151,7 +151,7 @@ func (b *B) launch() { b.runN(n) // Run the benchmark for at least the specified amount of time. - d := time.Duration(*benchTime * float64(time.Second)) + d := *benchTime for !b.failed && b.duration < d && n < 1e9 { last := n // Predict iterations/sec. diff --git a/src/pkg/go/doc/testdata/e.go b/src/pkg/go/doc/testdata/e.go index 19dd138cf..ec432e3e5 100644 --- a/src/pkg/go/doc/testdata/e.go +++ b/src/pkg/go/doc/testdata/e.go @@ -106,7 +106,7 @@ type U4 struct { *u5 } -// U4.M should appear as method of U4. +// U4.M should appear as method of U4. func (*U4) M() {} type u5 struct { diff --git a/src/pkg/go/doc/testdata/error2.1.golden b/src/pkg/go/doc/testdata/error2.1.golden index 776bd1b3e..dbcc1b03e 100644 --- a/src/pkg/go/doc/testdata/error2.1.golden +++ b/src/pkg/go/doc/testdata/error2.1.golden @@ -10,7 +10,7 @@ FILENAMES TYPES // type I0 interface { - // When embedded, the the locally declared error interface + // When embedded, the locally-declared error interface // is only visible if all declarations are shown. error } diff --git a/src/pkg/go/doc/testdata/error2.go b/src/pkg/go/doc/testdata/error2.go index 6cc36feef..6ee96c245 100644 --- a/src/pkg/go/doc/testdata/error2.go +++ b/src/pkg/go/doc/testdata/error2.go @@ -5,7 +5,7 @@ package error2 type I0 interface { - // When embedded, the the locally declared error interface + // When embedded, the locally-declared error interface // is only visible if all declarations are shown. error } diff --git a/src/pkg/go/doc/testdata/template.txt b/src/pkg/go/doc/testdata/template.txt index 32e331cdd..d3882b6b9 100644 --- a/src/pkg/go/doc/testdata/template.txt +++ b/src/pkg/go/doc/testdata/template.txt @@ -60,6 +60,9 @@ TYPES {{end}}{{end}}{{end}}{{/* */}}{{with .Bugs}} -BUGS +BUGS .Bugs is now deprecated, please use .Notes instead {{range .}} {{synopsis .}} -{{end}}{{end}}
\ No newline at end of file +{{end}}{{end}}{{with .Notes}}{{range $marker, $content := .}} +{{$marker}}S +{{range $content}} {{synopsis .}} +{{end}}{{end}}{{end}}
\ No newline at end of file diff --git a/src/pkg/go/doc/testdata/testing.1.golden b/src/pkg/go/doc/testdata/testing.1.golden index d26a4685c..ffdb5c3b5 100644 --- a/src/pkg/go/doc/testdata/testing.1.golden +++ b/src/pkg/go/doc/testdata/testing.1.golden @@ -45,7 +45,7 @@ VARIABLES ) // - var benchTime = flag.Float64("test.benchtime", 1, "approximate run time for each benchmark, in seconds") + var benchTime = flag.Duration("test.benchtime", 1*time.Second, "approximate run time for each benchmark") // var matchBenchmarks = flag.String("test.bench", "", "regular expression to select benchmarks to run") diff --git a/src/pkg/go/doc/testdata/testing.go b/src/pkg/go/doc/testdata/testing.go index 71c1d1eaf..c2499ad77 100644 --- a/src/pkg/go/doc/testdata/testing.go +++ b/src/pkg/go/doc/testdata/testing.go @@ -197,7 +197,7 @@ func (c *common) Fatalf(format string, args ...interface{}) { c.FailNow() } -// Parallel signals that this test is to be run in parallel with (and only with) +// Parallel signals that this test is to be run in parallel with (and only with) // other parallel tests in this CPU group. func (t *T) Parallel() { t.signal <- (*T)(nil) // Release main testing loop @@ -215,7 +215,7 @@ func tRunner(t *T, test *InternalTest) { t.start = time.Now() // When this goroutine is done, either because test.F(t) - // returned normally or because a test failure triggered + // returned normally or because a test failure triggered // a call to runtime.Goexit, record the duration and send // a signal saying that the test is done. defer func() { |