Skip to content

Commit 1e8aaf3

Browse files
committed
cmd/go/internal/doc: reject meta packages in go doc
Meta-package names such as std, cmd, tool, work, and all are package patterns that expand to multiple packages, not single documentable packages. Today go doc std can fall through package resolution and print documentation for an unrelated first match such as archive/tar. Reject these names when they are the first argument to go doc, including the two-argument form such as go doc std Foo. Keep go doc -http std routing to the standard library page. Fixes #53446 Change-Id: Iaf76b2be6fec0efa6f601b7959f4bcaac7ab776d
1 parent 9e0467b commit 1e8aaf3

3 files changed

Lines changed: 47 additions & 0 deletions

File tree

src/cmd/go/internal/doc/doc.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,12 +233,18 @@ func do(ctx context.Context, writer io.Writer, flagSet *flag.FlagSet, args []str
233233
// Outside a module or workspace, go to the documentation for the standard library.
234234
return doPkgsite(ctx, "std", "")
235235
}
236+
if args := flagSet.Args(); len(args) == 1 && args[0] == "std" {
237+
return doPkgsite(ctx, "std", "")
238+
}
236239

237240
// If args are provided, we need to figure out which page to open on the pkgsite
238241
// instance. Run the logic below to determine a match for a symbol, method,
239242
// or field, but don't actually print the documentation to the output.
240243
writer = io.Discard
241244
}
245+
if a := flagSet.Args(); len(a) > 0 && search.IsMetaPackage(a[0]) {
246+
return fmt.Errorf("no such package: %s", a[0])
247+
}
242248
var paths []string
243249
var symbol, method string
244250
// Loop until something is printed.

src/cmd/go/internal/doc/doc_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,6 +1239,31 @@ func TestNoPackageClauseWhenNoMatch(t *testing.T) {
12391239
}
12401240
}
12411241

1242+
func TestMetaPackage(t *testing.T) {
1243+
maybeSkip(t)
1244+
for _, args := range [][]string{
1245+
{"std"},
1246+
{"cmd"},
1247+
{"all"},
1248+
{"tool"},
1249+
{"work"},
1250+
{"std", "Foo"},
1251+
} {
1252+
var b strings.Builder
1253+
var flagSet flag.FlagSet
1254+
err := do(t.Context(), &b, &flagSet, args)
1255+
if err == nil {
1256+
t.Fatalf("expected error for go doc %s; got output:\n%s", strings.Join(args, " "), b.String())
1257+
}
1258+
if want := "no such package: " + args[0]; !strings.Contains(err.Error(), want) {
1259+
t.Fatalf("unexpected error for go doc %s: %v", strings.Join(args, " "), err)
1260+
}
1261+
if strings.Contains(b.String(), `package tar // import "archive/tar"`) {
1262+
t.Fatalf("go doc %s resolved to archive/tar:\n%s", strings.Join(args, " "), b.String())
1263+
}
1264+
}
1265+
}
1266+
12421267
type trimTest struct {
12431268
path string
12441269
prefix string

src/cmd/go/testdata/script/doc.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,22 @@ stdout .
6060
go doc Method
6161
stdout .
6262

63+
# Meta packages are package patterns, not documentable packages.
64+
# Regression test for golang.org/issue/53446.
65+
! go doc std
66+
stderr '^doc: no such package: std$'
67+
! stdout 'package tar // import "archive/tar"'
68+
69+
! go doc all
70+
stderr '^doc: no such package: all$'
71+
72+
! go doc std Foo
73+
stderr '^doc: no such package: std$'
74+
75+
env TEST_GODOC_URL_FILE=$WORK/url.txt
76+
go doc -http std
77+
grep '/std' $TEST_GODOC_URL_FILE
78+
6379
-- go.mod --
6480
module p/v2
6581

0 commit comments

Comments
 (0)