src/goTest: do not set range for dynamic subtests

By default, no longer sets the range property of dynamically discovered
subtests. As a result, 'Go to Test' for a dynamic subtest will open
relevant file but will not scroll to the function; and no play button
will appear in the gutter for the subtest. Adds a setting to revert to
the previous behavior.

Since the previous behavior was to copy the range from the parent test,
all such subtests would have the exact same range as the parent test,
and thus the gutter play button would attempt to run the parent test and
all of its subtests, requiring the user to right click the play button
and manually select the parent test to avoid this.

Change-Id: I7b95995206045b215a60d34afc00cbb6ad36ccd0
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/345869
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
Trust: Hyang-Ah Hana Kim <hyangah@gmail.com>
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com>
TryBot-Result: kokoro <noreply+kokoro@google.com>
diff --git a/docs/settings.md b/docs/settings.md
index bd599c8..ee4a83a 100644
--- a/docs/settings.md
+++ b/docs/settings.md
@@ -409,6 +409,11 @@
 Include benchmarks when running all tests in a group.
 
 Default: `false`
+### `go.testExplorerSetDynamicSubtestRange`
+
+If true, the source location of dynamically discovered subtests will be set to the source location of the containing function
+
+Default: `false`
 ### `go.testFlags`
 
 Flags to pass to `go test`. If null, then buildFlags will be used. This is not propagated to the language server.
diff --git a/package.json b/package.json
index e37f952..f8c49cc 100644
--- a/package.json
+++ b/package.json
@@ -1312,6 +1312,12 @@
           "description": "If true, test log messages associated with a given location will be shown as a single message.",
           "scope": "resource"
         },
+        "go.testExplorerSetDynamicSubtestRange": {
+          "type": "boolean",
+          "default": false,
+          "description": "If true, the source location of dynamically discovered subtests will be set to the source location of the containing function",
+          "scope": "resource"
+        },
         "go.generateTestsFlags": {
           "type": "array",
           "items": {
diff --git a/src/goTest/resolve.ts b/src/goTest/resolve.ts
index 376e796..9cc393a 100644
--- a/src/goTest/resolve.ts
+++ b/src/goTest/resolve.ts
@@ -151,8 +151,14 @@
 		item.canResolveChildren = true;
 		const sub = this.createItem(name, item.uri, kind, `${parentName}/${name}`);
 		item.children.add(sub);
-		sub.range = item.range;
-		if (dynamic) this.isDynamicSubtest.add(item);
+
+		if (dynamic) {
+			this.isDynamicSubtest.add(sub);
+			if (this.shouldSetRange(item)) {
+				sub.range = item.range;
+			}
+		}
+
 		return sub;
 	}
 
@@ -192,6 +198,11 @@
 
 	/* ***** Private ***** */
 
+	private shouldSetRange(item: TestItem): boolean {
+		const config = getGoConfig(item.uri);
+		return config.get<boolean>('testExplorerSetDynamicSubtestRange');
+	}
+
 	// Create an item.
 	private createItem(label: string, uri: Uri, kind: GoTestKind, name?: string): TestItem {
 		return this.ctrl.createTestItem(GoTest.id(uri, kind, name), label, uri.with({ query: '', fragment: '' }));
@@ -222,6 +233,9 @@
 	// location.
 	private relocateChildren(item: TestItem) {
 		item.children.forEach((child) => {
+			if (!this.isDynamicSubtest.has(child)) return;
+			if (!this.shouldSetRange(child)) return;
+
 			child.range = item.range;
 			this.relocateChildren(child);
 		});