go/analysis/passes/modernize: embedlit - skip multi assigns and decls

The embedlit modernizer introduces a syntax error when
attempting to combine an embedded field assignment
into its initialization if the initialization is
a multi-assignment or multi-declaration. This is because
the edits produced assume that there is only one
comp lit initialization:

	t1, t2 := T1{...}, T2{...}
	t1.x = v

	=>

	t1, t2 := T1{, T2{}, x: v}

For now, don't modernize when we encounter a multi-assign
or multi-decl, but leave a TODO because we could handle
this case by changing the way we calculate the edits.

(Found this bug while running the embedlit modernizer
in the ecosystem metrics pipeline, which we recently
updated to use the Go1.27rc1)

Change-Id: I78135f02f88746d76561ba14d639878b3a05a312
Reviewed-on: https://go-review.googlesource.com/c/tools/+/798880
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
diff --git a/go/analysis/passes/modernize/embedlit.go b/go/analysis/passes/modernize/embedlit.go
index d2c71b5..f8b6dfc 100644
--- a/go/analysis/passes/modernize/embedlit.go
+++ b/go/analysis/passes/modernize/embedlit.go
@@ -209,15 +209,25 @@
 	case edge.AssignStmt_Rhs:
 		assign := curLit.Parent().Node().(*ast.AssignStmt)
 		// TODO(mkalil): Handle lhs forms that aren't idents, i.e. x.y[i] = T{...}.
-		if id, ok := assign.Lhs[curLit.ParentEdgeIndex()].(*ast.Ident); ok {
+		// TODO(mkalil): Handle multi-assignments like t1, t2 := A{}, B{}
+		if len(assign.Lhs) != 1 {
+			return nil
+		}
+		if id, ok := assign.Lhs[0].(*ast.Ident); ok {
 			lhs = id
 			curStmt = curLit.Parent()
 		}
 	case edge.ValueSpec_Values:
 		spec := curLit.Parent().Node().(*ast.ValueSpec)
-		lhs = spec.Names[curLit.ParentEdgeIndex()]
+		// TODO(mkalil): Handle multi-declarations like var (x = A{}; y = B{}) or var x, y = ...
+		if len(spec.Names) != 1 {
+			return nil
+		}
+		lhs = spec.Names[0]
 		if decl, ok := moreiters.First(curLit.Enclosing((*ast.DeclStmt)(nil))); ok {
-			curStmt = decl
+			if gdecl, ok := decl.Node().(*ast.DeclStmt).Decl.(*ast.GenDecl); ok && len(gdecl.Specs) == 1 {
+				curStmt = decl
+			}
 		}
 	default:
 		return nil
diff --git a/go/analysis/passes/modernize/testdata/src/embedlit/embedlit_go127.go b/go/analysis/passes/modernize/testdata/src/embedlit/embedlit_go127.go
index 39300a1..19a47ee 100644
--- a/go/analysis/passes/modernize/testdata/src/embedlit/embedlit_go127.go
+++ b/go/analysis/passes/modernize/testdata/src/embedlit/embedlit_go127.go
@@ -207,6 +207,21 @@
 		a: 1, // comment, with a comma
 	}
 	t16.b = 2
+
+	assgn1, assgn2 := A{}, A{} // nope, multi-assign
+	assgn1.e = 1
+	assgn2.e = 1
+
+	var (
+		v        = A{} // nope, multi-declaration
+		othervar = 2
+	)
+	v.e = 1
+	_ = othervar
+
+	var v1, v2 = A{}, A{} // nope, multi-declaration
+	v2.e = 1
+	_ = v1
 }
 
 func foo() int {
diff --git a/go/analysis/passes/modernize/testdata/src/embedlit/embedlit_go127.go.golden b/go/analysis/passes/modernize/testdata/src/embedlit/embedlit_go127.go.golden
index 69fe4ab..6d8e437 100644
--- a/go/analysis/passes/modernize/testdata/src/embedlit/embedlit_go127.go.golden
+++ b/go/analysis/passes/modernize/testdata/src/embedlit/embedlit_go127.go.golden
@@ -185,7 +185,7 @@
 		a: 1,
 		b: foo() +
 			1}
-	
+
 	t15 := A{a: 1} // nope: += in field assignment
 	t15.b += 2
 
@@ -193,6 +193,21 @@
 		a: 1, // comment, with a comma
 
 		b: 2}
+
+	assgn1, assgn2 := A{}, A{} // nope, multi-assign
+	assgn1.e = 1
+	assgn2.e = 1
+
+	var (
+		v        = A{} // nope, multi-declaration
+		othervar = 2
+	)
+	v.e = 1
+	_ = othervar
+
+	var v1, v2 = A{}, A{} // nope, multi-declaration
+	v2.e = 1
+	_ = v1
 }
 
 func foo() int {