internal/godoc: remember and check GOOS/GOARCH

Package records the GOOS/GOARCH combination it was created with;
Render checks it.

Someday we'll allow multiple combos, but it requires a bit of
refactoring in internal/fetch, and could conceivably cause us to fail
on packages that we now succeed on (by parsing a file from a build
context that we don't currently get to). So we'll leave it for later.
See golang/go#37232.

Change-Id: I3d5e608fefebf4a9e825d1f8f8a5d1166b7e573b
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/258737
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Julie Qiu <julie@golang.org>
diff --git a/internal/fetch/load.go b/internal/fetch/load.go
index 2818e61..d210bb8 100644
--- a/internal/fetch/load.go
+++ b/internal/fetch/load.go
@@ -107,7 +107,7 @@
 	if err != nil {
 		return nil, err
 	}
-	docPkg := godoc.NewPackage(fset, modInfo.ModulePackages)
+	docPkg := godoc.NewPackage(fset, goos, goarch, modInfo.ModulePackages)
 	for _, pf := range goFiles {
 		var removeNodes bool
 		if experiment.IsActive(ctx, internal.ExperimentRemoveUnusedAST) {
diff --git a/internal/godoc/encode_test.go b/internal/godoc/encode_test.go
index 5e10c60..28a1b64 100644
--- a/internal/godoc/encode_test.go
+++ b/internal/godoc/encode_test.go
@@ -63,7 +63,7 @@
 	}
 	compareObjs(f)
 
-	p := NewPackage(fset, nil)
+	p := NewPackage(fset, "linux", "amd64", nil)
 	p.AddFile(f, false)
 	data, err := p.Encode()
 	if err != nil {
@@ -82,7 +82,7 @@
 	if err != nil {
 		return nil, err
 	}
-	p := NewPackage(fset, nil)
+	p := NewPackage(fset, "linux", "amd64", nil)
 	for _, pkg := range pkgs {
 		for _, f := range pkg.Files {
 			p.AddFile(f, removeNodes)
diff --git a/internal/godoc/godoc.go b/internal/godoc/godoc.go
index fac3e4d..9faea12 100644
--- a/internal/godoc/godoc.go
+++ b/internal/godoc/godoc.go
@@ -17,7 +17,7 @@
 
 type ModuleInfo = dochtml.ModuleInfo
 
-// A package contains everything needed to render Go documentation for a package.
+// A Package contains package-level information needed to render Go documentation.
 type Package struct {
 	Fset *token.FileSet
 	gobPackage
@@ -25,6 +25,7 @@
 }
 
 type gobPackage struct { // fields that can be directly gob-encoded
+	GOOS, GOARCH       string
 	Files              []*File
 	ModulePackagePaths map[string]bool
 }
@@ -36,10 +37,12 @@
 }
 
 // NewPackage returns a new Package with the given fset and set of module package paths.
-func NewPackage(fset *token.FileSet, modPaths map[string]bool) *Package {
+func NewPackage(fset *token.FileSet, goos, goarch string, modPaths map[string]bool) *Package {
 	return &Package{
 		Fset: fset,
 		gobPackage: gobPackage{
+			GOOS:               goos,
+			GOARCH:             goarch,
 			ModulePackagePaths: modPaths,
 		},
 	}
diff --git a/internal/godoc/render.go b/internal/godoc/render.go
index b223d30..75f59c6 100644
--- a/internal/godoc/render.go
+++ b/internal/godoc/render.go
@@ -35,6 +35,8 @@
 // It is a variable for testing.
 var MaxDocumentationHTML = 20 * megabyte
 
+var noDocTemplate = template.Must(template.New("").Parse(`<p>No documentation for GOOS/GOARCH {{.}}</p>`))
+
 // Render renders the documentation for the package.
 // Rendering destroys p's AST; do not call any methods of p after it returns.
 func (p *Package) Render(ctx context.Context, innerPath string, sourceInfo *source.Info, modInfo *ModuleInfo, goos, goarch string) (synopsis string, imports []string, html safehtml.HTML, err error) {
@@ -43,6 +45,14 @@
 
 	p.renderCalled = true
 
+	// Empty goos/goarch means we don't care.
+	if (goos != "" && goos != p.GOOS) || (goarch != "" && goarch != p.GOARCH) {
+		html, err := noDocTemplate.ExecuteToHTML(goos + "/" + goarch)
+		if err != nil {
+			return "", nil, safehtml.HTML{}, err
+		}
+		return "No documentation.", nil, html, errors.New("no doc")
+	}
 	importPath := path.Join(modInfo.ModulePath, innerPath)
 	if modInfo.ModulePath == stdlib.ModulePath {
 		importPath = innerPath
diff --git a/internal/godoc/render_test.go b/internal/godoc/render_test.go
index fd59b4c..6f30eb1 100644
--- a/internal/godoc/render_test.go
+++ b/internal/godoc/render_test.go
@@ -30,7 +30,7 @@
 	if err != nil {
 		t.Fatal(err)
 	}
-	wantSyn, wantImports, wantDoc, err := p.Render(ctx, "p", si, mi, "GOOS", "GOARCH")
+	wantSyn, wantImports, wantDoc, err := p.Render(ctx, "p", si, mi, "", "")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -40,7 +40,7 @@
 
 	check := func(p *Package) {
 		t.Helper()
-		gotSyn, gotImports, gotDoc, err := p.Render(ctx, "p", si, mi, "GOOS", "GOARCH")
+		gotSyn, gotImports, gotDoc, err := p.Render(ctx, "p", si, mi, "", "")
 		if err != nil {
 			t.Fatal(err)
 		}