Merge remote-tracking branch 'aosp/upstream'

* aosp/upstream:
  docs: Allow propery structs to contain non-struct ptrs
  Catch panics in build logic
  Colorize errors
diff --git a/bootstrap/bpdoc/bpdoc.go b/bootstrap/bpdoc/bpdoc.go
index d4b52a5..f96d37e 100644
--- a/bootstrap/bpdoc/bpdoc.go
+++ b/bootstrap/bpdoc/bpdoc.go
@@ -501,13 +501,11 @@
 						}
 						elem = elem.Elem()
 					}
-					if elem.Kind() != reflect.Struct {
-						panic(fmt.Errorf("can't get type of field %q: points to a "+
-							"non-struct", field.Name))
+					if elem.Kind() == reflect.Struct {
+						nestPoint := prefix + proptools.PropertyNameForField(field.Name)
+						ret[nestPoint] = elem
+						walk(elem, nestPoint+".")
 					}
-					nestPoint := prefix + proptools.PropertyNameForField(field.Name)
-					ret[nestPoint] = elem
-					walk(elem, nestPoint+".")
 				}
 			default:
 				panic(fmt.Errorf("unexpected kind for property struct field %q: %s",
diff --git a/bootstrap/command.go b/bootstrap/command.go
index 65d6f46..69b2271 100644
--- a/bootstrap/command.go
+++ b/bootstrap/command.go
@@ -177,12 +177,15 @@
 }
 
 func fatalErrors(errs []error) {
+	red := "\x1b[31m"
+	unred := "\x1b[0m"
+
 	for _, err := range errs {
-		switch err.(type) {
+		switch err := err.(type) {
 		case *blueprint.Error:
-			_, _ = fmt.Printf("%s\n", err.Error())
+			fmt.Printf("%serror:%s %s\n", red, unred, err.Error())
 		default:
-			_, _ = fmt.Printf("internal error: %s\n", err)
+			fmt.Printf("%sinternal error:%s %s\n", red, unred, err)
 		}
 	}
 	os.Exit(1)
diff --git a/context.go b/context.go
index 31541da..30dc451 100644
--- a/context.go
+++ b/context.go
@@ -157,6 +157,14 @@
 	actionDefs localBuildActions
 }
 
+func (module *moduleInfo) String() string {
+	s := fmt.Sprintf("module %q", module.properties.Name)
+	if module.variantName != "" {
+		s += fmt.Sprintf(" variant %q", module.variantName)
+	}
+	return s
+}
+
 // A Variation is a way that a variant of a module differs from other variants of the same module.
 // For example, two variants of the same module might have Variation{"arch","arm"} and
 // Variation{"arch","arm64"}
@@ -1122,13 +1130,20 @@
 	ctx.AddDependency(ctx.Module(), ctx.moduleInfo().properties.Deps...)
 
 	if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
-		dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
+		func() {
+			defer func() {
+				if r := recover(); r != nil {
+					ctx.error(newPanicErrorf(r, "DynamicDependencies for %s", ctx.moduleInfo()))
+				}
+			}()
+			dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
 
-		if ctx.Failed() {
-			return
-		}
+			if ctx.Failed() {
+				return
+			}
 
-		ctx.AddDependency(ctx.Module(), dynamicDeps...)
+			ctx.AddDependency(ctx.Module(), dynamicDeps...)
+		}()
 	}
 }
 
@@ -1516,7 +1531,20 @@
 					},
 					name: mutator.name,
 				}
-				mutator.mutator(mctx)
+				func() {
+					defer func() {
+						if r := recover(); r != nil {
+							in := fmt.Sprintf("early mutator %q for %s", mutator.name, module)
+							if err, ok := r.(panicError); ok {
+								err.addIn(in)
+								mctx.error(err)
+							} else {
+								mctx.error(newPanicErrorf(r, in))
+							}
+						}
+					}()
+					mutator.mutator(mctx)
+				}()
 				if len(mctx.errs) > 0 {
 					errs = append(errs, mctx.errs...)
 					return errs
@@ -1576,8 +1604,21 @@
 			},
 			name: name,
 		}
+		func() {
+			defer func() {
+				if r := recover(); r != nil {
+					in := fmt.Sprintf("top down mutator %q for %s", name, module)
+					if err, ok := r.(panicError); ok {
+						err.addIn(in)
+						mctx.error(err)
+					} else {
+						mctx.error(newPanicErrorf(r, in))
+					}
+				}
+			}()
+			mutator(mctx)
+		}()
 
-		mutator(mctx)
 		if len(mctx.errs) > 0 {
 			errs = append(errs, mctx.errs...)
 			return errs
@@ -1609,7 +1650,20 @@
 			reverseDeps: reverseDeps,
 		}
 
-		mutator(mctx)
+		func() {
+			defer func() {
+				if r := recover(); r != nil {
+					in := fmt.Sprintf("bottom up mutator %q for %s", name, module)
+					if err, ok := r.(panicError); ok {
+						err.addIn(in)
+						mctx.error(err)
+					} else {
+						mctx.error(newPanicErrorf(r, in))
+					}
+				}
+			}()
+			mutator(mctx)
+		}()
 		if len(mctx.errs) > 0 {
 			errs = append(errs, mctx.errs...)
 			return errs
@@ -1726,7 +1780,20 @@
 			handledMissingDeps: module.missingDeps == nil,
 		}
 
-		mctx.module.logicModule.GenerateBuildActions(mctx)
+		func() {
+			defer func() {
+				if r := recover(); r != nil {
+					in := fmt.Sprintf("GenerateBuildActions for %s", module)
+					if err, ok := r.(panicError); ok {
+						err.addIn(in)
+						mctx.error(err)
+					} else {
+						mctx.error(newPanicErrorf(r, in))
+					}
+				}
+			}()
+			mctx.module.logicModule.GenerateBuildActions(mctx)
+		}()
 
 		if len(mctx.errs) > 0 {
 			errsCh <- mctx.errs
@@ -1781,7 +1848,20 @@
 			scope:   scope,
 		}
 
-		info.singleton.GenerateBuildActions(sctx)
+		func() {
+			defer func() {
+				if r := recover(); r != nil {
+					in := fmt.Sprintf("GenerateBuildActions for singleton %s", info.name)
+					if err, ok := r.(panicError); ok {
+						err.addIn(in)
+						sctx.error(err)
+					} else {
+						sctx.error(newPanicErrorf(r, in))
+					}
+				}
+			}()
+			info.singleton.GenerateBuildActions(sctx)
+		}()
 
 		if len(sctx.errs) > 0 {
 			errs = append(errs, sctx.errs...)
@@ -1849,6 +1929,14 @@
 	visit func(Module, Module) bool) {
 
 	visited := make(map[*moduleInfo]bool)
+	var visiting *moduleInfo
+
+	defer func() {
+		if r := recover(); r != nil {
+			panic(newPanicErrorf(r, "WalkDeps(%s, %s) for dependency %s",
+				topModule, funcName(visit), visiting))
+		}
+	}()
 
 	var walk func(module *moduleInfo)
 	walk = func(module *moduleInfo) {
@@ -1856,6 +1944,7 @@
 
 		for _, moduleDep := range module.directDeps {
 			if !visited[moduleDep] {
+				visiting = moduleDep
 				if visit(moduleDep.logicModule, module.logicModule) {
 					walk(moduleDep)
 				}
@@ -1866,8 +1955,18 @@
 	walk(topModule)
 }
 
+type innerPanicError error
+
 func (c *Context) visitDepsDepthFirst(topModule *moduleInfo, visit func(Module)) {
 	visited := make(map[*moduleInfo]bool)
+	var visiting *moduleInfo
+
+	defer func() {
+		if r := recover(); r != nil {
+			panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
+				topModule, funcName(visit), visiting))
+		}
+	}()
 
 	var walk func(module *moduleInfo)
 	walk = func(module *moduleInfo) {
@@ -1879,6 +1978,7 @@
 		}
 
 		if module != topModule {
+			visiting = module
 			visit(module.logicModule)
 		}
 	}
@@ -1890,6 +1990,14 @@
 	visit func(Module)) {
 
 	visited := make(map[*moduleInfo]bool)
+	var visiting *moduleInfo
+
+	defer func() {
+		if r := recover(); r != nil {
+			panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
+				topModule, funcName(pred), funcName(visit), visiting))
+		}
+	}()
 
 	var walk func(module *moduleInfo)
 	walk = func(module *moduleInfo) {
@@ -1902,6 +2010,7 @@
 
 		if module != topModule {
 			if pred(module.logicModule) {
+				visiting = module
 				visit(module.logicModule)
 			}
 		}
@@ -1911,7 +2020,16 @@
 }
 
 func (c *Context) visitDirectDeps(module *moduleInfo, visit func(Module)) {
-	for _, dep := range module.directDeps {
+	var dep *moduleInfo
+
+	defer func() {
+		if r := recover(); r != nil {
+			panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s",
+				module, funcName(visit), dep))
+		}
+	}()
+
+	for _, dep = range module.directDeps {
 		visit(dep.logicModule)
 	}
 }
@@ -1919,7 +2037,16 @@
 func (c *Context) visitDirectDepsIf(module *moduleInfo, pred func(Module) bool,
 	visit func(Module)) {
 
-	for _, dep := range module.directDeps {
+	var dep *moduleInfo
+
+	defer func() {
+		if r := recover(); r != nil {
+			panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s",
+				module, funcName(pred), funcName(visit), dep))
+		}
+	}()
+
+	for _, dep = range module.directDeps {
 		if pred(dep.logicModule) {
 			visit(dep.logicModule)
 		}
@@ -1940,9 +2067,18 @@
 }
 
 func (c *Context) visitAllModules(visit func(Module)) {
+	var module *moduleInfo
+
+	defer func() {
+		if r := recover(); r != nil {
+			panic(newPanicErrorf(r, "VisitAllModules(%s) for %s",
+				funcName(visit), module))
+		}
+	}()
+
 	for _, moduleName := range c.sortedModuleNames() {
 		group := c.moduleGroups[moduleName]
-		for _, module := range group.modules {
+		for _, module = range group.modules {
 			visit(module.logicModule)
 		}
 	}
@@ -1951,6 +2087,15 @@
 func (c *Context) visitAllModulesIf(pred func(Module) bool,
 	visit func(Module)) {
 
+	var module *moduleInfo
+
+	defer func() {
+		if r := recover(); r != nil {
+			panic(newPanicErrorf(r, "VisitAllModulesIf(%s, %s) for %s",
+				funcName(pred), funcName(visit), module))
+		}
+	}()
+
 	for _, moduleName := range c.sortedModuleNames() {
 		group := c.moduleGroups[moduleName]
 		for _, module := range group.modules {
@@ -1961,6 +2106,23 @@
 	}
 }
 
+func (c *Context) visitAllModuleVariants(module *moduleInfo,
+	visit func(Module)) {
+
+	var variant *moduleInfo
+
+	defer func() {
+		if r := recover(); r != nil {
+			panic(newPanicErrorf(r, "VisitAllModuleVariants(%s, %s) for %s",
+				module, funcName(visit), variant))
+		}
+	}()
+
+	for _, variant = range module.group.modules {
+		visit(variant.logicModule)
+	}
+}
+
 func (c *Context) requireNinjaVersion(major, minor, micro int) {
 	if major != 1 {
 		panic("ninja version with major version != 1 not supported")
@@ -2236,9 +2398,7 @@
 func (c *Context) VisitAllModuleVariants(module Module,
 	visit func(Module)) {
 
-	for _, module := range c.moduleInfo[module].group.modules {
-		visit(module.logicModule)
-	}
+	c.visitAllModuleVariants(c.moduleInfo[module], visit)
 }
 
 // WriteBuildFile writes the Ninja manifeset text for the generated build
@@ -2739,6 +2899,34 @@
 	panic(fmt.Errorf("element %v not found in list %v", missing, list))
 }
 
+type panicError struct {
+	panic interface{}
+	stack []byte
+	in    string
+}
+
+func newPanicErrorf(panic interface{}, in string, a ...interface{}) error {
+	buf := make([]byte, 4096)
+	count := runtime.Stack(buf, false)
+	return panicError{
+		panic: panic,
+		in:    fmt.Sprintf(in, a...),
+		stack: buf[:count],
+	}
+}
+
+func (p panicError) Error() string {
+	return fmt.Sprintf("panic in %s\n%s\n%s\n", p.in, p.panic, p.stack)
+}
+
+func (p *panicError) addIn(in string) {
+	p.in += " in " + in
+}
+
+func funcName(f interface{}) string {
+	return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
+}
+
 var fileHeaderTemplate = `******************************************************************************
 ***            This file is generated and should not be edited             ***
 ******************************************************************************
diff --git a/module_ctx.go b/module_ctx.go
index 754c2d2..381b54a 100644
--- a/module_ctx.go
+++ b/module_ctx.go
@@ -119,6 +119,7 @@
 	Failed() bool
 
 	moduleInfo() *moduleInfo
+	error(err error)
 }
 
 type DynamicDependerModuleContext BottomUpMutatorContext
@@ -180,10 +181,16 @@
 	return d.config
 }
 
+func (d *baseModuleContext) error(err error) {
+	if err != nil {
+		d.errs = append(d.errs, err)
+	}
+}
+
 func (d *baseModuleContext) Errorf(pos scanner.Position,
 	format string, args ...interface{}) {
 
-	d.errs = append(d.errs, &Error{
+	d.error(&Error{
 		Err: fmt.Errorf(format, args...),
 		Pos: pos,
 	})
@@ -192,7 +199,7 @@
 func (d *baseModuleContext) ModuleErrorf(format string,
 	args ...interface{}) {
 
-	d.errs = append(d.errs, &Error{
+	d.error(&Error{
 		Err: fmt.Errorf(format, args...),
 		Pos: d.module.pos,
 	})
@@ -209,7 +216,7 @@
 
 	format = property + ": " + format
 
-	d.errs = append(d.errs, &Error{
+	d.error(&Error{
 		Err: fmt.Errorf(format, args...),
 		Pos: pos,
 	})
@@ -320,9 +327,7 @@
 }
 
 func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) {
-	for _, module := range m.module.group.modules {
-		visit(module.logicModule)
-	}
+	m.context.visitAllModuleVariants(m.module, visit)
 }
 
 func (m *moduleContext) GetMissingDependencies() []string {
diff --git a/singleton_ctx.go b/singleton_ctx.go
index 07e5108..a2d6109 100644
--- a/singleton_ctx.go
+++ b/singleton_ctx.go
@@ -91,15 +91,21 @@
 	return s.context.BlueprintFile(logicModule)
 }
 
+func (s *singletonContext) error(err error) {
+	if err != nil {
+		s.errs = append(s.errs, err)
+	}
+}
+
 func (s *singletonContext) ModuleErrorf(logicModule Module, format string,
 	args ...interface{}) {
 
-	s.errs = append(s.errs, s.context.ModuleErrorf(logicModule, format, args...))
+	s.error(s.context.ModuleErrorf(logicModule, format, args...))
 }
 
 func (s *singletonContext) Errorf(format string, args ...interface{}) {
 	// TODO: Make this not result in the error being printed as "internal error"
-	s.errs = append(s.errs, fmt.Errorf(format, args...))
+	s.error(fmt.Errorf(format, args...))
 }
 
 func (s *singletonContext) Failed() bool {
diff --git a/splice_modules_test.go b/splice_modules_test.go
index 091f5bf..cfe905a 100644
--- a/splice_modules_test.go
+++ b/splice_modules_test.go
@@ -28,10 +28,6 @@
 	testModuleF = &moduleInfo{variantName: "testModuleF"}
 )
 
-func (m *moduleInfo) String() string {
-	return m.variantName
-}
-
 var spliceModulesTestCases = []struct {
 	in         []*moduleInfo
 	replace    *moduleInfo