modfile: replace empty comments when adding indirect

When we add an "indirect" token to a line with an empty comment (only
whitespace after //), we should replace the comment text.

In CL 208273, we inserted "indirect;". The isIndirect predicate returns
false for "// indirect;" because there's only one word. When
modload.WriteGoMod is called multiple times (as it is in
'go mod tidy'), this caused us to write "// indirect; indirect".

Updates golang/go#35737

Change-Id: Ic2531a61ab15df7a0d4462ea3b1d25753d06d1d1
Reviewed-on: https://go-review.googlesource.com/c/mod/+/208671
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
diff --git a/modfile/rule.go b/modfile/rule.go
index 256ef60..62af068 100644
--- a/modfile/rule.go
+++ b/modfile/rule.go
@@ -313,8 +313,8 @@
 	if len(line.Suffix) == 0 {
 		return false
 	}
-	f := strings.Fields(line.Suffix[0].Token)
-	return (len(f) == 2 && f[1] == "indirect" || len(f) > 2 && f[1] == "indirect;") && f[0] == "//"
+	f := strings.Fields(strings.TrimPrefix(line.Suffix[0].Token, string(slashSlash)))
+	return (len(f) == 1 && f[0] == "indirect" || len(f) > 1 && f[0] == "indirect;")
 }
 
 // setIndirect sets line to have (or not have) a "// indirect" comment.
@@ -329,13 +329,17 @@
 			line.Suffix = []Comment{{Token: "// indirect", Suffix: true}}
 			return
 		}
-		// Insert at beginning of existing comment.
+
 		com := &line.Suffix[0]
-		space := " "
-		if len(com.Token) > 2 && (com.Token[2] == ' ' || com.Token[2] == '\t') {
-			space = ""
+		text := strings.TrimSpace(strings.TrimPrefix(com.Token, string(slashSlash)))
+		if text == "" {
+			// Empty comment.
+			com.Token = "// indirect"
+			return
 		}
-		com.Token = "// indirect;" + space + com.Token[2:]
+
+		// Insert at beginning of existing comment.
+		com.Token = "// indirect; " + text
 		return
 	}
 
diff --git a/modfile/rule_test.go b/modfile/rule_test.go
index 282d290..c2c28f9 100644
--- a/modfile/rule_test.go
+++ b/modfile/rule_test.go
@@ -99,9 +99,13 @@
 	{
 		`module m
 		require (
-			x.y/b v1.2.3 //
 			x.y/a v1.2.3
-			x.y/d v1.2.3
+			x.y/b v1.2.3 //
+			x.y/c v1.2.3 //c
+			x.y/d v1.2.3 //   c
+			x.y/e v1.2.3 // indirect
+			x.y/f v1.2.3 //indirect
+			x.y/g v1.2.3 //	indirect
 		)
 		`,
 		[]struct {
@@ -109,15 +113,23 @@
 			vers     string
 			indirect bool
 		}{
-			{"x.y/a", "v1.2.3", false},
+			{"x.y/a", "v1.2.3", true},
 			{"x.y/b", "v1.2.3", true},
-			{"x.y/c", "v1.2.3", false},
+			{"x.y/c", "v1.2.3", true},
+			{"x.y/d", "v1.2.3", true},
+			{"x.y/e", "v1.2.3", true},
+			{"x.y/f", "v1.2.3", true},
+			{"x.y/g", "v1.2.3", true},
 		},
 		`module m
 		require (
-			x.y/a v1.2.3
-			x.y/b v1.2.3 // indirect;
-			x.y/c v1.2.3
+			x.y/a v1.2.3 // indirect
+			x.y/b v1.2.3 // indirect
+			x.y/c v1.2.3 // indirect; c
+			x.y/d v1.2.3 // indirect; c
+			x.y/e v1.2.3 // indirect
+			x.y/f v1.2.3 //indirect
+			x.y/g v1.2.3 //	indirect
 		)
 		`,
 	},