Rename variables with "-" in androidmk

Make variables containg a "-" would succeed the translation to
blueprint, only to fail during the blueprint format step. Rename those
variables with a "-" and update references to them.

Test: androidmk_test.go
Bug: 112653593
Change-Id: Ifcbe1c6749a1e7f1e0b78cd6f01a8f1f52a334d0
diff --git a/androidmk/androidmk/androidmk.go b/androidmk/androidmk/androidmk.go
index 4aadbe8..dcd67d8 100644
--- a/androidmk/androidmk/androidmk.go
+++ b/androidmk/androidmk/androidmk.go
@@ -34,6 +34,7 @@
 	defs              []bpparser.Definition
 	localAssignments  map[string]*bpparser.Property
 	globalAssignments map[string]*bpparser.Expression
+	variableRenames   map[string]string
 	scope             mkparser.Scope
 	module            *bpparser.Module
 
@@ -43,6 +44,10 @@
 	inModule bool
 }
 
+var invalidVariableStringToReplacement = map[string]string{
+	"-": "_dash_",
+}
+
 func (f *bpFile) insertComment(s string) {
 	f.comments = append(f.comments, &bpparser.CommentGroup{
 		Comments: []*bpparser.Comment{
@@ -120,6 +125,7 @@
 		scope:             androidScope(),
 		localAssignments:  make(map[string]*bpparser.Property),
 		globalAssignments: make(map[string]*bpparser.Expression),
+		variableRenames:   make(map[string]string),
 	}
 
 	var conds []*conditional
@@ -224,6 +230,25 @@
 	return string(out), errs
 }
 
+func renameVariableWithInvalidCharacters(name string) string {
+	renamed := ""
+	for invalid, replacement := range invalidVariableStringToReplacement {
+		if strings.Contains(name, invalid) {
+			renamed = strings.ReplaceAll(name, invalid, replacement)
+		}
+	}
+
+	return renamed
+}
+
+func invalidVariableStrings() string {
+	invalidStrings := make([]string, 0, len(invalidVariableStringToReplacement))
+	for s := range invalidVariableStringToReplacement {
+		invalidStrings = append(invalidStrings, "\""+s+"\"")
+	}
+	return strings.Join(invalidStrings, ", ")
+}
+
 func handleAssignment(file *bpFile, assignment *mkparser.Assignment, c *conditional) {
 	if !assignment.Name.Const() {
 		file.errorf(assignment, "unsupported non-const variable name")
@@ -238,6 +263,12 @@
 	name := assignment.Name.Value(nil)
 	prefix := ""
 
+	if newName := renameVariableWithInvalidCharacters(name); newName != "" {
+		file.warnf("Variable names cannot contain: %s. Renamed \"%s\" to \"%s\"", invalidVariableStrings(), name, newName)
+		file.variableRenames[name] = newName
+		name = newName
+	}
+
 	if strings.HasPrefix(name, "LOCAL_") {
 		for _, x := range propertyPrefixes {
 			if strings.HasSuffix(name, "_"+x.mk) {
@@ -341,11 +372,11 @@
 	var err error
 	switch typ {
 	case bpparser.ListType:
-		exp, err = makeToListExpression(val, file.scope)
+		exp, err = makeToListExpression(val, file)
 	case bpparser.StringType:
-		exp, err = makeToStringExpression(val, file.scope)
+		exp, err = makeToStringExpression(val, file)
 	case bpparser.BoolType:
-		exp, err = makeToBoolExpression(val)
+		exp, err = makeToBoolExpression(val, file)
 	default:
 		panic("unknown type")
 	}
@@ -358,7 +389,6 @@
 }
 
 func setVariable(file *bpFile, plusequals bool, prefix, name string, value bpparser.Expression, local bool) error {
-
 	if prefix != "" {
 		name = prefix + "." + name
 	}
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index 54bd586..4f307c4 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -1367,6 +1367,28 @@
 `,
 	},
 	{
+		desc: "dashed_variable gets renamed",
+		in: `
+		include $(CLEAR_VARS)
+
+		dashed-variable:= a.cpp
+
+		LOCAL_MODULE:= test
+		LOCAL_SRC_FILES:= $(dashed-variable)
+		include $(BUILD_EXECUTABLE)
+		`,
+		expected: `
+
+// ANDROIDMK TRANSLATION WARNING: Variable names cannot contain: "-". Renamed "dashed-variable" to "dashed_dash_variable"
+dashed_dash_variable = ["a.cpp"]
+cc_binary {
+
+    name: "test",
+    srcs: dashed_dash_variable,
+}
+`,
+	},
+	{
 		desc: "undefined_boolean_var",
 		in: `
 include $(CLEAR_VARS)
diff --git a/androidmk/androidmk/values.go b/androidmk/androidmk/values.go
index 6b18a65..9618142 100644
--- a/androidmk/androidmk/values.go
+++ b/androidmk/androidmk/values.go
@@ -60,8 +60,7 @@
 	}, nil
 }
 
-func makeToStringExpression(ms *mkparser.MakeString, scope mkparser.Scope) (bpparser.Expression, error) {
-
+func makeToStringExpression(ms *mkparser.MakeString, file *bpFile) (bpparser.Expression, error) {
 	var val bpparser.Expression
 	var err error
 
@@ -70,18 +69,18 @@
 	}
 
 	for i, s := range ms.Strings[1:] {
-		if ret, ok := ms.Variables[i].EvalFunction(scope); ok {
+		if ret, ok := ms.Variables[i].EvalFunction(file.scope); ok {
 			if len(ret) > 1 {
 				return nil, fmt.Errorf("Unexpected list value %s", ms.Dump())
 			}
 			val, err = addValues(val, stringToStringValue(ret[0]))
 		} else {
-			name := ms.Variables[i].Name
-			if !name.Const() {
-				return nil, fmt.Errorf("Unsupported non-const variable name %s", name.Dump())
+			name, err := extractVariableName(ms.Variables[i].Name, file)
+			if err != nil {
+				return nil, err
 			}
 			tmp := &bpparser.Variable{
-				Name:  name.Value(nil),
+				Name:  name,
 				Value: &bpparser.String{},
 			}
 
@@ -125,8 +124,7 @@
 
 }
 
-func makeToListExpression(ms *mkparser.MakeString, scope mkparser.Scope) (bpparser.Expression, error) {
-
+func makeToListExpression(ms *mkparser.MakeString, file *bpFile) (bpparser.Expression, error) {
 	fields := ms.Split(" \t")
 
 	var listOfListValues []bpparser.Expression
@@ -135,14 +133,14 @@
 
 	for _, f := range fields {
 		if len(f.Variables) == 1 && f.Strings[0] == "" && f.Strings[1] == "" {
-			if ret, ok := f.Variables[0].EvalFunction(scope); ok {
+			if ret, ok := f.Variables[0].EvalFunction(file.scope); ok {
 				listValue.Values = append(listValue.Values, stringListToStringValueList(ret)...)
 			} else {
-				// Variable by itself, variable is probably a list
-				if !f.Variables[0].Name.Const() {
-					return nil, fmt.Errorf("unsupported non-const variable name")
+				name, err := extractVariableName(f.Variables[0].Name, file)
+				if err != nil {
+					return nil, err
 				}
-				if f.Variables[0].Name.Value(nil) == "TOP" {
+				if name == "TOP" {
 					listValue.Values = append(listValue.Values, &bpparser.String{
 						Value: ".",
 					})
@@ -151,14 +149,14 @@
 						listOfListValues = append(listOfListValues, listValue)
 					}
 					listOfListValues = append(listOfListValues, &bpparser.Variable{
-						Name:  f.Variables[0].Name.Value(nil),
+						Name:  name,
 						Value: &bpparser.List{},
 					})
 					listValue = &bpparser.List{}
 				}
 			}
 		} else {
-			s, err := makeToStringExpression(f, scope)
+			s, err := makeToStringExpression(f, file)
 			if err != nil {
 				return nil, err
 			}
@@ -208,15 +206,15 @@
 	}, nil
 }
 
-func makeToBoolExpression(ms *mkparser.MakeString) (bpparser.Expression, error) {
+func makeToBoolExpression(ms *mkparser.MakeString, file *bpFile) (bpparser.Expression, error) {
 	if !ms.Const() {
 		if len(ms.Variables) == 1 && ms.Strings[0] == "" && ms.Strings[1] == "" {
-			name := ms.Variables[0].Name
-			if !name.Const() {
-				return nil, fmt.Errorf("unsupported non-const variable name")
+			name, err := extractVariableName(ms.Variables[0].Name, file)
+			if err != nil {
+				return nil, err
 			}
 			return &bpparser.Variable{
-				Name:  name.Value(nil),
+				Name:  name,
 				Value: &bpparser.Bool{},
 			}, nil
 		} else {
@@ -226,3 +224,17 @@
 
 	return stringToBoolValue(ms.Value(nil))
 }
+
+func extractVariableName(name *mkparser.MakeString, file *bpFile) (string, error) {
+	if !name.Const() {
+		return "", fmt.Errorf("Unsupported non-const variable name %s", name.Dump())
+	}
+
+	variableName := name.Value(nil)
+
+	if newName, ok := file.variableRenames[variableName]; ok {
+		variableName = newName
+	}
+
+	return variableName, nil
+}