Modify ConvertWithBp2build mutator to convert gensrcs to Bazel rule

Test: b build --platforms=//build/bazel/platforms:linux_x86
//art/runtime:art_operator_src

Change-Id: I942d68e17968327cc77f379edce9b73416e6c4fd
diff --git a/bp2build/gensrcs_conversion_test.go b/bp2build/gensrcs_conversion_test.go
new file mode 100644
index 0000000..ebe60bf
--- /dev/null
+++ b/bp2build/gensrcs_conversion_test.go
@@ -0,0 +1,80 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package bp2build
+
+import (
+	"android/soong/android"
+	"android/soong/genrule"
+	"testing"
+)
+
+func TestGensrcs(t *testing.T) {
+	testcases := []struct {
+		name               string
+		bp                 string
+		expectedBazelAttrs attrNameToString
+	}{
+		{
+			name: "gensrcs with common usage of properties",
+			bp: `
+			gensrcs {
+                name: "foo",
+                srcs: ["test/input.txt", ":external_files"],
+                tool_files: ["program.py"],
+                cmd: "$(location program.py) $(in) $(out)",
+                output_extension: "out",
+                bazel_module: { bp2build_available: true },
+			}`,
+			expectedBazelAttrs: attrNameToString{
+				"srcs": `[
+        "test/input.txt",
+        ":external_files__BP2BUILD__MISSING__DEP",
+    ]`,
+				"tools":            `["program.py"]`,
+				"output_extension": `"out"`,
+				"cmd":              `"$(location program.py) $(SRC) $(OUT)"`,
+			},
+		},
+		{
+			name: "gensrcs with out_extension unset",
+			bp: `
+			gensrcs {
+                name: "foo",
+                srcs: ["input.txt"],
+                cmd: "cat $(in) > $(out)",
+                bazel_module: { bp2build_available: true },
+			}`,
+			expectedBazelAttrs: attrNameToString{
+				"srcs": `["input.txt"]`,
+				"cmd":  `"cat $(SRC) > $(OUT)"`,
+			},
+		},
+	}
+
+	for _, test := range testcases {
+		expectedBazelTargets := []string{
+			makeBazelTarget("gensrcs", "foo", test.expectedBazelAttrs),
+		}
+		t.Run(test.name, func(t *testing.T) {
+			runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+				bp2buildTestCase{
+					moduleTypeUnderTest:        "gensrcs",
+					moduleTypeUnderTestFactory: genrule.GenSrcsFactory,
+					blueprint:                  test.bp,
+					expectedBazelTargets:       expectedBazelTargets,
+				})
+		})
+	}
+}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 8649b15..818e1bc 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -805,6 +805,7 @@
 func GenSrcsFactory() android.Module {
 	m := NewGenSrcs()
 	android.InitAndroidModule(m)
+	android.InitBazelModule(m)
 	return m
 }
 
@@ -816,6 +817,13 @@
 	Shard_size *int64
 }
 
+type bazelGensrcsAttributes struct {
+	Srcs             bazel.LabelListAttribute
+	Output_extension *string
+	Tools            bazel.LabelListAttribute
+	Cmd              string
+}
+
 const defaultShardSize = 50
 
 func NewGenRule() *Module {
@@ -880,8 +888,14 @@
 	// Replace in and out variables with $< and $@
 	var cmd string
 	if m.properties.Cmd != nil {
-		cmd = strings.Replace(*m.properties.Cmd, "$(in)", "$(SRCS)", -1)
-		cmd = strings.Replace(cmd, "$(out)", "$(OUTS)", -1)
+		if ctx.ModuleType() == "gensrcs" {
+			cmd = strings.ReplaceAll(*m.properties.Cmd, "$(in)", "$(SRC)")
+			cmd = strings.ReplaceAll(cmd, "$(out)", "$(OUT)")
+		} else {
+			cmd = strings.Replace(*m.properties.Cmd, "$(in)", "$(SRCS)", -1)
+			cmd = strings.Replace(cmd, "$(out)", "$(OUTS)", -1)
+		}
+
 		genDir := "$(GENDIR)"
 		if t := ctx.ModuleType(); t == "cc_genrule" || t == "java_genrule" || t == "java_genrule_host" {
 			genDir = "$(RULEDIR)"
@@ -901,30 +915,50 @@
 		}
 	}
 
-	// The Out prop is not in an immediately accessible field
-	// in the Module struct, so use GetProperties and cast it
-	// to the known struct prop.
-	var outs []string
-	for _, propIntf := range m.GetProperties() {
-		if props, ok := propIntf.(*genRuleProperties); ok {
-			outs = props.Out
-			break
+	if ctx.ModuleType() == "gensrcs" {
+		// The Output_extension prop is not in an immediately accessible field
+		// in the Module struct, so use GetProperties and cast it
+		// to the known struct prop.
+		var outputExtension *string
+		for _, propIntf := range m.GetProperties() {
+			if props, ok := propIntf.(*genSrcsProperties); ok {
+				outputExtension = props.Output_extension
+				break
+			}
 		}
+		props := bazel.BazelTargetModuleProperties{
+			Rule_class:        "gensrcs",
+			Bzl_load_location: "//build/bazel/rules:gensrcs.bzl",
+		}
+		attrs := &bazelGensrcsAttributes{
+			Srcs:             srcs,
+			Output_extension: outputExtension,
+			Cmd:              cmd,
+			Tools:            tools,
+		}
+		ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
+	} else {
+		// The Out prop is not in an immediately accessible field
+		// in the Module struct, so use GetProperties and cast it
+		// to the known struct prop.
+		var outs []string
+		for _, propIntf := range m.GetProperties() {
+			if props, ok := propIntf.(*genRuleProperties); ok {
+				outs = props.Out
+				break
+			}
+		}
+		attrs := &bazelGenruleAttributes{
+			Srcs:  srcs,
+			Outs:  outs,
+			Cmd:   cmd,
+			Tools: tools,
+		}
+		props := bazel.BazelTargetModuleProperties{
+			Rule_class: "genrule",
+		}
+		ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
 	}
-
-	attrs := &bazelGenruleAttributes{
-		Srcs:  srcs,
-		Outs:  outs,
-		Cmd:   cmd,
-		Tools: tools,
-	}
-
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class: "genrule",
-	}
-
-	// Create the BazelTargetModule.
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
 }
 
 var Bool = proptools.Bool