2016-03-01 22:57:46 +00:00
|
|
|
// Copyright 2015 The Go Authors. All rights reserved.
|
2015-06-19 12:39:02 +10:00
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"flag"
|
2018-03-05 16:21:44 +11:00
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
2015-06-19 12:39:02 +10:00
|
|
|
"regexp"
|
2015-06-20 20:28:46 +10:00
|
|
|
"runtime"
|
cmd/doc: don't stop after first package if the symbol is not found
The test case is
go doc rand.Float64
The first package it finds is crypto/rand, which does not have a Float64.
Before this change, cmd/doc would stop there even though math/rand
has the symbol. After this change, we get:
% go doc rand.Float64
package rand // import "math/rand"
func Float64() float64
Float64 returns, as a float64, a pseudo-random number in [0.0,1.0) from the
default Source.
%
Another nice consequence is that if a symbol is not found, we might get
a longer list of packages that were examined:
% go doc rand.Int64
doc: no symbol Int64 in packages crypto/rand, math/rand
exit status 1
%
This change introduces a coroutine to scan the file system so that if
the symbol is not found, the coroutine can deliver another path to try.
(This is darned close to the original motivation for coroutines.)
Paths are delivered on an unbuffered channel so the scanner does
not proceed until candidate paths are needed.
The scanner is attached to a new type, called Dirs, that caches the results
so if we need to scan a second time, we don't walk the file system
again. This is significantly more efficient than the existing code, which
could scan the tree multiple times looking for a package with
the symbol.
Change-Id: I2789505b9992cf04c19376c51ae09af3bc305f7f
Reviewed-on: https://go-review.googlesource.com/14921
Reviewed-by: Andrew Gerrand <adg@golang.org>
2015-09-23 16:49:30 -07:00
|
|
|
"strings"
|
2015-06-19 12:39:02 +10:00
|
|
|
"testing"
|
|
|
|
|
)
|
|
|
|
|
|
2018-03-21 12:36:58 +00:00
|
|
|
func TestMain(m *testing.M) {
|
cmd/doc: skip directories like other go tools
It was skipping dirs starting with ".", but it was missing the "_"
prefix and the "testdata" name. From "go help packages":
Directory and file names that begin with "." or "_" are ignored
by the go tool, as are directories named "testdata".
Before the change:
$ go doc z # using src/cmd/go/testdata/testvendor/src/q/z
package z // import "."
After the fix, it falls back to the current directory, as expected when
a single argument isn't found as a package in $GOPATH.
TestMain needs a small adjustment to keep the tests working, as now
their use of cmd/doc/testdata would normally not work.
This is the second try for this fix; the first time around, we included
cmd/doc/testdata to the dirs list by sending it to the channel via a
goroutine. However, that can end up in a send to a closed channel, if
GOROOT is a very small directory tree or missing.
To avoid that possibility, include the extra directory by pre-populating
the paths list, before the walking of GOROOT and GOPATH actually starts.
Fixes #24462.
Change-Id: I3b95b6431578e0d5cbb8342f305debc4ccb5f656
Reviewed-on: https://go-review.googlesource.com/109216
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Elias Naur <elias.naur@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2018-04-13 19:39:32 +01:00
|
|
|
// Clear GOPATH so we don't access the user's own packages in the test.
|
2018-03-21 12:36:58 +00:00
|
|
|
buildCtx.GOPATH = ""
|
2018-07-30 14:53:44 -04:00
|
|
|
testGOPATH = true // force GOPATH mode; module test is in cmd/go/testdata/script/mod_doc.txt
|
cmd/doc: skip directories like other go tools
It was skipping dirs starting with ".", but it was missing the "_"
prefix and the "testdata" name. From "go help packages":
Directory and file names that begin with "." or "_" are ignored
by the go tool, as are directories named "testdata".
Before the change:
$ go doc z # using src/cmd/go/testdata/testvendor/src/q/z
package z // import "."
After the fix, it falls back to the current directory, as expected when
a single argument isn't found as a package in $GOPATH.
TestMain needs a small adjustment to keep the tests working, as now
their use of cmd/doc/testdata would normally not work.
This is the second try for this fix; the first time around, we included
cmd/doc/testdata to the dirs list by sending it to the channel via a
goroutine. However, that can end up in a send to a closed channel, if
GOROOT is a very small directory tree or missing.
To avoid that possibility, include the extra directory by pre-populating
the paths list, before the walking of GOROOT and GOPATH actually starts.
Fixes #24462.
Change-Id: I3b95b6431578e0d5cbb8342f305debc4ccb5f656
Reviewed-on: https://go-review.googlesource.com/109216
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Elias Naur <elias.naur@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2018-04-13 19:39:32 +01:00
|
|
|
|
|
|
|
|
// Add $GOROOT/src/cmd/doc/testdata explicitly so we can access its contents in the test.
|
|
|
|
|
// Normally testdata directories are ignored, but sending it to dirs.scan directly is
|
|
|
|
|
// a hack that works around the check.
|
|
|
|
|
testdataDir, err := filepath.Abs("testdata")
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
2018-07-30 14:53:44 -04:00
|
|
|
dirsInit(Dir{"testdata", testdataDir}, Dir{"testdata/nested", filepath.Join(testdataDir, "nested")}, Dir{"testdata/nested/nested", filepath.Join(testdataDir, "nested", "nested")})
|
cmd/doc: skip directories like other go tools
It was skipping dirs starting with ".", but it was missing the "_"
prefix and the "testdata" name. From "go help packages":
Directory and file names that begin with "." or "_" are ignored
by the go tool, as are directories named "testdata".
Before the change:
$ go doc z # using src/cmd/go/testdata/testvendor/src/q/z
package z // import "."
After the fix, it falls back to the current directory, as expected when
a single argument isn't found as a package in $GOPATH.
TestMain needs a small adjustment to keep the tests working, as now
their use of cmd/doc/testdata would normally not work.
This is the second try for this fix; the first time around, we included
cmd/doc/testdata to the dirs list by sending it to the channel via a
goroutine. However, that can end up in a send to a closed channel, if
GOROOT is a very small directory tree or missing.
To avoid that possibility, include the extra directory by pre-populating
the paths list, before the walking of GOROOT and GOPATH actually starts.
Fixes #24462.
Change-Id: I3b95b6431578e0d5cbb8342f305debc4ccb5f656
Reviewed-on: https://go-review.googlesource.com/109216
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Elias Naur <elias.naur@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2018-04-13 19:39:32 +01:00
|
|
|
|
2018-03-21 12:36:58 +00:00
|
|
|
os.Exit(m.Run())
|
|
|
|
|
}
|
|
|
|
|
|
cmd/doc: don't stop after first package if the symbol is not found
The test case is
go doc rand.Float64
The first package it finds is crypto/rand, which does not have a Float64.
Before this change, cmd/doc would stop there even though math/rand
has the symbol. After this change, we get:
% go doc rand.Float64
package rand // import "math/rand"
func Float64() float64
Float64 returns, as a float64, a pseudo-random number in [0.0,1.0) from the
default Source.
%
Another nice consequence is that if a symbol is not found, we might get
a longer list of packages that were examined:
% go doc rand.Int64
doc: no symbol Int64 in packages crypto/rand, math/rand
exit status 1
%
This change introduces a coroutine to scan the file system so that if
the symbol is not found, the coroutine can deliver another path to try.
(This is darned close to the original motivation for coroutines.)
Paths are delivered on an unbuffered channel so the scanner does
not proceed until candidate paths are needed.
The scanner is attached to a new type, called Dirs, that caches the results
so if we need to scan a second time, we don't walk the file system
again. This is significantly more efficient than the existing code, which
could scan the tree multiple times looking for a package with
the symbol.
Change-Id: I2789505b9992cf04c19376c51ae09af3bc305f7f
Reviewed-on: https://go-review.googlesource.com/14921
Reviewed-by: Andrew Gerrand <adg@golang.org>
2015-09-23 16:49:30 -07:00
|
|
|
func maybeSkip(t *testing.T) {
|
|
|
|
|
if strings.HasPrefix(runtime.GOOS, "nacl") {
|
|
|
|
|
t.Skip("nacl does not have a full file tree")
|
|
|
|
|
}
|
|
|
|
|
if runtime.GOOS == "darwin" && strings.HasPrefix(runtime.GOARCH, "arm") {
|
|
|
|
|
t.Skip("darwin/arm does not have a full file tree")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-05 16:21:44 +11:00
|
|
|
type isDotSlashTest struct {
|
|
|
|
|
str string
|
|
|
|
|
result bool
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var isDotSlashTests = []isDotSlashTest{
|
|
|
|
|
{``, false},
|
|
|
|
|
{`x`, false},
|
|
|
|
|
{`...`, false},
|
|
|
|
|
{`.../`, false},
|
|
|
|
|
{`...\`, false},
|
|
|
|
|
|
|
|
|
|
{`.`, true},
|
|
|
|
|
{`./`, true},
|
|
|
|
|
{`.\`, true},
|
|
|
|
|
{`./x`, true},
|
|
|
|
|
{`.\x`, true},
|
|
|
|
|
|
|
|
|
|
{`..`, true},
|
|
|
|
|
{`../`, true},
|
|
|
|
|
{`..\`, true},
|
|
|
|
|
{`../x`, true},
|
|
|
|
|
{`..\x`, true},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestIsDotSlashPath(t *testing.T) {
|
|
|
|
|
for _, test := range isDotSlashTests {
|
|
|
|
|
if result := isDotSlash(test.str); result != test.result {
|
|
|
|
|
t.Errorf("isDotSlash(%q) = %t; expected %t", test.str, result, test.result)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-19 12:39:02 +10:00
|
|
|
type test struct {
|
|
|
|
|
name string
|
|
|
|
|
args []string // Arguments to "[go] doc".
|
|
|
|
|
yes []string // Regular expressions that should match.
|
|
|
|
|
no []string // Regular expressions that should not match.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const p = "cmd/doc/testdata"
|
|
|
|
|
|
|
|
|
|
var tests = []test{
|
|
|
|
|
// Sanity check.
|
|
|
|
|
{
|
2015-06-20 08:12:10 +10:00
|
|
|
"sanity check",
|
|
|
|
|
[]string{p},
|
|
|
|
|
[]string{`type ExportedType struct`},
|
2015-06-19 12:39:02 +10:00
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Package dump includes import, package statement.
|
|
|
|
|
{
|
|
|
|
|
"package clause",
|
|
|
|
|
[]string{p},
|
|
|
|
|
[]string{`package pkg.*cmd/doc/testdata`},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Constants.
|
|
|
|
|
// Package dump
|
|
|
|
|
{
|
|
|
|
|
"full package",
|
|
|
|
|
[]string{p},
|
|
|
|
|
[]string{
|
|
|
|
|
`Package comment`,
|
cmd/doc: ensure summaries truly are only one line
The documentation for doc says:
> Doc prints the documentation comments associated with the item identified by its
> arguments (a package, const, func, type, var, or method) followed by a one-line
> summary of each of the first-level items "under" that item (package-level
> declarations for a package, methods for a type, etc.).
Certain variables (and constants, functions, and types) have value specifications
that are multiple lines long. Prior to this change, doc would print out all of the
lines necessary to display the value. This is inconsistent with the documented
behavior, which guarantees a one-line summary for all first-level items.
We fix this here by writing a general oneLineNode method that always returns
a one-line summary (guaranteed!) of any input node.
Packages like image/color/palette and unicode now become much
more readable since large slices are now a single line.
$ go doc image/color/palette
<<<
// Before:
var Plan9 = []color.Color{
color.RGBA{0x00, 0x00, 0x00, 0xff},
color.RGBA{0x00, 0x00, 0x44, 0xff},
color.RGBA{0x00, 0x00, 0x88, 0xff},
... // Hundreds of more lines!
}
var WebSafe = []color.Color{
color.RGBA{0x00, 0x00, 0x00, 0xff},
color.RGBA{0x00, 0x00, 0x33, 0xff},
color.RGBA{0x00, 0x00, 0x66, 0xff},
... // Hundreds of more lines!
}
// After:
var Plan9 = []color.Color{ ... }
var WebSafe = []color.Color{ ... }
>>>
In order to test this, I ran `go doc` and `go doc -u` on all of the
standard library packages and diff'd the output with and without the
change to ensure that all differences were intended.
Fixes #13072
Change-Id: Ida10b7796b7e4e174a929b55c60813a9eb7158fe
Reviewed-on: https://go-review.googlesource.com/25420
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-08-03 00:31:17 -07:00
|
|
|
`const ExportedConstant = 1`, // Simple constant.
|
|
|
|
|
`const ConstOne = 1`, // First entry in constant block.
|
|
|
|
|
`const ConstFive ...`, // From block starting with unexported constant.
|
|
|
|
|
`var ExportedVariable = 1`, // Simple variable.
|
|
|
|
|
`var VarOne = 1`, // First entry in variable block.
|
|
|
|
|
`func ExportedFunc\(a int\) bool`, // Function.
|
|
|
|
|
`func ReturnUnexported\(\) unexportedType`, // Function with unexported return type.
|
|
|
|
|
`type ExportedType struct{ ... }`, // Exported type.
|
|
|
|
|
`const ExportedTypedConstant ExportedType = iota`, // Typed constant.
|
|
|
|
|
`const ExportedTypedConstant_unexported unexportedType`, // Typed constant, exported for unexported type.
|
|
|
|
|
`const ConstLeft2 uint64 ...`, // Typed constant using unexported iota.
|
|
|
|
|
`const ConstGroup1 unexportedType = iota ...`, // Typed constant using unexported type.
|
|
|
|
|
`const ConstGroup4 ExportedType = ExportedType{}`, // Typed constant using exported type.
|
|
|
|
|
`const MultiLineConst = ...`, // Multi line constant.
|
|
|
|
|
`var MultiLineVar = map\[struct{ ... }\]struct{ ... }{ ... }`, // Multi line variable.
|
|
|
|
|
`func MultiLineFunc\(x interface{ ... }\) \(r struct{ ... }\)`, // Multi line function.
|
cmd/doc: truncate long lists of arguments
Some field-lists (especially in generated code) can be excessively long.
In the one-line printout, it does not make sense to print all elements
of the list if line-wrapping causes the "one-line" to become multi-line.
// Before:
var LongLine = newLongLine("someArgument1", "someArgument2", "someArgument3", "someArgument4", "someArgument5", "someArgument6", "someArgument7", "someArgument8")
// After:
var LongLine = newLongLine("someArgument1", "someArgument2", "someArgument3", "someArgument4", ...)
Change-Id: I4bbbe2dbd1d7be9f02d63431d213088c3dee332c
Reviewed-on: https://go-review.googlesource.com/36031
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2017-01-11 16:53:49 -08:00
|
|
|
`var LongLine = newLongLine\(("someArgument[1-4]", ){4}...\)`, // Long list of arguments.
|
go/printer, gofmt: tuned table alignment for better results
The go/printer (and thus gofmt) uses a heuristic to determine
whether to break alignment between elements of an expression
list which is spread across multiple lines. The heuristic only
kicked in if the entry sizes (character length) was above a
certain threshold (20) and the ratio between the previous and
current entry size was above a certain value (4).
This heuristic worked reasonably most of the time, but also
led to unfortunate breaks in many cases where a single entry
was suddenly much smaller (or larger) then the previous one.
The behavior of gofmt was sufficiently mysterious in some of
these situations that many issues were filed against it.
The simplest solution to address this problem is to remove
the heuristic altogether and have a programmer introduce
empty lines to force different alignments if it improves
readability. The problem with that approach is that the
places where it really matters, very long tables with many
(hundreds, or more) entries, may be machine-generated and
not "post-processed" by a human (e.g., unicode/utf8/tables.go).
If a single one of those entries is overlong, the result
would be that the alignment would force all comments or
values in key:value pairs to be adjusted to that overlong
value, making the table hard to read (e.g., that entry may
not even be visible on screen and all other entries seem
spaced out too wide).
Instead, we opted for a slightly improved heuristic that
behaves much better for "normal", human-written code.
1) The threshold is increased from 20 to 40. This disables
the heuristic for many common cases yet even if the alignment
is not "ideal", 40 is not that many characters per line with
todays screens, making it very likely that the entire line
remains "visible" in an editor.
2) Changed the heuristic to not simply look at the size ratio
between current and previous line, but instead considering the
geometric mean of the sizes of the previous (aligned) lines.
This emphasizes the "overall picture" of the previous lines,
rather than a single one (which might be an outlier).
3) Changed the ratio from 4 to 2.5. Now that we ignore sizes
below 40, a ratio of 4 would mean that a new entry would have
to be 4 times bigger (160) or smaller (10) before alignment
would be broken. A ratio of 2.5 seems more sensible.
Applied updated gofmt to all of src and misc. Also tested
against several former issues that complained about this
and verified that the output for the given examples is
satisfactory (added respective test cases).
Some of the files changed because they were not gofmt-ed
in the first place.
For #644.
For #7335.
For #10392.
(and probably more related issues)
Fixes #22852.
Change-Id: I5e48b3d3b157a5cf2d649833b7297b33f43a6f6e
2018-04-03 17:05:47 -07:00
|
|
|
`type T1 = T2`, // Type alias
|
2015-06-19 12:39:02 +10:00
|
|
|
},
|
|
|
|
|
[]string{
|
2018-10-10 11:50:49 +11:00
|
|
|
`const internalConstant = 2`, // No internal constants.
|
|
|
|
|
`var internalVariable = 2`, // No internal variables.
|
|
|
|
|
`func internalFunc(a int) bool`, // No internal functions.
|
|
|
|
|
`Comment about exported constant`, // No comment for single constant.
|
|
|
|
|
`Comment about exported variable`, // No comment for single variable.
|
|
|
|
|
`Comment about block of constants`, // No comment for constant block.
|
|
|
|
|
`Comment about block of variables`, // No comment for variable block.
|
|
|
|
|
`Comment before ConstOne`, // No comment for first entry in constant block.
|
|
|
|
|
`Comment before VarOne`, // No comment for first entry in variable block.
|
|
|
|
|
`ConstTwo = 2`, // No second entry in constant block.
|
|
|
|
|
`VarTwo = 2`, // No second entry in variable block.
|
|
|
|
|
`VarFive = 5`, // From block starting with unexported variable.
|
|
|
|
|
`type unexportedType`, // No unexported type.
|
|
|
|
|
`unexportedTypedConstant`, // No unexported typed constant.
|
|
|
|
|
`\bField`, // No fields.
|
|
|
|
|
`Method`, // No methods.
|
|
|
|
|
`someArgument[5-8]`, // No truncated arguments.
|
|
|
|
|
`type T1 T2`, // Type alias does not display as type declaration.
|
2015-06-19 12:39:02 +10:00
|
|
|
},
|
|
|
|
|
},
|
2018-10-13 21:06:43 +11:00
|
|
|
// Package dump -all
|
|
|
|
|
{
|
|
|
|
|
"full package",
|
|
|
|
|
[]string{"-all", p},
|
|
|
|
|
[]string{
|
|
|
|
|
`package pkg .*import`,
|
|
|
|
|
`Package comment`,
|
|
|
|
|
`CONSTANTS`,
|
|
|
|
|
`Comment before ConstOne`,
|
|
|
|
|
`ConstOne = 1`,
|
|
|
|
|
`ConstTwo = 2 // Comment on line with ConstTwo`,
|
|
|
|
|
`ConstFive`,
|
|
|
|
|
`ConstSix`,
|
|
|
|
|
`Const block where first entry is unexported`,
|
|
|
|
|
`ConstLeft2, constRight2 uint64`,
|
|
|
|
|
`constLeft3, ConstRight3`,
|
|
|
|
|
`ConstLeft4, ConstRight4`,
|
|
|
|
|
`Duplicate = iota`,
|
|
|
|
|
`const CaseMatch = 1`,
|
|
|
|
|
`const Casematch = 2`,
|
|
|
|
|
`const ExportedConstant = 1`,
|
|
|
|
|
`const MultiLineConst = `,
|
|
|
|
|
`MultiLineString1`,
|
|
|
|
|
`VARIABLES`,
|
|
|
|
|
`Comment before VarOne`,
|
|
|
|
|
`VarOne = 1`,
|
|
|
|
|
`Comment about block of variables`,
|
|
|
|
|
`VarFive = 5`,
|
|
|
|
|
`var ExportedVariable = 1`,
|
|
|
|
|
`var LongLine = newLongLine\(`,
|
|
|
|
|
`var MultiLineVar = map\[struct {`,
|
|
|
|
|
`FUNCTIONS`,
|
|
|
|
|
`func ExportedFunc\(a int\) bool`,
|
|
|
|
|
`Comment about exported function`,
|
|
|
|
|
`func MultiLineFunc\(x interface`,
|
|
|
|
|
`func ReturnUnexported\(\) unexportedType`,
|
|
|
|
|
`TYPES`,
|
|
|
|
|
`type ExportedInterface interface`,
|
|
|
|
|
`type ExportedStructOneField struct`,
|
|
|
|
|
`type ExportedType struct`,
|
|
|
|
|
`Comment about exported type`,
|
|
|
|
|
`const ConstGroup4 ExportedType = ExportedType`,
|
|
|
|
|
`ExportedTypedConstant ExportedType = iota`,
|
|
|
|
|
`Constants tied to ExportedType`,
|
|
|
|
|
`func ExportedTypeConstructor\(\) \*ExportedType`,
|
|
|
|
|
`Comment about constructor for exported type`,
|
|
|
|
|
`func ReturnExported\(\) ExportedType`,
|
|
|
|
|
`func \(ExportedType\) ExportedMethod\(a int\) bool`,
|
|
|
|
|
`Comment about exported method`,
|
|
|
|
|
`type T1 = T2`,
|
|
|
|
|
`type T2 int`,
|
|
|
|
|
},
|
|
|
|
|
[]string{
|
|
|
|
|
`constThree`,
|
|
|
|
|
`_, _ uint64 = 2 \* iota, 1 << iota`,
|
|
|
|
|
`constLeft1, constRight1`,
|
|
|
|
|
`duplicate`,
|
|
|
|
|
`varFour`,
|
|
|
|
|
`func internalFunc`,
|
|
|
|
|
`unexportedField`,
|
|
|
|
|
`func \(unexportedType\)`,
|
|
|
|
|
},
|
|
|
|
|
},
|
2015-06-19 12:39:02 +10:00
|
|
|
// Package dump -u
|
|
|
|
|
{
|
|
|
|
|
"full package with u",
|
|
|
|
|
[]string{`-u`, p},
|
|
|
|
|
[]string{
|
2016-08-01 20:04:25 -07:00
|
|
|
`const ExportedConstant = 1`, // Simple constant.
|
|
|
|
|
`const internalConstant = 2`, // Internal constants.
|
|
|
|
|
`func internalFunc\(a int\) bool`, // Internal functions.
|
|
|
|
|
`func ReturnUnexported\(\) unexportedType`, // Function with unexported return type.
|
2015-06-19 12:39:02 +10:00
|
|
|
},
|
|
|
|
|
[]string{
|
|
|
|
|
`Comment about exported constant`, // No comment for simple constant.
|
|
|
|
|
`Comment about block of constants`, // No comment for constant block.
|
|
|
|
|
`Comment about internal function`, // No comment for internal function.
|
cmd/doc: ensure summaries truly are only one line
The documentation for doc says:
> Doc prints the documentation comments associated with the item identified by its
> arguments (a package, const, func, type, var, or method) followed by a one-line
> summary of each of the first-level items "under" that item (package-level
> declarations for a package, methods for a type, etc.).
Certain variables (and constants, functions, and types) have value specifications
that are multiple lines long. Prior to this change, doc would print out all of the
lines necessary to display the value. This is inconsistent with the documented
behavior, which guarantees a one-line summary for all first-level items.
We fix this here by writing a general oneLineNode method that always returns
a one-line summary (guaranteed!) of any input node.
Packages like image/color/palette and unicode now become much
more readable since large slices are now a single line.
$ go doc image/color/palette
<<<
// Before:
var Plan9 = []color.Color{
color.RGBA{0x00, 0x00, 0x00, 0xff},
color.RGBA{0x00, 0x00, 0x44, 0xff},
color.RGBA{0x00, 0x00, 0x88, 0xff},
... // Hundreds of more lines!
}
var WebSafe = []color.Color{
color.RGBA{0x00, 0x00, 0x00, 0xff},
color.RGBA{0x00, 0x00, 0x33, 0xff},
color.RGBA{0x00, 0x00, 0x66, 0xff},
... // Hundreds of more lines!
}
// After:
var Plan9 = []color.Color{ ... }
var WebSafe = []color.Color{ ... }
>>>
In order to test this, I ran `go doc` and `go doc -u` on all of the
standard library packages and diff'd the output with and without the
change to ensure that all differences were intended.
Fixes #13072
Change-Id: Ida10b7796b7e4e174a929b55c60813a9eb7158fe
Reviewed-on: https://go-review.googlesource.com/25420
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-08-03 00:31:17 -07:00
|
|
|
`MultiLine(String|Method|Field)`, // No data from multi line portions.
|
2015-06-19 12:39:02 +10:00
|
|
|
},
|
|
|
|
|
},
|
2018-10-13 21:06:43 +11:00
|
|
|
// Package dump -u -all
|
|
|
|
|
{
|
|
|
|
|
"full package",
|
|
|
|
|
[]string{"-u", "-all", p},
|
|
|
|
|
[]string{
|
|
|
|
|
`package pkg .*import`,
|
|
|
|
|
`Package comment`,
|
|
|
|
|
`CONSTANTS`,
|
|
|
|
|
`Comment before ConstOne`,
|
|
|
|
|
`ConstOne += 1`,
|
|
|
|
|
`ConstTwo += 2 // Comment on line with ConstTwo`,
|
|
|
|
|
`constThree = 3 // Comment on line with constThree`,
|
|
|
|
|
`ConstFive`,
|
|
|
|
|
`const internalConstant += 2`,
|
|
|
|
|
`Comment about internal constant`,
|
|
|
|
|
`VARIABLES`,
|
|
|
|
|
`Comment before VarOne`,
|
|
|
|
|
`VarOne += 1`,
|
|
|
|
|
`Comment about block of variables`,
|
|
|
|
|
`varFour += 4`,
|
|
|
|
|
`VarFive += 5`,
|
|
|
|
|
`varSix += 6`,
|
|
|
|
|
`var ExportedVariable = 1`,
|
|
|
|
|
`var LongLine = newLongLine\(`,
|
|
|
|
|
`var MultiLineVar = map\[struct {`,
|
|
|
|
|
`var internalVariable = 2`,
|
|
|
|
|
`Comment about internal variable`,
|
|
|
|
|
`FUNCTIONS`,
|
|
|
|
|
`func ExportedFunc\(a int\) bool`,
|
|
|
|
|
`Comment about exported function`,
|
|
|
|
|
`func MultiLineFunc\(x interface`,
|
|
|
|
|
`func internalFunc\(a int\) bool`,
|
|
|
|
|
`Comment about internal function`,
|
|
|
|
|
`func newLongLine\(ss .*string\)`,
|
|
|
|
|
`TYPES`,
|
|
|
|
|
`type ExportedType struct`,
|
|
|
|
|
`type T1 = T2`,
|
|
|
|
|
`type T2 int`,
|
|
|
|
|
`type unexportedType int`,
|
|
|
|
|
`Comment about unexported type`,
|
|
|
|
|
`ConstGroup1 unexportedType = iota`,
|
|
|
|
|
`ConstGroup2`,
|
|
|
|
|
`ConstGroup3`,
|
|
|
|
|
`ExportedTypedConstant_unexported unexportedType = iota`,
|
|
|
|
|
`Constants tied to unexportedType`,
|
|
|
|
|
`const unexportedTypedConstant unexportedType = 1`,
|
|
|
|
|
`func ReturnUnexported\(\) unexportedType`,
|
|
|
|
|
`func \(unexportedType\) ExportedMethod\(\) bool`,
|
|
|
|
|
`func \(unexportedType\) unexportedMethod\(\) bool`,
|
|
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
2015-06-19 12:39:02 +10:00
|
|
|
|
|
|
|
|
// Single constant.
|
|
|
|
|
{
|
|
|
|
|
"single constant",
|
|
|
|
|
[]string{p, `ExportedConstant`},
|
|
|
|
|
[]string{
|
|
|
|
|
`Comment about exported constant`, // Include comment.
|
|
|
|
|
`const ExportedConstant = 1`,
|
|
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
// Single constant -u.
|
|
|
|
|
{
|
|
|
|
|
"single constant with -u",
|
|
|
|
|
[]string{`-u`, p, `internalConstant`},
|
|
|
|
|
[]string{
|
|
|
|
|
`Comment about internal constant`, // Include comment.
|
|
|
|
|
`const internalConstant = 2`,
|
|
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
// Block of constants.
|
|
|
|
|
{
|
|
|
|
|
"block of constants",
|
|
|
|
|
[]string{p, `ConstTwo`},
|
|
|
|
|
[]string{
|
|
|
|
|
`Comment before ConstOne.\n.*ConstOne = 1`, // First...
|
|
|
|
|
`ConstTwo = 2.*Comment on line with ConstTwo`, // And second show up.
|
|
|
|
|
`Comment about block of constants`, // Comment does too.
|
|
|
|
|
},
|
|
|
|
|
[]string{
|
|
|
|
|
`constThree`, // No unexported constant.
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
// Block of constants -u.
|
|
|
|
|
{
|
|
|
|
|
"block of constants with -u",
|
|
|
|
|
[]string{"-u", p, `constThree`},
|
|
|
|
|
[]string{
|
|
|
|
|
`constThree = 3.*Comment on line with constThree`,
|
|
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
2018-10-10 11:50:49 +11:00
|
|
|
// Block of constants -src.
|
|
|
|
|
{
|
|
|
|
|
"block of constants with -src",
|
|
|
|
|
[]string{"-src", p, `ConstTwo`},
|
|
|
|
|
[]string{
|
|
|
|
|
`Comment about block of constants`, // Top comment.
|
|
|
|
|
`ConstOne.*=.*1`, // Each constant seen.
|
|
|
|
|
`ConstTwo.*=.*2.*Comment on line with ConstTwo`,
|
|
|
|
|
`constThree`, // Even unexported constants.
|
|
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
2016-08-02 18:42:58 -07:00
|
|
|
// Block of constants with carryover type from unexported field.
|
|
|
|
|
{
|
|
|
|
|
"block of constants with carryover type",
|
|
|
|
|
[]string{p, `ConstLeft2`},
|
|
|
|
|
[]string{
|
|
|
|
|
`ConstLeft2, constRight2 uint64`,
|
|
|
|
|
`constLeft3, ConstRight3`,
|
|
|
|
|
`ConstLeft4, ConstRight4`,
|
|
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
// Block of constants -u with carryover type from unexported field.
|
|
|
|
|
{
|
|
|
|
|
"block of constants with carryover type",
|
|
|
|
|
[]string{"-u", p, `ConstLeft2`},
|
|
|
|
|
[]string{
|
|
|
|
|
`_, _ uint64 = 2 \* iota, 1 << iota`,
|
|
|
|
|
`constLeft1, constRight1`,
|
|
|
|
|
`ConstLeft2, constRight2`,
|
|
|
|
|
`constLeft3, ConstRight3`,
|
|
|
|
|
`ConstLeft4, ConstRight4`,
|
|
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
2015-06-19 12:39:02 +10:00
|
|
|
|
|
|
|
|
// Single variable.
|
|
|
|
|
{
|
|
|
|
|
"single variable",
|
|
|
|
|
[]string{p, `ExportedVariable`},
|
|
|
|
|
[]string{
|
|
|
|
|
`ExportedVariable`, // Include comment.
|
2015-06-21 05:10:05 +10:00
|
|
|
`var ExportedVariable = 1`,
|
2015-06-19 12:39:02 +10:00
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
// Single variable -u.
|
|
|
|
|
{
|
|
|
|
|
"single variable with -u",
|
|
|
|
|
[]string{`-u`, p, `internalVariable`},
|
|
|
|
|
[]string{
|
|
|
|
|
`Comment about internal variable`, // Include comment.
|
2015-06-21 05:10:05 +10:00
|
|
|
`var internalVariable = 2`,
|
2015-06-19 12:39:02 +10:00
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
// Block of variables.
|
|
|
|
|
{
|
|
|
|
|
"block of variables",
|
|
|
|
|
[]string{p, `VarTwo`},
|
|
|
|
|
[]string{
|
|
|
|
|
`Comment before VarOne.\n.*VarOne = 1`, // First...
|
|
|
|
|
`VarTwo = 2.*Comment on line with VarTwo`, // And second show up.
|
|
|
|
|
`Comment about block of variables`, // Comment does too.
|
|
|
|
|
},
|
|
|
|
|
[]string{
|
|
|
|
|
`varThree= 3`, // No unexported variable.
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
// Block of variables -u.
|
|
|
|
|
{
|
|
|
|
|
"block of variables with -u",
|
|
|
|
|
[]string{"-u", p, `varThree`},
|
|
|
|
|
[]string{
|
|
|
|
|
`varThree = 3.*Comment on line with varThree`,
|
|
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Function.
|
|
|
|
|
{
|
|
|
|
|
"function",
|
|
|
|
|
[]string{p, `ExportedFunc`},
|
|
|
|
|
[]string{
|
|
|
|
|
`Comment about exported function`, // Include comment.
|
|
|
|
|
`func ExportedFunc\(a int\) bool`,
|
|
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
// Function -u.
|
|
|
|
|
{
|
|
|
|
|
"function with -u",
|
|
|
|
|
[]string{"-u", p, `internalFunc`},
|
|
|
|
|
[]string{
|
|
|
|
|
`Comment about internal function`, // Include comment.
|
|
|
|
|
`func internalFunc\(a int\) bool`,
|
|
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
2018-10-10 11:50:49 +11:00
|
|
|
// Function with -src.
|
|
|
|
|
{
|
|
|
|
|
"function with -src",
|
|
|
|
|
[]string{"-src", p, `ExportedFunc`},
|
|
|
|
|
[]string{
|
|
|
|
|
`Comment about exported function`, // Include comment.
|
|
|
|
|
`func ExportedFunc\(a int\) bool`,
|
|
|
|
|
`return true != false`, // Include body.
|
|
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
2015-06-19 12:39:02 +10:00
|
|
|
|
|
|
|
|
// Type.
|
|
|
|
|
{
|
|
|
|
|
"type",
|
|
|
|
|
[]string{p, `ExportedType`},
|
|
|
|
|
[]string{
|
|
|
|
|
`Comment about exported type`, // Include comment.
|
|
|
|
|
`type ExportedType struct`, // Type definition.
|
2015-10-23 17:09:39 -07:00
|
|
|
`Comment before exported field.*\n.*ExportedField +int` +
|
2018-10-10 11:50:49 +11:00
|
|
|
`.*Comment on line with exported field`,
|
|
|
|
|
`ExportedEmbeddedType.*Comment on line with exported embedded field`,
|
2015-06-19 12:39:02 +10:00
|
|
|
`Has unexported fields`,
|
|
|
|
|
`func \(ExportedType\) ExportedMethod\(a int\) bool`,
|
|
|
|
|
`const ExportedTypedConstant ExportedType = iota`, // Must include associated constant.
|
2015-06-20 20:28:46 +10:00
|
|
|
`func ExportedTypeConstructor\(\) \*ExportedType`, // Must include constructor.
|
2018-10-10 11:50:49 +11:00
|
|
|
`io.Reader.*Comment on line with embedded Reader`,
|
2015-06-19 12:39:02 +10:00
|
|
|
},
|
|
|
|
|
[]string{
|
2018-10-10 11:50:49 +11:00
|
|
|
`unexportedField`, // No unexported field.
|
|
|
|
|
`int.*embedded`, // No unexported embedded field.
|
|
|
|
|
`Comment about exported method`, // No comment about exported method.
|
|
|
|
|
`unexportedMethod`, // No unexported method.
|
|
|
|
|
`unexportedTypedConstant`, // No unexported constant.
|
|
|
|
|
`error`, // No embedded error.
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
// Type with -src. Will see unexported fields.
|
|
|
|
|
{
|
|
|
|
|
"type",
|
|
|
|
|
[]string{"-src", p, `ExportedType`},
|
|
|
|
|
[]string{
|
|
|
|
|
`Comment about exported type`, // Include comment.
|
|
|
|
|
`type ExportedType struct`, // Type definition.
|
2018-10-18 13:46:54 +11:00
|
|
|
`Comment before exported field`,
|
|
|
|
|
`ExportedField.*Comment on line with exported field`,
|
2018-10-10 11:50:49 +11:00
|
|
|
`ExportedEmbeddedType.*Comment on line with exported embedded field`,
|
|
|
|
|
`unexportedType.*Comment on line with unexported embedded field`,
|
|
|
|
|
`func \(ExportedType\) ExportedMethod\(a int\) bool`,
|
|
|
|
|
`const ExportedTypedConstant ExportedType = iota`, // Must include associated constant.
|
|
|
|
|
`func ExportedTypeConstructor\(\) \*ExportedType`, // Must include constructor.
|
|
|
|
|
`io.Reader.*Comment on line with embedded Reader`,
|
|
|
|
|
},
|
|
|
|
|
[]string{
|
|
|
|
|
`Comment about exported method`, // No comment about exported method.
|
|
|
|
|
`unexportedMethod`, // No unexported method.
|
|
|
|
|
`unexportedTypedConstant`, // No unexported constant.
|
2015-06-19 12:39:02 +10:00
|
|
|
},
|
|
|
|
|
},
|
2018-10-24 13:33:14 +11:00
|
|
|
// Type -all.
|
|
|
|
|
{
|
|
|
|
|
"type",
|
|
|
|
|
[]string{"-all", p, `ExportedType`},
|
|
|
|
|
[]string{
|
|
|
|
|
`type ExportedType struct {`, // Type definition as source.
|
|
|
|
|
`Comment about exported type`, // Include comment afterwards.
|
|
|
|
|
`const ConstGroup4 ExportedType = ExportedType\{\}`, // Related constants.
|
|
|
|
|
`ExportedTypedConstant ExportedType = iota`,
|
|
|
|
|
`Constants tied to ExportedType`,
|
|
|
|
|
`func ExportedTypeConstructor\(\) \*ExportedType`,
|
|
|
|
|
`Comment about constructor for exported type.`,
|
|
|
|
|
`func ReturnExported\(\) ExportedType`,
|
|
|
|
|
`func \(ExportedType\) ExportedMethod\(a int\) bool`,
|
|
|
|
|
`Comment about exported method.`,
|
2019-03-08 11:56:16 +05:30
|
|
|
`func \(ExportedType\) Uncommented\(a int\) bool\n\n`, // Ensure line gap after method with no comment
|
2018-10-24 13:33:14 +11:00
|
|
|
},
|
|
|
|
|
[]string{
|
|
|
|
|
`unexportedType`,
|
|
|
|
|
},
|
|
|
|
|
},
|
2017-01-24 14:53:31 -05:00
|
|
|
// Type T1 dump (alias).
|
|
|
|
|
{
|
|
|
|
|
"type T1",
|
cmd/doc: truncate long lists of arguments
Some field-lists (especially in generated code) can be excessively long.
In the one-line printout, it does not make sense to print all elements
of the list if line-wrapping causes the "one-line" to become multi-line.
// Before:
var LongLine = newLongLine("someArgument1", "someArgument2", "someArgument3", "someArgument4", "someArgument5", "someArgument6", "someArgument7", "someArgument8")
// After:
var LongLine = newLongLine("someArgument1", "someArgument2", "someArgument3", "someArgument4", ...)
Change-Id: I4bbbe2dbd1d7be9f02d63431d213088c3dee332c
Reviewed-on: https://go-review.googlesource.com/36031
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2017-01-11 16:53:49 -08:00
|
|
|
[]string{p + ".T1"},
|
2017-01-24 14:53:31 -05:00
|
|
|
[]string{
|
|
|
|
|
`type T1 = T2`,
|
|
|
|
|
},
|
|
|
|
|
[]string{
|
|
|
|
|
`type T1 T2`,
|
|
|
|
|
`type ExportedType`,
|
|
|
|
|
},
|
|
|
|
|
},
|
2015-06-19 12:39:02 +10:00
|
|
|
// Type -u with unexported fields.
|
|
|
|
|
{
|
|
|
|
|
"type with unexported fields and -u",
|
|
|
|
|
[]string{"-u", p, `ExportedType`},
|
|
|
|
|
[]string{
|
|
|
|
|
`Comment about exported type`, // Include comment.
|
|
|
|
|
`type ExportedType struct`, // Type definition.
|
|
|
|
|
`Comment before exported field.*\n.*ExportedField +int`,
|
2018-10-10 11:50:49 +11:00
|
|
|
`unexportedField.*int.*Comment on line with unexported field`,
|
|
|
|
|
`ExportedEmbeddedType.*Comment on line with exported embedded field`,
|
|
|
|
|
`\*ExportedEmbeddedType.*Comment on line with exported embedded \*field`,
|
|
|
|
|
`\*qualified.ExportedEmbeddedType.*Comment on line with exported embedded \*selector.field`,
|
|
|
|
|
`unexportedType.*Comment on line with unexported embedded field`,
|
|
|
|
|
`\*unexportedType.*Comment on line with unexported embedded \*field`,
|
|
|
|
|
`io.Reader.*Comment on line with embedded Reader`,
|
|
|
|
|
`error.*Comment on line with embedded error`,
|
2015-06-19 12:39:02 +10:00
|
|
|
`func \(ExportedType\) unexportedMethod\(a int\) bool`,
|
|
|
|
|
`unexportedTypedConstant`,
|
|
|
|
|
},
|
|
|
|
|
[]string{
|
|
|
|
|
`Has unexported fields`,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
// Unexported type with -u.
|
|
|
|
|
{
|
|
|
|
|
"unexported type with -u",
|
|
|
|
|
[]string{"-u", p, `unexportedType`},
|
|
|
|
|
[]string{
|
|
|
|
|
`Comment about unexported type`, // Include comment.
|
|
|
|
|
`type unexportedType int`, // Type definition.
|
|
|
|
|
`func \(unexportedType\) ExportedMethod\(\) bool`,
|
|
|
|
|
`func \(unexportedType\) unexportedMethod\(\) bool`,
|
|
|
|
|
`ExportedTypedConstant_unexported unexportedType = iota`,
|
|
|
|
|
`const unexportedTypedConstant unexportedType = 1`,
|
|
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
|
2015-10-23 17:09:39 -07:00
|
|
|
// Interface.
|
|
|
|
|
{
|
2016-10-24 12:38:06 -07:00
|
|
|
"interface type",
|
2015-10-23 17:09:39 -07:00
|
|
|
[]string{p, `ExportedInterface`},
|
|
|
|
|
[]string{
|
|
|
|
|
`Comment about exported interface`, // Include comment.
|
|
|
|
|
`type ExportedInterface interface`, // Interface definition.
|
|
|
|
|
`Comment before exported method.*\n.*ExportedMethod\(\)` +
|
|
|
|
|
`.*Comment on line with exported method`,
|
2018-10-10 11:50:49 +11:00
|
|
|
`io.Reader.*Comment on line with embedded Reader`,
|
|
|
|
|
`error.*Comment on line with embedded error`,
|
2015-10-23 17:09:39 -07:00
|
|
|
`Has unexported methods`,
|
|
|
|
|
},
|
|
|
|
|
[]string{
|
|
|
|
|
`unexportedField`, // No unexported field.
|
|
|
|
|
`Comment about exported method`, // No comment about exported method.
|
|
|
|
|
`unexportedMethod`, // No unexported method.
|
|
|
|
|
`unexportedTypedConstant`, // No unexported constant.
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
// Interface -u with unexported methods.
|
|
|
|
|
{
|
2016-10-24 12:38:06 -07:00
|
|
|
"interface type with unexported methods and -u",
|
2015-10-23 17:09:39 -07:00
|
|
|
[]string{"-u", p, `ExportedInterface`},
|
|
|
|
|
[]string{
|
|
|
|
|
`Comment about exported interface`, // Include comment.
|
|
|
|
|
`type ExportedInterface interface`, // Interface definition.
|
|
|
|
|
`Comment before exported method.*\n.*ExportedMethod\(\)` +
|
|
|
|
|
`.*Comment on line with exported method`,
|
2018-10-10 11:50:49 +11:00
|
|
|
`unexportedMethod\(\).*Comment on line with unexported method`,
|
|
|
|
|
`io.Reader.*Comment on line with embedded Reader`,
|
|
|
|
|
`error.*Comment on line with embedded error`,
|
2015-10-23 17:09:39 -07:00
|
|
|
},
|
|
|
|
|
[]string{
|
|
|
|
|
`Has unexported methods`,
|
|
|
|
|
},
|
|
|
|
|
},
|
2016-10-24 12:38:06 -07:00
|
|
|
|
|
|
|
|
// Interface method.
|
|
|
|
|
{
|
|
|
|
|
"interface method",
|
|
|
|
|
[]string{p, `ExportedInterface.ExportedMethod`},
|
|
|
|
|
[]string{
|
|
|
|
|
`Comment before exported method.*\n.*ExportedMethod\(\)` +
|
|
|
|
|
`.*Comment on line with exported method`,
|
|
|
|
|
},
|
|
|
|
|
[]string{
|
2018-10-10 11:50:49 +11:00
|
|
|
`Comment about exported interface`,
|
2016-10-24 12:38:06 -07:00
|
|
|
},
|
|
|
|
|
},
|
2015-10-23 17:09:39 -07:00
|
|
|
|
2015-06-19 12:39:02 +10:00
|
|
|
// Method.
|
|
|
|
|
{
|
|
|
|
|
"method",
|
|
|
|
|
[]string{p, `ExportedType.ExportedMethod`},
|
|
|
|
|
[]string{
|
|
|
|
|
`func \(ExportedType\) ExportedMethod\(a int\) bool`,
|
2018-10-10 11:50:49 +11:00
|
|
|
`Comment about exported method`,
|
2015-06-19 12:39:02 +10:00
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
// Method with -u.
|
|
|
|
|
{
|
|
|
|
|
"method with -u",
|
|
|
|
|
[]string{"-u", p, `ExportedType.unexportedMethod`},
|
|
|
|
|
[]string{
|
|
|
|
|
`func \(ExportedType\) unexportedMethod\(a int\) bool`,
|
2018-10-10 11:50:49 +11:00
|
|
|
`Comment about unexported method`,
|
|
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
// Method with -src.
|
|
|
|
|
{
|
|
|
|
|
"method with -src",
|
|
|
|
|
[]string{"-src", p, `ExportedType.ExportedMethod`},
|
|
|
|
|
[]string{
|
|
|
|
|
`func \(ExportedType\) ExportedMethod\(a int\) bool`,
|
|
|
|
|
`Comment about exported method`,
|
|
|
|
|
`return true != true`,
|
2015-06-19 12:39:02 +10:00
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
|
2017-03-21 20:27:47 -07:00
|
|
|
// Field.
|
|
|
|
|
{
|
|
|
|
|
"field",
|
|
|
|
|
[]string{p, `ExportedType.ExportedField`},
|
|
|
|
|
[]string{
|
2017-07-06 20:02:26 +00:00
|
|
|
`type ExportedType struct`,
|
2017-03-21 20:27:47 -07:00
|
|
|
`ExportedField int`,
|
2018-10-10 11:50:49 +11:00
|
|
|
`Comment before exported field`,
|
|
|
|
|
`Comment on line with exported field`,
|
2017-07-06 20:02:26 +00:00
|
|
|
`other fields elided`,
|
2017-03-21 20:27:47 -07:00
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
|
2017-07-06 20:02:26 +00:00
|
|
|
// Field with -u.
|
2017-03-21 20:27:47 -07:00
|
|
|
{
|
|
|
|
|
"method with -u",
|
|
|
|
|
[]string{"-u", p, `ExportedType.unexportedField`},
|
|
|
|
|
[]string{
|
|
|
|
|
`unexportedField int`,
|
2018-10-10 11:50:49 +11:00
|
|
|
`Comment on line with unexported field`,
|
2017-03-21 20:27:47 -07:00
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
|
2017-07-06 20:02:26 +00:00
|
|
|
// Field of struct with only one field.
|
|
|
|
|
{
|
|
|
|
|
"single-field struct",
|
|
|
|
|
[]string{p, `ExportedStructOneField.OnlyField`},
|
|
|
|
|
[]string{`the only field`},
|
|
|
|
|
[]string{`other fields elided`},
|
|
|
|
|
},
|
|
|
|
|
|
2015-06-19 12:39:02 +10:00
|
|
|
// Case matching off.
|
|
|
|
|
{
|
|
|
|
|
"case matching off",
|
|
|
|
|
[]string{p, `casematch`},
|
|
|
|
|
[]string{
|
|
|
|
|
`CaseMatch`,
|
|
|
|
|
`Casematch`,
|
|
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Case matching on.
|
|
|
|
|
{
|
|
|
|
|
"case matching on",
|
|
|
|
|
[]string{"-c", p, `Casematch`},
|
|
|
|
|
[]string{
|
|
|
|
|
`Casematch`,
|
|
|
|
|
},
|
|
|
|
|
[]string{
|
|
|
|
|
`CaseMatch`,
|
|
|
|
|
},
|
|
|
|
|
},
|
2017-11-20 14:12:43 +11:00
|
|
|
|
|
|
|
|
// No dups with -u. Issue 21797.
|
|
|
|
|
{
|
|
|
|
|
"case matching on, no dups",
|
|
|
|
|
[]string{"-u", p, `duplicate`},
|
|
|
|
|
[]string{
|
|
|
|
|
`Duplicate`,
|
|
|
|
|
`duplicate`,
|
|
|
|
|
},
|
|
|
|
|
[]string{
|
|
|
|
|
"\\)\n+const", // This will appear if the const decl appears twice.
|
|
|
|
|
},
|
|
|
|
|
},
|
2018-05-23 17:23:35 -04:00
|
|
|
{
|
|
|
|
|
"non-imported: pkg.sym",
|
|
|
|
|
[]string{"nested.Foo"},
|
|
|
|
|
[]string{"Foo struct"},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"non-imported: pkg only",
|
|
|
|
|
[]string{"nested"},
|
|
|
|
|
[]string{"Foo struct"},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"non-imported: pkg sym",
|
|
|
|
|
[]string{"nested", "Foo"},
|
|
|
|
|
[]string{"Foo struct"},
|
|
|
|
|
nil,
|
|
|
|
|
},
|
2015-06-19 12:39:02 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDoc(t *testing.T) {
|
cmd/doc: don't stop after first package if the symbol is not found
The test case is
go doc rand.Float64
The first package it finds is crypto/rand, which does not have a Float64.
Before this change, cmd/doc would stop there even though math/rand
has the symbol. After this change, we get:
% go doc rand.Float64
package rand // import "math/rand"
func Float64() float64
Float64 returns, as a float64, a pseudo-random number in [0.0,1.0) from the
default Source.
%
Another nice consequence is that if a symbol is not found, we might get
a longer list of packages that were examined:
% go doc rand.Int64
doc: no symbol Int64 in packages crypto/rand, math/rand
exit status 1
%
This change introduces a coroutine to scan the file system so that if
the symbol is not found, the coroutine can deliver another path to try.
(This is darned close to the original motivation for coroutines.)
Paths are delivered on an unbuffered channel so the scanner does
not proceed until candidate paths are needed.
The scanner is attached to a new type, called Dirs, that caches the results
so if we need to scan a second time, we don't walk the file system
again. This is significantly more efficient than the existing code, which
could scan the tree multiple times looking for a package with
the symbol.
Change-Id: I2789505b9992cf04c19376c51ae09af3bc305f7f
Reviewed-on: https://go-review.googlesource.com/14921
Reviewed-by: Andrew Gerrand <adg@golang.org>
2015-09-23 16:49:30 -07:00
|
|
|
maybeSkip(t)
|
2015-06-19 12:39:02 +10:00
|
|
|
for _, test := range tests {
|
|
|
|
|
var b bytes.Buffer
|
|
|
|
|
var flagSet flag.FlagSet
|
|
|
|
|
err := do(&b, &flagSet, test.args)
|
|
|
|
|
if err != nil {
|
2018-07-30 14:53:44 -04:00
|
|
|
t.Fatalf("%s %v: %s\n", test.name, test.args, err)
|
2015-06-19 12:39:02 +10:00
|
|
|
}
|
|
|
|
|
output := b.Bytes()
|
|
|
|
|
failed := false
|
|
|
|
|
for j, yes := range test.yes {
|
|
|
|
|
re, err := regexp.Compile(yes)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, yes, err)
|
|
|
|
|
}
|
|
|
|
|
if !re.Match(output) {
|
|
|
|
|
t.Errorf("%s.%d: no match for %s %#q", test.name, j, test.args, yes)
|
|
|
|
|
failed = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for j, no := range test.no {
|
|
|
|
|
re, err := regexp.Compile(no)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, no, err)
|
|
|
|
|
}
|
|
|
|
|
if re.Match(output) {
|
|
|
|
|
t.Errorf("%s.%d: incorrect match for %s %#q", test.name, j, test.args, no)
|
|
|
|
|
failed = true
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-10-17 22:32:27 +11:00
|
|
|
if bytes.Count(output, []byte("TYPES\n")) > 1 {
|
|
|
|
|
t.Fatalf("%s: repeating headers", test.name)
|
|
|
|
|
}
|
2015-06-19 12:39:02 +10:00
|
|
|
if failed {
|
|
|
|
|
t.Logf("\n%s", output)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
cmd/doc: don't stop after first package if the symbol is not found
The test case is
go doc rand.Float64
The first package it finds is crypto/rand, which does not have a Float64.
Before this change, cmd/doc would stop there even though math/rand
has the symbol. After this change, we get:
% go doc rand.Float64
package rand // import "math/rand"
func Float64() float64
Float64 returns, as a float64, a pseudo-random number in [0.0,1.0) from the
default Source.
%
Another nice consequence is that if a symbol is not found, we might get
a longer list of packages that were examined:
% go doc rand.Int64
doc: no symbol Int64 in packages crypto/rand, math/rand
exit status 1
%
This change introduces a coroutine to scan the file system so that if
the symbol is not found, the coroutine can deliver another path to try.
(This is darned close to the original motivation for coroutines.)
Paths are delivered on an unbuffered channel so the scanner does
not proceed until candidate paths are needed.
The scanner is attached to a new type, called Dirs, that caches the results
so if we need to scan a second time, we don't walk the file system
again. This is significantly more efficient than the existing code, which
could scan the tree multiple times looking for a package with
the symbol.
Change-Id: I2789505b9992cf04c19376c51ae09af3bc305f7f
Reviewed-on: https://go-review.googlesource.com/14921
Reviewed-by: Andrew Gerrand <adg@golang.org>
2015-09-23 16:49:30 -07:00
|
|
|
// Test the code to try multiple packages. Our test case is
|
|
|
|
|
// go doc rand.Float64
|
|
|
|
|
// This needs to find math/rand.Float64; however crypto/rand, which doesn't
|
|
|
|
|
// have the symbol, usually appears first in the directory listing.
|
|
|
|
|
func TestMultiplePackages(t *testing.T) {
|
|
|
|
|
if testing.Short() {
|
|
|
|
|
t.Skip("scanning file system takes too long")
|
|
|
|
|
}
|
|
|
|
|
maybeSkip(t)
|
|
|
|
|
var b bytes.Buffer // We don't care about the output.
|
|
|
|
|
// Make sure crypto/rand does not have the symbol.
|
|
|
|
|
{
|
|
|
|
|
var flagSet flag.FlagSet
|
|
|
|
|
err := do(&b, &flagSet, []string{"crypto/rand.float64"})
|
|
|
|
|
if err == nil {
|
|
|
|
|
t.Errorf("expected error from crypto/rand.float64")
|
|
|
|
|
} else if !strings.Contains(err.Error(), "no symbol float64") {
|
|
|
|
|
t.Errorf("unexpected error %q from crypto/rand.float64", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Make sure math/rand does have the symbol.
|
|
|
|
|
{
|
|
|
|
|
var flagSet flag.FlagSet
|
|
|
|
|
err := do(&b, &flagSet, []string{"math/rand.float64"})
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("unexpected error %q from math/rand.float64", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Try the shorthand.
|
|
|
|
|
{
|
|
|
|
|
var flagSet flag.FlagSet
|
|
|
|
|
err := do(&b, &flagSet, []string{"rand.float64"})
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("unexpected error %q from rand.float64", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Now try a missing symbol. We should see both packages in the error.
|
|
|
|
|
{
|
|
|
|
|
var flagSet flag.FlagSet
|
|
|
|
|
err := do(&b, &flagSet, []string{"rand.doesnotexit"})
|
|
|
|
|
if err == nil {
|
|
|
|
|
t.Errorf("expected error from rand.doesnotexit")
|
|
|
|
|
} else {
|
|
|
|
|
errStr := err.Error()
|
|
|
|
|
if !strings.Contains(errStr, "no symbol") {
|
|
|
|
|
t.Errorf("error %q should contain 'no symbol", errStr)
|
|
|
|
|
}
|
|
|
|
|
if !strings.Contains(errStr, "crypto/rand") {
|
|
|
|
|
t.Errorf("error %q should contain crypto/rand", errStr)
|
|
|
|
|
}
|
|
|
|
|
if !strings.Contains(errStr, "math/rand") {
|
|
|
|
|
t.Errorf("error %q should contain math/rand", errStr)
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-06-19 12:39:02 +10:00
|
|
|
}
|
|
|
|
|
}
|
2015-09-28 13:45:57 -07:00
|
|
|
|
2017-08-28 15:33:11 +10:00
|
|
|
// Test the code to look up packages when given two args. First test case is
|
|
|
|
|
// go doc binary BigEndian
|
|
|
|
|
// This needs to find encoding/binary.BigEndian, which means
|
|
|
|
|
// finding the package encoding/binary given only "binary".
|
|
|
|
|
// Second case is
|
|
|
|
|
// go doc rand Float64
|
|
|
|
|
// which again needs to find math/rand and not give up after crypto/rand,
|
|
|
|
|
// which has no such function.
|
|
|
|
|
func TestTwoArgLookup(t *testing.T) {
|
|
|
|
|
if testing.Short() {
|
|
|
|
|
t.Skip("scanning file system takes too long")
|
|
|
|
|
}
|
|
|
|
|
maybeSkip(t)
|
|
|
|
|
var b bytes.Buffer // We don't care about the output.
|
|
|
|
|
{
|
|
|
|
|
var flagSet flag.FlagSet
|
|
|
|
|
err := do(&b, &flagSet, []string{"binary", "BigEndian"})
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("unexpected error %q from binary BigEndian", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
var flagSet flag.FlagSet
|
|
|
|
|
err := do(&b, &flagSet, []string{"rand", "Float64"})
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("unexpected error %q from rand Float64", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
cmd/doc: print a symbol error on "bytes Foo"
In golang.org/cl/59413, the two-argument behavior of cmd/doc was changed
to use findPackage instead of build.Import, meaning that the tool was
more consistent and useful.
However, it introduced a regression:
$ go doc bytes Foo
doc: no such package: bytes
This is because the directory list search would not find Foo in bytes,
and reach the end of the directory list - thus resulting in a "no such
package" error, since no directory matched our first argument.
Move the "no such package" error out of parseArgs, so that the "loop
until something is printed" loop can have control over it. In
particular, it is useful to know when we have reached the end of the
list without any exact match, yet we did find one package matching
"bytes":
$ go doc bytes Foo
doc: no symbol Foo in package bytes
While at it, make the "no such package" error not be fatal so that we
may test for it. It is important to have the test, as parseArgs may now
return a nil package instead of exiting the entire program, potentially
meaning a nil pointer dereference panic.
Fixes #22810.
Change-Id: I90cc6fd755e2d1675bea6d49a1c13cc18ac9bfb9
Reviewed-on: https://go-review.googlesource.com/78677
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2017-11-19 17:28:46 +00:00
|
|
|
{
|
|
|
|
|
var flagSet flag.FlagSet
|
|
|
|
|
err := do(&b, &flagSet, []string{"bytes", "Foo"})
|
|
|
|
|
if err == nil {
|
|
|
|
|
t.Errorf("expected error from bytes Foo")
|
|
|
|
|
} else if !strings.Contains(err.Error(), "no symbol Foo") {
|
|
|
|
|
t.Errorf("unexpected error %q from bytes Foo", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
var flagSet flag.FlagSet
|
|
|
|
|
err := do(&b, &flagSet, []string{"nosuchpackage", "Foo"})
|
|
|
|
|
if err == nil {
|
|
|
|
|
// actually present in the user's filesystem
|
|
|
|
|
} else if !strings.Contains(err.Error(), "no such package") {
|
|
|
|
|
t.Errorf("unexpected error %q from nosuchpackage Foo", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-08-28 15:33:11 +10:00
|
|
|
}
|
|
|
|
|
|
2018-03-05 16:21:44 +11:00
|
|
|
// Test the code to look up packages when the first argument starts with "./".
|
|
|
|
|
// Our test case is in effect "cd src/text; doc ./template". This should get
|
|
|
|
|
// text/template but before Issue 23383 was fixed would give html/template.
|
|
|
|
|
func TestDotSlashLookup(t *testing.T) {
|
|
|
|
|
if testing.Short() {
|
|
|
|
|
t.Skip("scanning file system takes too long")
|
|
|
|
|
}
|
|
|
|
|
maybeSkip(t)
|
|
|
|
|
where := pwd()
|
|
|
|
|
defer func() {
|
|
|
|
|
if err := os.Chdir(where); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
}()
|
2018-03-21 12:36:58 +00:00
|
|
|
if err := os.Chdir(filepath.Join(buildCtx.GOROOT, "src", "text")); err != nil {
|
2018-03-05 16:21:44 +11:00
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
var b bytes.Buffer
|
|
|
|
|
var flagSet flag.FlagSet
|
|
|
|
|
err := do(&b, &flagSet, []string{"./template"})
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("unexpected error %q from ./template", err)
|
|
|
|
|
}
|
|
|
|
|
// The output should contain information about the text/template package.
|
|
|
|
|
const want = `package template // import "text/template"`
|
|
|
|
|
output := b.String()
|
|
|
|
|
if !strings.HasPrefix(output, want) {
|
|
|
|
|
t.Fatalf("wrong package: %.*q...", len(want), output)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-28 13:45:57 -07:00
|
|
|
type trimTest struct {
|
|
|
|
|
path string
|
|
|
|
|
prefix string
|
|
|
|
|
result string
|
|
|
|
|
ok bool
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var trimTests = []trimTest{
|
|
|
|
|
{"", "", "", true},
|
|
|
|
|
{"/usr/gopher", "/usr/gopher", "/usr/gopher", true},
|
|
|
|
|
{"/usr/gopher/bar", "/usr/gopher", "bar", true},
|
|
|
|
|
{"/usr/gopherflakes", "/usr/gopher", "/usr/gopherflakes", false},
|
|
|
|
|
{"/usr/gopher/bar", "/usr/zot", "/usr/gopher/bar", false},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestTrim(t *testing.T) {
|
|
|
|
|
for _, test := range trimTests {
|
|
|
|
|
result, ok := trim(test.path, test.prefix)
|
|
|
|
|
if ok != test.ok {
|
|
|
|
|
t.Errorf("%s %s expected %t got %t", test.path, test.prefix, test.ok, ok)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if result != test.result {
|
|
|
|
|
t.Errorf("%s %s expected %q got %q", test.path, test.prefix, test.result, result)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|