bp2build: automatically convert all filegroups.

See build_conversion_test.go for expected outputs.

Test: build_conversion_test.go
Test: GENERATE_BAZEL_FILES=true m nothing &&
./build/bazel/scripts/bp2build-sync.sh write && bazel build
//bionic/libc/tools/...
Test: bazel query //... --config=queryview

Change-Id: I3c54b96c0812f1ea4ab2c95da1bff3d7c5cc4006
diff --git a/android/filegroup.go b/android/filegroup.go
index 9425616..fd4a2fe 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -17,10 +17,50 @@
 import (
 	"android/soong/bazel"
 	"strings"
+
+	"github.com/google/blueprint/proptools"
 )
 
 func init() {
 	RegisterModuleType("filegroup", FileGroupFactory)
+	RegisterBp2BuildMutator("filegroup", bp2buildMutator)
+}
+
+// https://docs.bazel.build/versions/master/be/general.html#filegroup
+type bazelFilegroupAttributes struct {
+	Name *string
+	Srcs []string
+}
+
+type bazelFilegroup struct {
+	BazelTargetModuleBase
+	bazelFilegroupAttributes
+}
+
+func BazelFileGroupFactory() Module {
+	module := &bazelFilegroup{}
+	module.AddProperties(&module.bazelFilegroupAttributes)
+	InitBazelTargetModule(module)
+	return module
+}
+
+func (bfg *bazelFilegroup) Name() string {
+	return bfg.BaseModuleName()
+}
+
+func (bfg *bazelFilegroup) GenerateAndroidBuildActions(ctx ModuleContext) {}
+
+// TODO: Create helper functions to avoid this boilerplate.
+func bp2buildMutator(ctx TopDownMutatorContext) {
+	if m, ok := ctx.Module().(*fileGroup); ok {
+		name := "__bp2build__" + m.base().BaseModuleName()
+		ctx.CreateModule(BazelFileGroupFactory, &bazelFilegroupAttributes{
+			Name: proptools.StringPtr(name),
+			Srcs: m.properties.Srcs,
+		}, &bazel.BazelTargetModuleProperties{
+			Rule_class: "filegroup",
+		})
+	}
 }
 
 type fileGroupProperties struct {
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 0217580..2df72bd 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -266,3 +266,68 @@
 		}
 	}
 }
+
+func TestModuleTypeBp2Build(t *testing.T) {
+	testCases := []struct {
+		moduleTypeUnderTest        string
+		moduleTypeUnderTestFactory android.ModuleFactory
+		bp                         string
+		expectedBazelTarget        string
+	}{
+		{
+			moduleTypeUnderTest:        "filegroup",
+			moduleTypeUnderTestFactory: android.FileGroupFactory,
+			bp: `filegroup {
+	name: "foo",
+	srcs: [],
+}`,
+			expectedBazelTarget: `filegroup(
+    name = "foo",
+    srcs = [
+    ],
+)`,
+		},
+		{
+			moduleTypeUnderTest:        "filegroup",
+			moduleTypeUnderTestFactory: android.FileGroupFactory,
+			bp: `filegroup {
+	name: "foo",
+	srcs: ["a", "b"],
+}`,
+			expectedBazelTarget: `filegroup(
+    name = "foo",
+    srcs = [
+        "a",
+        "b",
+    ],
+)`,
+		},
+	}
+
+	dir := "."
+	for _, testCase := range testCases {
+		config := android.TestConfig(buildDir, nil, testCase.bp, nil)
+		ctx := android.NewTestContext(config)
+		ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
+		ctx.RegisterForBazelConversion()
+
+		_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
+		android.FailIfErrored(t, errs)
+		_, errs = ctx.ResolveDependencies(config)
+		android.FailIfErrored(t, errs)
+
+		bazelTargets := GenerateSoongModuleTargets(ctx.Context.Context, true)[dir]
+		if g, w := len(bazelTargets), 1; g != w {
+			t.Fatalf("Expected %d bazel target, got %d", w, g)
+		}
+
+		actualBazelTarget := bazelTargets[0]
+		if actualBazelTarget.content != testCase.expectedBazelTarget {
+			t.Errorf(
+				"Expected generated Bazel target to be '%s', got '%s'",
+				testCase.expectedBazelTarget,
+				actualBazelTarget.content,
+			)
+		}
+	}
+}