Merge "Reduce how often both mutated variants are needed."
diff --git a/Android.bp b/Android.bp
index b57b0cc..e89f908 100644
--- a/Android.bp
+++ b/Android.bp
@@ -64,6 +64,7 @@
         "android/env.go",
     ],
     testSrcs: [
+        "android/config_test.go",
         "android/expand_test.go",
         "android/paths_test.go",
         "android/prebuilt_test.go",
diff --git a/android/config_test.go b/android/config_test.go
new file mode 100644
index 0000000..5eb6ed5
--- /dev/null
+++ b/android/config_test.go
@@ -0,0 +1,86 @@
+// Copyright 2017 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 android
+
+import (
+	"fmt"
+	"reflect"
+	"strings"
+	"testing"
+)
+
+func validateConfigAnnotations(configurable jsonConfigurable) (err error) {
+	reflectType := reflect.TypeOf(configurable)
+	reflectType = reflectType.Elem()
+	for i := 0; i < reflectType.NumField(); i++ {
+		field := reflectType.Field(i)
+		jsonTag := field.Tag.Get("json")
+		// Check for mistakes in the json tag
+		if jsonTag != "" && !strings.HasPrefix(jsonTag, ",") {
+			if !strings.Contains(jsonTag, ",") {
+				// Probably an accidental rename, most likely "omitempty" instead of ",omitempty"
+				return fmt.Errorf("Field %s.%s has tag %s which specifies to change its json field name to %q.\n"+
+					"Did you mean to use an annotation of %q?\n"+
+					"(Alternatively, to change the json name of the field, rename the field in source instead.)",
+					reflectType.Name(), field.Name, field.Tag, jsonTag, ","+jsonTag)
+			} else {
+				// Although this rename was probably intentional,
+				// a json annotation is still more confusing than renaming the source variable
+				requestedName := strings.Split(jsonTag, ",")[0]
+				return fmt.Errorf("Field %s.%s has tag %s which specifies to change its json field name to %q.\n"+
+					"To change the json name of the field, rename the field in source instead.",
+					reflectType.Name(), field.Name, field.Tag, requestedName)
+
+			}
+		}
+	}
+	return nil
+}
+
+type configType struct {
+	populateMe *bool `json:"omitempty"`
+}
+
+func (c *configType) SetDefaultConfig() {
+}
+
+// tests that ValidateConfigAnnotation works
+func TestValidateConfigAnnotations(t *testing.T) {
+	config := configType{}
+	err := validateConfigAnnotations(&config)
+	expectedError := `Field configType.populateMe has tag json:"omitempty" which specifies to change its json field name to "omitempty".
+Did you mean to use an annotation of ",omitempty"?
+(Alternatively, to change the json name of the field, rename the field in source instead.)`
+	if err.Error() != expectedError {
+		t.Errorf("Incorrect error; expected:\n"+
+			"%s\n"+
+			"got:\n"+
+			"%s",
+			expectedError, err.Error())
+	}
+}
+
+// run validateConfigAnnotations against each type that might have json annotations
+func TestProductConfigAnnotations(t *testing.T) {
+	err := validateConfigAnnotations(&productVariables{})
+	if err != nil {
+		t.Errorf(err.Error())
+	}
+
+	validateConfigAnnotations(&FileConfigurableOptions{})
+	if err != nil {
+		t.Errorf(err.Error())
+	}
+}
diff --git a/android/package_ctx.go b/android/package_ctx.go
index 8e37a83..d32e82b 100644
--- a/android/package_ctx.go
+++ b/android/package_ctx.go
@@ -198,7 +198,7 @@
 // AndroidStaticRule wraps blueprint.StaticRule and provides a default Pool if none is specified
 func (p AndroidPackageContext) AndroidStaticRule(name string, params blueprint.RuleParams,
 	argNames ...string) blueprint.Rule {
-	return p.AndroidRuleFunc(name, func(interface{}) (blueprint.RuleParams, error) {
+	return p.AndroidRuleFunc(name, func(Config) (blueprint.RuleParams, error) {
 		return params, nil
 	}, argNames...)
 }
@@ -210,9 +210,9 @@
 }
 
 func (p AndroidPackageContext) AndroidRuleFunc(name string,
-	f func(interface{}) (blueprint.RuleParams, error), argNames ...string) blueprint.Rule {
+	f func(Config) (blueprint.RuleParams, error), argNames ...string) blueprint.Rule {
 	return p.PackageContext.RuleFunc(name, func(config interface{}) (blueprint.RuleParams, error) {
-		params, err := f(config)
+		params, err := f(config.(Config))
 		if config.(Config).UseGoma() && params.Pool == nil {
 			// When USE_GOMA=true is set and the rule is not supported by goma, restrict jobs to the
 			// local parallelism value
diff --git a/cc/compiler.go b/cc/compiler.go
index ca68a00..fc2eeec 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -206,6 +206,21 @@
 	return deps
 }
 
+// Return true if the module is in the WarningAllowedProjects.
+func warningsAreAllowed(subdir string) bool {
+	subdir += "/"
+	for _, prefix := range config.WarningAllowedProjects {
+		if strings.HasPrefix(subdir, prefix) {
+			return true
+		}
+	}
+	return false
+}
+
+func addToModuleList(ctx ModuleContext, list string, module string) {
+	getWallWerrorMap(ctx.AConfig(), list).Store(module, true)
+}
+
 // Create a Flags struct that collects the compile flags from global values,
 // per-target values, module type values, and per-module Blueprints properties
 func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags {
@@ -464,6 +479,21 @@
 		flags = rsFlags(ctx, flags, &compiler.Properties)
 	}
 
+	if len(compiler.Properties.Srcs) > 0 {
+		module := ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
+		if inList("-Wno-error", flags.CFlags) || inList("-Wno-error", flags.CppFlags) {
+			addToModuleList(ctx, modulesUsingWnoError, module)
+		} else if !inList("-Werror", flags.CFlags) && !inList("-Werror", flags.CppFlags) {
+			if warningsAreAllowed(ctx.ModuleDir()) {
+				addToModuleList(ctx, modulesAddedWall, module)
+				flags.CFlags = append([]string{"-Wall"}, flags.CFlags...)
+			} else {
+				addToModuleList(ctx, modulesAddedWerror, module)
+				flags.CFlags = append([]string{"-Wall", "-Werror"}, flags.CFlags...)
+			}
+		}
+	}
+
 	return flags
 }
 
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index 0f28d1e..fda4f9d 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -115,7 +115,9 @@
 			"-D__ARM_FEATURE_LPAE=1",
 		},
 		"kryo": []string{
-			"-mcpu=cortex-a15",
+			// Use cortex-a53 because the GNU assembler doesn't recognize -mcpu=kryo
+			// even though clang does.
+			"-mcpu=cortex-a53",
 			"-mfpu=neon-fp-armv8",
 			// Fake an ARM compiler flag as these processors support LPAE which GCC/clang
 			// don't advertise.
@@ -158,10 +160,9 @@
 	android.RegisterArchVariantFeatures(android.Arm, "armv7-a-neon", "neon")
 	android.RegisterArchVariantFeatures(android.Arm, "armv8-a", "neon")
 
-	// Krait and Kryo targets are not supported by GCC, but are supported by Clang,
-	// so override the definitions when building modules with Clang.
+	// Krait is not supported by GCC, but is supported by Clang, so
+	// override the definitions when building modules with Clang.
 	replaceFirst(armClangCpuVariantCflags["krait"], "-mcpu=cortex-a15", "-mcpu=krait")
-	replaceFirst(armClangCpuVariantCflags["kryo"], "-mcpu=cortex-a15", "-mcpu=krait")
 
 	// The reason we use "-march=armv8-a+crc", instead of "-march=armv8-a", for
 	// gcc is the latter would conflict with any specified/supported -mcpu!
diff --git a/cc/config/global.go b/cc/config/global.go
index 44ad30b..4322436 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -118,6 +118,51 @@
 	ClangDefaultBase         = "prebuilts/clang/host"
 	ClangDefaultVersion      = "clang-4393122"
 	ClangDefaultShortVersion = "5.0.1"
+
+	WarningAllowedProjects = []string{
+		"external/boringssl/",
+		"external/libese/third_party/NXPNFC_P61_JCOP_Kit/",
+		"external/mdnsresponder/",
+		"external/protobuf/",
+		"external/skia/",
+		"device/",
+		"frameworks/av/media/libeffects/factory/",
+		"frameworks/av/media/libstagefright/codecs/",
+		"frameworks/base/tools/streaming_proto/",
+		"frameworks/ml/nn/",
+		"frameworks/native/libs/vr/libbufferhub/",
+		"frameworks/native/libs/vr/libbufferhubqueue/",
+		"frameworks/native/libs/vr/libdvr/tests/",
+		"frameworks/native/services/surfaceflinger/tests/",
+		"frameworks/native/services/vr/",
+		"hardware/interfaces/audio/effect/",
+		"hardware/interfaces/biometrics/fingerprint/",
+		"vendor/",
+	}
+
+	// Some Android.mk files still have warnings.
+	WarningAllowedOldProjects = []string{
+		"cts/hostsidetests/security/securityPatch/",
+		"cts/tests/tests/permission/jni/",
+		"development/tutorials/ReverseDebug/",
+		"external/freetype/",
+		"frameworks/av/drm/mediacas/plugins/",
+		"frameworks/av/media/libaaudio/examples/",
+		"frameworks/av/services/mediaextractor/",
+		"frameworks/base/core/tests/webkit/apk_with_native_libs/jni/",
+		"frameworks/base/tests/backup/",
+		"frameworks/native/cmds/cmd/",
+		"frameworks/webview/chromium/",
+		"hardware/interfaces/audio/2.0/",
+		"hardware/libhardware/modules/",
+		"hardware/libhardware/tests/",
+		"hardware/qcom/",
+		"sdk/emulator/mksdcard/",
+		"system/vold/tests/",
+		"test/vts-testcase/kernel/api/qtaguid/",
+		"test/vts-testcase/security/poc/target/",
+		"tools/adt/idea/android/ultimate/get_modification_time/jni/",
+	}
 )
 
 var pctx = android.NewPackageContext("android/soong/cc/config")
diff --git a/cc/makevars.go b/cc/makevars.go
index 7befb11..f7f8b60 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -18,15 +18,51 @@
 	"fmt"
 	"sort"
 	"strings"
+	"sync"
 
 	"android/soong/android"
 	"android/soong/cc/config"
 )
 
+const (
+	modulesAddedWall     = "ModulesAddedWall"
+	modulesAddedWerror   = "ModulesAddedWerror"
+	modulesUsingWnoError = "ModulesUsingWnoError"
+)
+
 func init() {
 	android.RegisterMakeVarsProvider(pctx, makeVarsProvider)
 }
 
+func getWallWerrorMap(config android.Config, name string) *sync.Map {
+	return config.Once(name, func() interface{} {
+		return &sync.Map{}
+	}).(*sync.Map)
+}
+
+func makeStringOfKeys(ctx android.MakeVarsContext, setName string) string {
+	set := getWallWerrorMap(ctx.Config(), setName)
+	keys := []string{}
+	set.Range(func(key interface{}, value interface{}) bool {
+		keys = append(keys, key.(string))
+		return true
+	})
+	sort.Strings(keys)
+	return strings.Join(keys, " ")
+}
+
+func makeStringOfWarningAllowedProjects() string {
+	allProjects := append([]string{}, config.WarningAllowedProjects...)
+	allProjects = append(allProjects, config.WarningAllowedOldProjects...)
+	sort.Strings(allProjects)
+	// Makefile rules use pattern "path/%" to match module paths.
+	if len(allProjects) > 0 {
+		return strings.Join(allProjects, "% ") + "%"
+	} else {
+		return ""
+	}
+}
+
 func makeVarsProvider(ctx android.MakeVarsContext) {
 	ctx.Strict("LLVM_RELEASE_VERSION", "${config.ClangShortVersion}")
 	ctx.Strict("LLVM_PREBUILTS_VERSION", "${config.ClangVersion}")
@@ -64,6 +100,11 @@
 	ctx.Strict("LLNDK_LIBRARIES", strings.Join(llndkLibraries, " "))
 	ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(vndkPrivateLibraries, " "))
 
+	ctx.Strict("ANDROID_WARNING_ALLOWED_PROJECTS", makeStringOfWarningAllowedProjects())
+	ctx.Strict("SOONG_MODULES_ADDED_WALL", makeStringOfKeys(ctx, modulesAddedWall))
+	ctx.Strict("SOONG_MODULES_ADDED_WERROR", makeStringOfKeys(ctx, modulesAddedWerror))
+	ctx.Strict("SOONG_MODULES_USING_WNO_ERROR", makeStringOfKeys(ctx, modulesUsingWnoError))
+
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", strings.Join(asanCflags, " "))
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_LDFLAGS", strings.Join(asanLdflags, " "))
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_STATIC_LIBRARIES", strings.Join(asanLibs, " "))
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index c517523..96a90fb 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -251,6 +251,8 @@
 		"-Wno-incompatible-library-redeclaration",
 		"-Wno-builtin-requires-header",
 		"-Wno-invalid-noreturn",
+		"-Wall",
+		"-Werror",
 		// These libraries aren't actually used. Don't worry about unwinding
 		// (avoids the need to link an unwinder into a fake library).
 		"-fno-unwind-tables",