[release-branch.go1.14] go/doc: fix detection of whole file examples

After CL 211357 (commit 499dc1c),
hasTests and numDecl were not updated properly for function
declarations with parameters, which affected the whole file
example detection logic. This caused examples like

	package foo_test

	func Foo(x int) {
	}

	func Example() {
		fmt.Println("Hello, world!")
		// Output: Hello, world!
	}

to not be detected as whole file ones.

Fixes #38418.
For #38409.

Change-Id: I9ebd47e52d7ee9d91eb6f8e0257511de69b2a402
GitHub-Last-Rev: cc71c31124f6e3514f4e33ac7b169eca74c8bcb7
GitHub-Pull-Request: golang/go#37730
Reviewed-on: https://go-review.googlesource.com/c/go/+/222477
Reviewed-by: Agniva De Sarker <agniva.quicksilver@gmail.com>
Reviewed-by: Robert Griesemer <gri@golang.org>
Run-TryBot: Agniva De Sarker <agniva.quicksilver@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
(cherry picked from commit c4961dc247ca39c251a5a3c80ebfe59609b4e669)
Reviewed-on: https://go-review.googlesource.com/c/go/+/232868
Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Gregory Petrosyan <gregory.petrosyan@gmail.com>
diff --git a/src/go/doc/example.go b/src/go/doc/example.go
index a010d3a..ebf8118 100644
--- a/src/go/doc/example.go
+++ b/src/go/doc/example.go
@@ -62,9 +62,6 @@
 			if !ok || f.Recv != nil {
 				continue
 			}
-			if params := f.Type.Params; len(params.List) != 0 {
-				continue // function has params; not a valid example
-			}
 			numDecl++
 			name := f.Name.Name
 			if isTest(name, "Test") || isTest(name, "Benchmark") {
@@ -74,6 +71,9 @@
 			if !isTest(name, "Example") {
 				continue
 			}
+			if params := f.Type.Params; len(params.List) != 0 {
+				continue // function has params; not a valid example
+			}
 			if f.Body == nil { // ast.File.Body nil dereference (see issue 28044)
 				continue
 			}
diff --git a/src/go/doc/example_test.go b/src/go/doc/example_test.go
index cd2f469..32db3cd 100644
--- a/src/go/doc/example_test.go
+++ b/src/go/doc/example_test.go
@@ -331,25 +331,65 @@
 }
 `
 
+const exampleWholeFileFunction = `package foo_test
+
+func Foo(x int) {
+}
+
+func Example() {
+	fmt.Println("Hello, world!")
+	// Output: Hello, world!
+}
+`
+
+const exampleWholeFileFunctionOutput = `package main
+
+func Foo(x int) {
+}
+
+func main() {
+	fmt.Println("Hello, world!")
+}
+`
+
+var exampleWholeFileTestCases = []struct {
+	Title, Source, Play, Output string
+}{
+	{
+		"Methods",
+		exampleWholeFile,
+		exampleWholeFileOutput,
+		"Hello, world!\n",
+	},
+	{
+		"Function",
+		exampleWholeFileFunction,
+		exampleWholeFileFunctionOutput,
+		"Hello, world!\n",
+	},
+}
+
 func TestExamplesWholeFile(t *testing.T) {
-	fset := token.NewFileSet()
-	file, err := parser.ParseFile(fset, "test.go", strings.NewReader(exampleWholeFile), parser.ParseComments)
-	if err != nil {
-		t.Fatal(err)
-	}
-	es := doc.Examples(file)
-	if len(es) != 1 {
-		t.Fatalf("wrong number of examples; got %d want 1", len(es))
-	}
-	e := es[0]
-	if e.Name != "" {
-		t.Errorf("got Name == %q, want %q", e.Name, "")
-	}
-	if g, w := formatFile(t, fset, e.Play), exampleWholeFileOutput; g != w {
-		t.Errorf("got Play == %q, want %q", g, w)
-	}
-	if g, w := e.Output, "Hello, world!\n"; g != w {
-		t.Errorf("got Output == %q, want %q", g, w)
+	for _, c := range exampleWholeFileTestCases {
+		fset := token.NewFileSet()
+		file, err := parser.ParseFile(fset, "test.go", strings.NewReader(c.Source), parser.ParseComments)
+		if err != nil {
+			t.Fatal(err)
+		}
+		es := doc.Examples(file)
+		if len(es) != 1 {
+			t.Fatalf("%s: wrong number of examples; got %d want 1", c.Title, len(es))
+		}
+		e := es[0]
+		if e.Name != "" {
+			t.Errorf("%s: got Name == %q, want %q", c.Title, e.Name, "")
+		}
+		if g, w := formatFile(t, fset, e.Play), c.Play; g != w {
+			t.Errorf("%s: got Play == %q, want %q", c.Title, g, w)
+		}
+		if g, w := e.Output, c.Output; g != w {
+			t.Errorf("%s: got Output == %q, want %q", c.Title, g, w)
+		}
 	}
 }