androidmk: support cfi, diag, and misc_undefined properties

Support more sanitize related properties.  Also remove integer,
since it isn't a supported property, and rewrite it to be
deterministic by not going through splitBpList.

This reapplies Ie8fba06c36fc121912c65a77ee495ceef4962df0.

Bug: 37547301
Test: androidmk_test.go
Change-Id: Id637ffdb7d36bed8a2c2fe76bd6f54662709e3b3
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index 3c3e2a1..8801b34 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -33,7 +33,8 @@
 	"LOCAL_MODULE_STEM":           stem,
 	"LOCAL_MODULE_HOST_OS":        hostOs,
 	"LOCAL_SRC_FILES":             srcFiles,
-	"LOCAL_SANITIZE":              sanitize,
+	"LOCAL_SANITIZE":              sanitize(""),
+	"LOCAL_SANITIZE_DIAG":         sanitize("diag."),
 
 	// composite functions
 	"LOCAL_MODULE_TAGS": includeVariableIf(bpVariable{"tags", bpparser.ListType}, not(valueDumpEquals("optional"))),
@@ -413,60 +414,50 @@
 	return nil
 }
 
-func sanitize(ctx variableAssignmentContext) error {
-	val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.ListType)
-	if err != nil {
-		return err
-	}
-
-	lists, err := splitBpList(val, func(value bpparser.Expression) (string, bpparser.Expression, error) {
-		switch v := value.(type) {
-		case *bpparser.Variable:
-			return "vars", value, nil
-		case *bpparser.Operator:
-			ctx.file.errorf(ctx.mkvalue, "unknown sanitize expression")
-			return "unknown", value, nil
-		case *bpparser.String:
-			switch v.Value {
-			case "never", "address", "coverage", "integer", "thread", "undefined":
-				bpTrue := &bpparser.Bool{
-					Value: true,
-				}
-				return v.Value, bpTrue, nil
-			default:
-				ctx.file.errorf(ctx.mkvalue, "unknown sanitize argument: %s", v.Value)
-				return "unknown", value, nil
-			}
-		default:
-			return "", nil, fmt.Errorf("sanitize expected a string, got %s", value.Type())
-		}
-	})
-	if err != nil {
-		return err
-	}
-
-	for k, v := range lists {
-		if emptyList(v) {
-			continue
-		}
-
-		switch k {
-		case "never", "address", "coverage", "integer", "thread", "undefined":
-			err = setVariable(ctx.file, false, ctx.prefix, "sanitize."+k, lists[k].(*bpparser.List).Values[0], true)
-		case "unknown":
-		// Nothing, we already added the error above
-		case "vars":
-			fallthrough
-		default:
-			err = setVariable(ctx.file, true, ctx.prefix, "sanitize", v, true)
-		}
-
+func sanitize(sub string) func(ctx variableAssignmentContext) error {
+	return func(ctx variableAssignmentContext) error {
+		val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.ListType)
 		if err != nil {
 			return err
 		}
-	}
 
-	return err
+		if _, ok := val.(*bpparser.List); !ok {
+			return fmt.Errorf("unsupported sanitize expression")
+		}
+
+		misc := &bpparser.List{}
+
+		for _, v := range val.(*bpparser.List).Values {
+			switch v := v.(type) {
+			case *bpparser.Variable, *bpparser.Operator:
+				ctx.file.errorf(ctx.mkvalue, "unsupported sanitize expression")
+			case *bpparser.String:
+				switch v.Value {
+				case "never", "address", "coverage", "thread", "undefined", "cfi":
+					bpTrue := &bpparser.Bool{
+						Value: true,
+					}
+					err = setVariable(ctx.file, false, ctx.prefix, "sanitize."+sub+v.Value, bpTrue, true)
+					if err != nil {
+						return err
+					}
+				default:
+					misc.Values = append(misc.Values, v)
+				}
+			default:
+				return fmt.Errorf("sanitize expected a string, got %s", v.Type())
+			}
+		}
+
+		if len(misc.Values) > 0 {
+			err = setVariable(ctx.file, false, ctx.prefix, "sanitize."+sub+"misc_undefined", misc, true)
+			if err != nil {
+				return err
+			}
+		}
+
+		return err
+	}
 }
 
 func prebuiltClass(ctx variableAssignmentContext) error {
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index 0c44ea7..5fbc951 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -285,37 +285,26 @@
 		desc: "LOCAL_SANITIZE unknown parameter",
 		in: `
 include $(CLEAR_VARS)
-LOCAL_SANITIZE := integer asdf
+LOCAL_SANITIZE := thread cfi asdf
+LOCAL_SANITIZE_DIAG := cfi
 LOCAL_SANITIZE_RECOVER := qwert
 include $(BUILD_SHARED_LIBRARY)
 `,
 		expected: `
 cc_library_shared {
-    // ANDROIDMK TRANSLATION ERROR: unknown sanitize argument: asdf
-    // integer asdf
     sanitize: {
-	integer: true,
-	recover: ["qwert"],
+        thread: true,
+        cfi: true,
+        misc_undefined: ["asdf"],
+        diag: {
+            cfi: true,
+        },
+        recover: ["qwert"],
     },
 }
 `,
 	},
 	{
-		desc: "LOCAL_SANITIZE using variable",
-		in: `
-sanitize_var := never
-include $(CLEAR_VARS)
-LOCAL_SANITIZE := $(sanitize_var)
-include $(BUILD_SHARED_LIBRARY)
-`,
-		expected: `
-sanitize_var = ["never"]
-cc_library_shared {
-    sanitize: sanitize_var,
-}
-`,
-	},
-	{
 		desc: "LOCAL_SANITIZE_RECOVER",
 		in: `
 include $(CLEAR_VARS)