bp2build: convert paths/module refs to Bazel label

This currently expands all globs, still need to support converting glob
syntax.

Test: go build_conversion_test
Test: GENERATE_BAZEL_FILES=true m nothing
Test: m nothing
Bug: 165114590
Change-Id: If7b26e8e663d17566fad9614ca87a8da1f095284
diff --git a/android/arch.go b/android/arch.go
index baee9be..90e0485 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -436,7 +436,7 @@
 	// blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext
 	// filters out non-Soong modules.  Now that we've handled them, create a
 	// normal android.BottomUpMutatorContext.
-	mctx := bottomUpMutatorContextFactory(bpctx, module, false)
+	mctx := bottomUpMutatorContextFactory(bpctx, module, false, false)
 
 	base := module.base()
 
@@ -576,7 +576,7 @@
 	// blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext
 	// filters out non-Soong modules.  Now that we've handled them, create a
 	// normal android.BottomUpMutatorContext.
-	mctx := bottomUpMutatorContextFactory(bpctx, module, false)
+	mctx := bottomUpMutatorContextFactory(bpctx, module, false, false)
 
 	base := module.base()
 
diff --git a/android/filegroup.go b/android/filegroup.go
index 3d1bbc5..7a6cc4f 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -29,7 +29,7 @@
 // https://docs.bazel.build/versions/master/be/general.html#filegroup
 type bazelFilegroupAttributes struct {
 	Name *string
-	Srcs []string
+	Srcs bazel.LabelList
 }
 
 type bazelFilegroup struct {
@@ -52,15 +52,18 @@
 
 // TODO: Create helper functions to avoid this boilerplate.
 func FilegroupBp2Build(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",
-		})
+	fg, ok := ctx.Module().(*fileGroup)
+	if !ok {
+		return
 	}
+
+	name := "__bp2build__" + fg.base().BaseModuleName()
+	ctx.CreateModule(BazelFileGroupFactory, &bazelFilegroupAttributes{
+		Name: proptools.StringPtr(name),
+		Srcs: BazelLabelForModuleSrcExcludes(ctx, fg.properties.Srcs, fg.properties.Exclude_srcs),
+	}, &bazel.BazelTargetModuleProperties{
+		Rule_class: "filegroup",
+	})
 }
 
 type fileGroupProperties struct {
diff --git a/android/module.go b/android/module.go
index dcc2b84..1409d44 100644
--- a/android/module.go
+++ b/android/module.go
@@ -2220,10 +2220,17 @@
 	}
 	var deps []dep
 	b.VisitDirectDepsBlueprint(func(module blueprint.Module) {
-		if aModule, _ := module.(Module); aModule != nil && aModule.base().BaseModuleName() == name {
-			returnedTag := b.bp.OtherModuleDependencyTag(aModule)
+		if aModule, _ := module.(Module); aModule != nil {
+			if aModule.base().BaseModuleName() == name {
+				returnedTag := b.bp.OtherModuleDependencyTag(aModule)
+				if tag == nil || returnedTag == tag {
+					deps = append(deps, dep{aModule, returnedTag})
+				}
+			}
+		} else if b.bp.OtherModuleName(module) == name {
+			returnedTag := b.bp.OtherModuleDependencyTag(module)
 			if tag == nil || returnedTag == tag {
-				deps = append(deps, dep{aModule, returnedTag})
+				deps = append(deps, dep{module, returnedTag})
 			}
 		}
 	})
diff --git a/android/mutator.go b/android/mutator.go
index 6b19dc5..15be65f 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -45,14 +45,30 @@
 }
 
 // RegisterMutatorsForBazelConversion is a alternate registration pipeline for bp2build. Exported for testing.
-func RegisterMutatorsForBazelConversion(ctx *blueprint.Context, bp2buildMutators []RegisterMutatorFunc) {
-	mctx := &registerMutatorsContext{}
-
-	sharedMutators := []RegisterMutatorFunc{
-		RegisterDefaultsPreArchMutators,
+func RegisterMutatorsForBazelConversion(ctx *blueprint.Context, preArchMutators, depsMutators, bp2buildMutators []RegisterMutatorFunc) {
+	mctx := &registerMutatorsContext{
+		bazelConversionMode: true,
 	}
 
-	for _, f := range sharedMutators {
+	bp2buildPreArchMutators = append([]RegisterMutatorFunc{
+		RegisterNamespaceMutator,
+		RegisterDefaultsPreArchMutators,
+		// TODO(b/165114590): this is required to resolve deps that are only prebuilts, but we should
+		// evaluate the impact on conversion.
+		RegisterPrebuiltsPreArchMutators,
+	},
+		preArchMutators...)
+
+	for _, f := range bp2buildPreArchMutators {
+		f(mctx)
+	}
+
+	bp2buildDepsMutators = append([]RegisterMutatorFunc{
+		registerDepsMutatorBp2Build,
+		registerPathDepsMutator,
+	}, depsMutators...)
+
+	for _, f := range bp2buildDepsMutators {
 		f(mctx)
 	}
 
@@ -77,7 +93,7 @@
 
 	register(preDeps)
 
-	mctx.BottomUp("deps", depsMutator).Parallel()
+	register([]RegisterMutatorFunc{registerDepsMutator})
 
 	register(postDeps)
 
@@ -88,8 +104,9 @@
 }
 
 type registerMutatorsContext struct {
-	mutators   []*mutator
-	finalPhase bool
+	mutators            []*mutator
+	finalPhase          bool
+	bazelConversionMode bool
 }
 
 type RegisterMutatorsContext interface {
@@ -211,6 +228,8 @@
 	finalDeps = append(finalDeps, f)
 }
 
+var bp2buildPreArchMutators = []RegisterMutatorFunc{}
+var bp2buildDepsMutators = []RegisterMutatorFunc{}
 var bp2buildMutators = []RegisterMutatorFunc{}
 
 // RegisterBp2BuildMutator registers specially crafted mutators for
@@ -219,13 +238,24 @@
 //
 // TODO(b/178068862): bring this into TestContext.
 func RegisterBp2BuildMutator(moduleType string, m func(TopDownMutatorContext)) {
-	mutatorName := moduleType + "_bp2build"
 	f := func(ctx RegisterMutatorsContext) {
-		ctx.TopDown(mutatorName, m)
+		ctx.TopDown(moduleType, m)
 	}
 	bp2buildMutators = append(bp2buildMutators, f)
 }
 
+// PreArchBp2BuildMutators adds mutators to be register for converting Android Blueprint modules
+// into Bazel BUILD targets that should run prior to deps and conversion.
+func PreArchBp2BuildMutators(f RegisterMutatorFunc) {
+	bp2buildPreArchMutators = append(bp2buildPreArchMutators, f)
+}
+
+// DepsBp2BuildMutators adds mutators to be register for converting Android Blueprint modules into
+// Bazel BUILD targets that should run prior to conversion to resolve dependencies.
+func DepsBp2BuildMutators(f RegisterMutatorFunc) {
+	bp2buildDepsMutators = append(bp2buildDepsMutators, f)
+}
+
 type BaseMutatorContext interface {
 	BaseModuleContext
 
@@ -370,32 +400,38 @@
 	// variant of the current module.  The value should not be modified after being passed to
 	// SetVariationProvider.
 	SetVariationProvider(module blueprint.Module, provider blueprint.ProviderKey, value interface{})
+
+	// BazelConversionMode returns whether this mutator is being run as part of Bazel Conversion.
+	BazelConversionMode() bool
 }
 
 type bottomUpMutatorContext struct {
 	bp blueprint.BottomUpMutatorContext
 	baseModuleContext
-	finalPhase bool
+	finalPhase          bool
+	bazelConversionMode bool
 }
 
 func bottomUpMutatorContextFactory(ctx blueprint.BottomUpMutatorContext, a Module,
-	finalPhase bool) BottomUpMutatorContext {
+	finalPhase, bazelConversionMode bool) BottomUpMutatorContext {
 
 	return &bottomUpMutatorContext{
-		bp:                ctx,
-		baseModuleContext: a.base().baseModuleContextFactory(ctx),
-		finalPhase:        finalPhase,
+		bp:                  ctx,
+		baseModuleContext:   a.base().baseModuleContextFactory(ctx),
+		finalPhase:          finalPhase,
+		bazelConversionMode: bazelConversionMode,
 	}
 }
 
 func (x *registerMutatorsContext) BottomUp(name string, m BottomUpMutator) MutatorHandle {
 	finalPhase := x.finalPhase
+	bazelConversionMode := x.bazelConversionMode
 	f := func(ctx blueprint.BottomUpMutatorContext) {
 		if a, ok := ctx.Module().(Module); ok {
-			m(bottomUpMutatorContextFactory(ctx, a, finalPhase))
+			m(bottomUpMutatorContextFactory(ctx, a, finalPhase, bazelConversionMode))
 		}
 	}
-	mutator := &mutator{name: name, bottomUpMutator: f}
+	mutator := &mutator{name: x.mutatorName(name), bottomUpMutator: f}
 	x.mutators = append(x.mutators, mutator)
 	return mutator
 }
@@ -406,6 +442,13 @@
 	return mutator
 }
 
+func (x *registerMutatorsContext) mutatorName(name string) string {
+	if x.bazelConversionMode {
+		return name + "_bp2build"
+	}
+	return name
+}
+
 func (x *registerMutatorsContext) TopDown(name string, m TopDownMutator) MutatorHandle {
 	f := func(ctx blueprint.TopDownMutatorContext) {
 		if a, ok := ctx.Module().(Module); ok {
@@ -416,7 +459,7 @@
 			m(actx)
 		}
 	}
-	mutator := &mutator{name: name, topDownMutator: f}
+	mutator := &mutator{name: x.mutatorName(name), topDownMutator: f}
 	x.mutators = append(x.mutators, mutator)
 	return mutator
 }
@@ -449,6 +492,16 @@
 	}
 }
 
+func registerDepsMutator(ctx RegisterMutatorsContext) {
+	ctx.BottomUp("deps", depsMutator).Parallel()
+}
+
+func registerDepsMutatorBp2Build(ctx RegisterMutatorsContext) {
+	// TODO(b/179313531): Consider a separate mutator that only runs depsMutator for modules that are
+	// being converted to build targets.
+	ctx.BottomUp("deps", depsMutator).Parallel()
+}
+
 func (t *topDownMutatorContext) AppendProperties(props ...interface{}) {
 	for _, p := range props {
 		err := proptools.AppendMatchingProperties(t.Module().base().customizableProperties,
@@ -576,12 +629,28 @@
 
 func (b *bottomUpMutatorContext) AddVariationDependencies(variations []blueprint.Variation, tag blueprint.DependencyTag,
 	names ...string) []blueprint.Module {
+	if b.bazelConversionMode {
+		_, noSelfDeps := RemoveFromList(b.ModuleName(), names)
+		if len(noSelfDeps) == 0 {
+			return []blueprint.Module(nil)
+		}
+		// In Bazel conversion mode, mutators should not have created any variants. So, when adding a
+		// dependency, the variations would not exist and the dependency could not be added, by
+		// specifying no variations, we will allow adding the dependency to succeed.
+		return b.bp.AddFarVariationDependencies(nil, tag, noSelfDeps...)
+	}
 
 	return b.bp.AddVariationDependencies(variations, tag, names...)
 }
 
 func (b *bottomUpMutatorContext) AddFarVariationDependencies(variations []blueprint.Variation,
 	tag blueprint.DependencyTag, names ...string) []blueprint.Module {
+	if b.bazelConversionMode {
+		// In Bazel conversion mode, mutators should not have created any variants. So, when adding a
+		// dependency, the variations would not exist and the dependency could not be added, by
+		// specifying no variations, we will allow adding the dependency to succeed.
+		return b.bp.AddFarVariationDependencies(nil, tag, names...)
+	}
 
 	return b.bp.AddFarVariationDependencies(variations, tag, names...)
 }
@@ -609,3 +678,7 @@
 func (b *bottomUpMutatorContext) SetVariationProvider(module blueprint.Module, provider blueprint.ProviderKey, value interface{}) {
 	b.bp.SetVariationProvider(module, provider, value)
 }
+
+func (b *bottomUpMutatorContext) BazelConversionMode() bool {
+	return b.bazelConversionMode
+}
diff --git a/android/paths.go b/android/paths.go
index 8106958..44221be 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -15,6 +15,7 @@
 package android
 
 import (
+	"android/soong/bazel"
 	"fmt"
 	"io/ioutil"
 	"os"
@@ -331,6 +332,115 @@
 	return ret
 }
 
+// A subset of the ModuleContext methods which are sufficient to resolve references to paths/deps in
+// order to form a Bazel-compatible label for conversion.
+type BazelConversionPathContext interface {
+	EarlyModulePathContext
+
+	GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
+	OtherModuleName(m blueprint.Module) string
+	OtherModuleDir(m blueprint.Module) string
+}
+
+// BazelLabelForModuleDeps returns a Bazel-compatible label for the requested modules which
+// correspond to dependencies on the module within the given ctx.
+func BazelLabelForModuleDeps(ctx BazelConversionPathContext, modules []string) bazel.LabelList {
+	var labels bazel.LabelList
+	for _, module := range modules {
+		bpText := module
+		if m := SrcIsModule(module); m == "" {
+			module = ":" + module
+		}
+		if m, t := SrcIsModuleWithTag(module); m != "" {
+			l := getOtherModuleLabel(ctx, m, t)
+			l.Bp_text = bpText
+			labels.Includes = append(labels.Includes, l)
+		} else {
+			ctx.ModuleErrorf("%q, is not a module reference", module)
+		}
+	}
+	return labels
+}
+
+// BazelLabelForModuleSrc returns bazel.LabelList with paths rooted from the module's local source
+// directory. It expands globs, and resolves references to modules using the ":name" syntax to
+// bazel-compatible labels.  Properties passed as the paths or excludes argument must have been
+// annotated with struct tag `android:"path"` so that dependencies on other modules will have
+// already been handled by the path_properties mutator.
+func BazelLabelForModuleSrc(ctx BazelConversionPathContext, paths []string) bazel.LabelList {
+	return BazelLabelForModuleSrcExcludes(ctx, paths, []string(nil))
+}
+
+// BazelLabelForModuleSrcExcludes returns bazel.LabelList with paths rooted from the module's local
+// source directory, excluding labels included in the excludes argument. It expands globs, and
+// resolves references to modules using the ":name" syntax to bazel-compatible labels. Properties
+// passed as the paths or excludes argument must have been annotated with struct tag
+// `android:"path"` so that dependencies on other modules will have already been handled by the
+// path_properties mutator.
+func BazelLabelForModuleSrcExcludes(ctx BazelConversionPathContext, paths, excludes []string) bazel.LabelList {
+	excludeLabels := expandSrcsForBazel(ctx, excludes, []string(nil))
+	excluded := make([]string, 0, len(excludeLabels.Includes))
+	for _, e := range excludeLabels.Includes {
+		excluded = append(excluded, e.Label)
+	}
+	labels := expandSrcsForBazel(ctx, paths, excluded)
+	labels.Excludes = excludeLabels.Includes
+	return labels
+}
+
+// expandSrcsForBazel returns bazel.LabelList with paths rooted from the module's local
+// source directory, excluding labels included in the excludes argument. It expands globs, and
+// resolves references to modules using the ":name" syntax to bazel-compatible labels.  Properties
+// passed as the paths or excludes argument must have been annotated with struct tag
+// `android:"path"` so that dependencies on other modules will have already been handled by the
+// path_properties mutator.
+func expandSrcsForBazel(ctx BazelConversionPathContext, paths, expandedExcludes []string) bazel.LabelList {
+	labels := bazel.LabelList{
+		Includes: []bazel.Label{},
+	}
+	for _, p := range paths {
+		if m, tag := SrcIsModuleWithTag(p); m != "" {
+			l := getOtherModuleLabel(ctx, m, tag)
+			if !InList(l.Label, expandedExcludes) {
+				l.Bp_text = fmt.Sprintf(":%s", m)
+				labels.Includes = append(labels.Includes, l)
+			}
+		} else {
+			var expandedPaths []bazel.Label
+			if pathtools.IsGlob(p) {
+				globbedPaths := GlobFiles(ctx, pathForModuleSrc(ctx, p).String(), expandedExcludes)
+				globbedPaths = PathsWithModuleSrcSubDir(ctx, globbedPaths, "")
+				for _, path := range globbedPaths {
+					s := path.Rel()
+					expandedPaths = append(expandedPaths, bazel.Label{Label: s})
+				}
+			} else {
+				if !InList(p, expandedExcludes) {
+					expandedPaths = append(expandedPaths, bazel.Label{Label: p})
+				}
+			}
+			labels.Includes = append(labels.Includes, expandedPaths...)
+		}
+	}
+	return labels
+}
+
+// getOtherModuleLabel returns a bazel.Label for the given dependency/tag combination for the
+// module. The label will be relative to the current directory if appropriate. The dependency must
+// already be resolved by either deps mutator or path deps mutator.
+func getOtherModuleLabel(ctx BazelConversionPathContext, dep, tag string) bazel.Label {
+	m, _ := ctx.GetDirectDep(dep)
+	// TODO(b/165114590): Convert tag (":name{.tag}") to corresponding Bazel implicit output targets.
+	otherModuleName := ctx.OtherModuleName(m)
+	var label bazel.Label
+	if otherDir, dir := ctx.OtherModuleDir(m), ctx.ModuleDir(); otherDir != dir {
+		label.Label = fmt.Sprintf("//%s:%s", otherDir, otherModuleName)
+	} else {
+		label.Label = fmt.Sprintf(":%s", otherModuleName)
+	}
+	return label
+}
+
 // OutputPaths is a slice of OutputPath objects, with helpers to operate on the collection.
 type OutputPaths []OutputPath
 
diff --git a/android/register.go b/android/register.go
index 02fc97e..18c743f 100644
--- a/android/register.go
+++ b/android/register.go
@@ -115,7 +115,7 @@
 		ctx.RegisterSingletonType(t.name, SingletonFactoryAdaptor(ctx, t.factory))
 	}
 
-	RegisterMutatorsForBazelConversion(ctx.Context, bp2buildMutators)
+	RegisterMutatorsForBazelConversion(ctx.Context, bp2buildPreArchMutators, bp2buildDepsMutators, bp2buildMutators)
 }
 
 // Register the pipeline of singletons, module types, and mutators for
diff --git a/android/testing.go b/android/testing.go
index 5640c29..de338bf 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -56,9 +56,9 @@
 
 type TestContext struct {
 	*Context
-	preArch, preDeps, postDeps, finalDeps []RegisterMutatorFunc
-	bp2buildMutators                      []RegisterMutatorFunc
-	NameResolver                          *NameResolver
+	preArch, preDeps, postDeps, finalDeps           []RegisterMutatorFunc
+	bp2buildPreArch, bp2buildDeps, bp2buildMutators []RegisterMutatorFunc
+	NameResolver                                    *NameResolver
 }
 
 func (ctx *TestContext) PreArchMutators(f RegisterMutatorFunc) {
@@ -85,13 +85,24 @@
 // RegisterBp2BuildMutator registers a BazelTargetModule mutator for converting a module
 // type to the equivalent Bazel target.
 func (ctx *TestContext) RegisterBp2BuildMutator(moduleType string, m func(TopDownMutatorContext)) {
-	mutatorName := moduleType + "_bp2build"
 	f := func(ctx RegisterMutatorsContext) {
-		ctx.TopDown(mutatorName, m)
+		ctx.TopDown(moduleType, m)
 	}
 	ctx.bp2buildMutators = append(ctx.bp2buildMutators, f)
 }
 
+// PreArchBp2BuildMutators adds mutators to be register for converting Android Blueprint modules
+// into Bazel BUILD targets that should run prior to deps and conversion.
+func (ctx *TestContext) PreArchBp2BuildMutators(f RegisterMutatorFunc) {
+	ctx.bp2buildPreArch = append(ctx.bp2buildPreArch, f)
+}
+
+// DepsBp2BuildMutators adds mutators to be register for converting Android Blueprint modules into
+// Bazel BUILD targets that should run prior to conversion to resolve dependencies.
+func (ctx *TestContext) DepsBp2BuildMutators(f RegisterMutatorFunc) {
+	ctx.bp2buildDeps = append(ctx.bp2buildDeps, f)
+}
+
 func (ctx *TestContext) Register() {
 	registerMutators(ctx.Context.Context, ctx.preArch, ctx.preDeps, ctx.postDeps, ctx.finalDeps)
 
@@ -100,7 +111,7 @@
 
 // RegisterForBazelConversion prepares a test context for bp2build conversion.
 func (ctx *TestContext) RegisterForBazelConversion() {
-	RegisterMutatorsForBazelConversion(ctx.Context.Context, ctx.bp2buildMutators)
+	RegisterMutatorsForBazelConversion(ctx.Context.Context, ctx.bp2buildPreArch, ctx.bp2buildDeps, ctx.bp2buildMutators)
 }
 
 func (ctx *TestContext) ParseFileList(rootDir string, filePaths []string) (deps []string, errs []error) {