Make *Context.Config return a Config instead of a interface{}

In Soong, a Config() method will always return a Config.  Make
ModuleContext, SingletonContext, TopDownMutatorContext and
BottomUpMutatorContext's Config() methods explictly return
a Config to avoid having to type-assert everywhere.  Overriding
the Config method requires duplicating the list of methods in
blueprint.BaseModuleContext and blueprint.BottomUpMutatorContext,
following the same pattern used by the other *Contexts.

Config() obsoletes the AConfig() method used in some places, which
will be cleaned up in the next patch.

Test: m checkbuild
Change-Id: Ibe21efde933959811d52443496967ab8ce71215e
diff --git a/android/androidmk.go b/android/androidmk.go
index aff43fa..d88ba8f 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -60,9 +60,7 @@
 type androidMkSingleton struct{}
 
 func (c *androidMkSingleton) GenerateBuildActions(ctx SingletonContext) {
-	config := ctx.Config().(Config)
-
-	if !config.EmbeddedInMake() {
+	if !ctx.Config().EmbeddedInMake() {
 		return
 	}
 
@@ -74,7 +72,7 @@
 
 	sort.Sort(AndroidModulesByName{androidMkModulesList, ctx})
 
-	transMk := PathForOutput(ctx, "Android"+String(config.ProductVariables.Make_suffix)+".mk")
+	transMk := PathForOutput(ctx, "Android"+String(ctx.Config().ProductVariables.Make_suffix)+".mk")
 	if ctx.Failed() {
 		return
 	}
@@ -184,8 +182,7 @@
 
 		}
 
-		config := ctx.Config().(Config)
-		if amod.Arch().ArchType != config.Targets[amod.Os().Class][0].Arch.ArchType {
+		if amod.Arch().ArchType != ctx.Config().Targets[amod.Os().Class][0].Arch.ArchType {
 			prefix = "2ND_" + prefix
 		}
 	}
diff --git a/android/api_levels.go b/android/api_levels.go
index bdfbc43..a519117 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -66,7 +66,7 @@
 		"N-MR1": 25,
 		"O":     26,
 	}
-	for i, codename := range ctx.Config().(Config).PlatformVersionCombinedCodenames() {
+	for i, codename := range ctx.Config().PlatformVersionCombinedCodenames() {
 		apiLevelsMap[codename] = baseApiLevel + i
 	}
 
diff --git a/android/env.go b/android/env.go
index c03431b..469dfff 100644
--- a/android/env.go
+++ b/android/env.go
@@ -48,7 +48,7 @@
 type envSingleton struct{}
 
 func (c *envSingleton) GenerateBuildActions(ctx SingletonContext) {
-	envDeps := ctx.Config().(Config).EnvDeps()
+	envDeps := ctx.Config().EnvDeps()
 
 	envFile := PathForOutput(ctx, ".soong.environment")
 	if ctx.Failed() {
diff --git a/android/makevars.go b/android/makevars.go
index d323613..00a20f5 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -105,13 +105,11 @@
 }
 
 func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
-	config := ctx.Config().(Config)
-
-	if !config.EmbeddedInMake() {
+	if !ctx.Config().EmbeddedInMake() {
 		return
 	}
 
-	outFile := PathForOutput(ctx, "make_vars"+proptools.String(config.ProductVariables.Make_suffix)+".mk").String()
+	outFile := PathForOutput(ctx, "make_vars"+proptools.String(ctx.Config().ProductVariables.Make_suffix)+".mk").String()
 
 	if ctx.Failed() {
 		return
@@ -120,7 +118,7 @@
 	vars := []makeVarsVariable{}
 	for _, provider := range makeVarsProviders {
 		mctx := &makeVarsContext{
-			config: config,
+			config: ctx.Config(),
 			ctx:    ctx,
 			pctx:   provider.pctx,
 		}
diff --git a/android/module.go b/android/module.go
index 0eb4820..476929a 100644
--- a/android/module.go
+++ b/android/module.go
@@ -19,6 +19,7 @@
 	"path/filepath"
 	"sort"
 	"strings"
+	"text/scanner"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
@@ -70,13 +71,36 @@
 }
 
 type BaseContext interface {
-	blueprint.BaseModuleContext
+	BaseModuleContext
 	androidBaseContext
 }
 
+// BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns
+// a Config instead of an interface{}.
+type BaseModuleContext interface {
+	ModuleName() string
+	ModuleDir() string
+	Config() Config
+
+	ContainsProperty(name string) bool
+	Errorf(pos scanner.Position, fmt string, args ...interface{})
+	ModuleErrorf(fmt string, args ...interface{})
+	PropertyErrorf(property, fmt string, args ...interface{})
+	Failed() bool
+
+	// GlobWithDeps returns a list of files that match the specified pattern but do not match any
+	// of the patterns in excludes.  It also adds efficient dependencies to rerun the primary
+	// builder whenever a file matching the pattern as added or removed, without rerunning if a
+	// file that does not match the pattern is added to a searched directory.
+	GlobWithDeps(pattern string, excludes []string) ([]string, error)
+
+	Fs() pathtools.FileSystem
+	AddNinjaFileDeps(deps ...string)
+}
+
 type ModuleContext interface {
 	androidBaseContext
-	blueprint.BaseModuleContext
+	BaseModuleContext
 
 	// Deprecated: use ModuleContext.Build instead.
 	ModuleBuild(pctx PackageContext, params ModuleBuildParams)
@@ -482,7 +506,7 @@
 			Rule:      blueprint.Phony,
 			Output:    name,
 			Implicits: allInstalledFiles,
-			Default:   !ctx.Config().(Config).EmbeddedInMake(),
+			Default:   !ctx.Config().EmbeddedInMake(),
 		})
 		deps = append(deps, name)
 		a.installTarget = name
@@ -501,7 +525,7 @@
 
 	if len(deps) > 0 {
 		suffix := ""
-		if ctx.Config().(Config).EmbeddedInMake() {
+		if ctx.Config().EmbeddedInMake() {
 			suffix = "-soong"
 		}
 
@@ -605,6 +629,10 @@
 	return
 }
 
+func (a *androidModuleContext) Config() Config {
+	return a.ModuleContext.Config().(Config)
+}
+
 func (a *androidModuleContext) ModuleBuild(pctx PackageContext, params ModuleBuildParams) {
 	a.Build(pctx, BuildParams(params))
 }
@@ -1094,7 +1122,7 @@
 	})
 
 	suffix := ""
-	if ctx.Config().(Config).EmbeddedInMake() {
+	if ctx.Config().EmbeddedInMake() {
 		suffix = "-soong"
 	}
 
@@ -1106,7 +1134,7 @@
 	})
 
 	// Make will generate the MODULES-IN-* targets
-	if ctx.Config().(Config).EmbeddedInMake() {
+	if ctx.Config().EmbeddedInMake() {
 		return
 	}
 
@@ -1151,7 +1179,7 @@
 			Implicits: modulesInDir[dir],
 			// HACK: checkbuild should be an optional build, but force it
 			// enabled for now in standalone builds
-			Default: !ctx.Config().(Config).EmbeddedInMake(),
+			Default: !ctx.Config().EmbeddedInMake(),
 		})
 	}
 
diff --git a/android/mutator.go b/android/mutator.go
index cc3f1f3..db3eaa3 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -108,7 +108,7 @@
 type AndroidTopDownMutator func(TopDownMutatorContext)
 
 type TopDownMutatorContext interface {
-	blueprint.BaseModuleContext
+	BaseModuleContext
 	androidBaseContext
 
 	OtherModuleExists(name string) bool
@@ -139,8 +139,22 @@
 type AndroidBottomUpMutator func(BottomUpMutatorContext)
 
 type BottomUpMutatorContext interface {
-	blueprint.BottomUpMutatorContext
+	BaseModuleContext
 	androidBaseContext
+
+	OtherModuleExists(name string) bool
+	Rename(name string)
+	Module() blueprint.Module
+
+	AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string)
+	AddReverseDependency(module blueprint.Module, tag blueprint.DependencyTag, name string)
+	CreateVariations(...string) []blueprint.Module
+	CreateLocalVariations(...string) []blueprint.Module
+	SetDependencyVariation(string)
+	AddVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string)
+	AddFarVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string)
+	AddInterVariantDependency(tag blueprint.DependencyTag, from, to blueprint.Module)
+	ReplaceDependencies(string)
 }
 
 type androidBottomUpMutatorContext struct {
@@ -193,6 +207,14 @@
 	}
 }
 
+func (a *androidTopDownMutatorContext) Config() Config {
+	return a.config
+}
+
+func (a *androidBottomUpMutatorContext) Config() Config {
+	return a.config
+}
+
 func (a *androidTopDownMutatorContext) Module() Module {
 	module, _ := a.TopDownMutatorContext.Module().(Module)
 	return module
diff --git a/android/package_ctx.go b/android/package_ctx.go
index 1626f76..b40e0a9 100644
--- a/android/package_ctx.go
+++ b/android/package_ctx.go
@@ -47,7 +47,7 @@
 var _ PathContext = &configErrorWrapper{}
 var _ errorfContext = &configErrorWrapper{}
 
-func (e *configErrorWrapper) Config() interface{} {
+func (e *configErrorWrapper) Config() Config {
 	return e.config
 }
 func (e *configErrorWrapper) Errorf(format string, args ...interface{}) {
diff --git a/android/paths.go b/android/paths.go
index 71049ee..cdc0399 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -29,7 +29,7 @@
 // Path methods.
 type PathContext interface {
 	Fs() pathtools.FileSystem
-	Config() interface{}
+	Config() Config
 	AddNinjaFileDeps(deps ...string)
 }
 
@@ -37,8 +37,8 @@
 	GlobWithDeps(globPattern string, excludes []string) ([]string, error)
 }
 
-var _ PathContext = blueprint.SingletonContext(nil)
-var _ PathContext = blueprint.ModuleContext(nil)
+var _ PathContext = SingletonContext(nil)
+var _ PathContext = ModuleContext(nil)
 
 type ModuleInstallPathContext interface {
 	PathContext
@@ -67,15 +67,6 @@
 
 var _ moduleErrorf = blueprint.ModuleContext(nil)
 
-// pathConfig returns the android Config interface associated to the context.
-// Panics if the context isn't affiliated with an android build.
-func pathConfig(ctx PathContext) Config {
-	if ret, ok := ctx.Config().(Config); ok {
-		return ret
-	}
-	panic("Paths may only be used on Soong builds")
-}
-
 // reportPathError will register an error with the attached context. It
 // attempts ctx.ModuleErrorf for a better error message first, then falls
 // back to ctx.Errorf.
@@ -197,7 +188,7 @@
 
 // PathsForSource returns Paths rooted from SrcDir
 func PathsForSource(ctx PathContext, paths []string) Paths {
-	if pathConfig(ctx).AllowMissingDependencies() {
+	if ctx.Config().AllowMissingDependencies() {
 		if modCtx, ok := ctx.(ModuleContext); ok {
 			ret := make(Paths, 0, len(paths))
 			intermediates := pathForModule(modCtx).withRel("missing")
@@ -476,14 +467,14 @@
 // code that is embedding ninja variables in paths
 func safePathForSource(ctx PathContext, path string) SourcePath {
 	p := validateSafePath(ctx, path)
-	ret := SourcePath{basePath{p, pathConfig(ctx), ""}}
+	ret := SourcePath{basePath{p, ctx.Config(), ""}}
 
 	abs, err := filepath.Abs(ret.String())
 	if err != nil {
 		reportPathError(ctx, "%s", err.Error())
 		return ret
 	}
-	buildroot, err := filepath.Abs(pathConfig(ctx).buildDir)
+	buildroot, err := filepath.Abs(ctx.Config().buildDir)
 	if err != nil {
 		reportPathError(ctx, "%s", err.Error())
 		return ret
@@ -501,14 +492,14 @@
 // On error, it will return a usable, but invalid SourcePath, and report a ModuleError.
 func PathForSource(ctx PathContext, pathComponents ...string) SourcePath {
 	p := validatePath(ctx, pathComponents...)
-	ret := SourcePath{basePath{p, pathConfig(ctx), ""}}
+	ret := SourcePath{basePath{p, ctx.Config(), ""}}
 
 	abs, err := filepath.Abs(ret.String())
 	if err != nil {
 		reportPathError(ctx, "%s", err.Error())
 		return ret
 	}
-	buildroot, err := filepath.Abs(pathConfig(ctx).buildDir)
+	buildroot, err := filepath.Abs(ctx.Config().buildDir)
 	if err != nil {
 		reportPathError(ctx, "%s", err.Error())
 		return ret
@@ -536,14 +527,14 @@
 	}
 
 	p := validatePath(ctx, pathComponents...)
-	path := SourcePath{basePath{p, pathConfig(ctx), ""}}
+	path := SourcePath{basePath{p, ctx.Config(), ""}}
 
 	abs, err := filepath.Abs(path.String())
 	if err != nil {
 		reportPathError(ctx, "%s", err.Error())
 		return OptionalPath{}
 	}
-	buildroot, err := filepath.Abs(pathConfig(ctx).buildDir)
+	buildroot, err := filepath.Abs(ctx.Config().buildDir)
 	if err != nil {
 		reportPathError(ctx, "%s", err.Error())
 		return OptionalPath{}
@@ -652,7 +643,7 @@
 // On error, it will return a usable, but invalid OutputPath, and report a ModuleError.
 func PathForOutput(ctx PathContext, pathComponents ...string) OutputPath {
 	path := validatePath(ctx, pathComponents...)
-	return OutputPath{basePath{path, pathConfig(ctx), ""}}
+	return OutputPath{basePath{path, ctx.Config(), ""}}
 }
 
 func (p OutputPath) writablePath() {}
@@ -905,7 +896,7 @@
 	if strings.ContainsAny(phony, "$/") {
 		reportPathError(ctx, "Phony target contains invalid character ($ or /): %s", phony)
 	}
-	return OutputPath{basePath{phony, pathConfig(ctx), ""}}
+	return OutputPath{basePath{phony, ctx.Config(), ""}}
 }
 
 type testPath struct {
diff --git a/android/paths_test.go b/android/paths_test.go
index 82ae4dc..1e4ba53 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -194,7 +194,7 @@
 	return pathtools.MockFs(nil)
 }
 
-func (m moduleInstallPathContextImpl) Config() interface{} {
+func (m moduleInstallPathContextImpl) Config() Config {
 	return m.androidBaseContextImpl.config
 }
 
diff --git a/android/singleton.go b/android/singleton.go
index f2f575f..87910fd 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -21,8 +21,7 @@
 
 // SingletonContext
 type SingletonContext interface {
-	// TODO(ccross): make this return an android.Config
-	Config() interface{}
+	Config() Config
 
 	ModuleName(module blueprint.Module) string
 	ModuleDir(module blueprint.Module) string
@@ -87,6 +86,10 @@
 	blueprint.SingletonContext
 }
 
+func (s singletonContextAdaptor) Config() Config {
+	return s.SingletonContext.Config().(Config)
+}
+
 func (s singletonContextAdaptor) Variable(pctx PackageContext, name, value string) {
 	s.SingletonContext.Variable(pctx.PackageContext, name, value)
 }
diff --git a/android/variable.go b/android/variable.go
index 13b5abf..c8a672e 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -258,7 +258,7 @@
 		property := "product_variables." + proptools.PropertyNameForField(name)
 
 		// Check that the variable was set for the product
-		val := reflect.ValueOf(mctx.Config().(Config).ProductVariables).FieldByName(name)
+		val := reflect.ValueOf(mctx.Config().ProductVariables).FieldByName(name)
 		if !val.IsValid() || val.Kind() != reflect.Ptr || val.IsNil() {
 			continue
 		}