Add configurable property support to neverallow

Bug: 362579941
Test: m nothing --no-skip-soong-tests
Change-Id: I50b8bf3cc2e3520a12932b0a0e1041e079379590
diff --git a/android/neverallow.go b/android/neverallow.go
index 0f363e7..a68f5ea 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -287,7 +287,7 @@
 			continue
 		}
 
-		if !n.appliesToProperties(properties) {
+		if !n.appliesToProperties(ctx, properties) {
 			continue
 		}
 
@@ -604,9 +604,9 @@
 	return (len(r.moduleTypes) == 0 || InList(moduleType, r.moduleTypes)) && !InList(moduleType, r.unlessModuleTypes)
 }
 
-func (r *rule) appliesToProperties(properties []interface{}) bool {
-	includeProps := hasAllProperties(properties, r.props)
-	excludeProps := hasAnyProperty(properties, r.unlessProps)
+func (r *rule) appliesToProperties(ctx BottomUpMutatorContext, properties []interface{}) bool {
+	includeProps := hasAllProperties(ctx, properties, r.props)
+	excludeProps := hasAnyProperty(ctx, properties, r.unlessProps)
 	return includeProps && !excludeProps
 }
 
@@ -644,25 +644,25 @@
 	return names
 }
 
-func hasAnyProperty(properties []interface{}, props []ruleProperty) bool {
+func hasAnyProperty(ctx BottomUpMutatorContext, properties []interface{}, props []ruleProperty) bool {
 	for _, v := range props {
-		if hasProperty(properties, v) {
+		if hasProperty(ctx, properties, v) {
 			return true
 		}
 	}
 	return false
 }
 
-func hasAllProperties(properties []interface{}, props []ruleProperty) bool {
+func hasAllProperties(ctx BottomUpMutatorContext, properties []interface{}, props []ruleProperty) bool {
 	for _, v := range props {
-		if !hasProperty(properties, v) {
+		if !hasProperty(ctx, properties, v) {
 			return false
 		}
 	}
 	return true
 }
 
-func hasProperty(properties []interface{}, prop ruleProperty) bool {
+func hasProperty(ctx BottomUpMutatorContext, properties []interface{}, prop ruleProperty) bool {
 	for _, propertyStruct := range properties {
 		propertiesValue := reflect.ValueOf(propertyStruct).Elem()
 		for _, v := range prop.fields {
@@ -679,14 +679,14 @@
 			return prop.matcher.Test(value)
 		}
 
-		if matchValue(propertiesValue, check) {
+		if matchValue(ctx, propertiesValue, check) {
 			return true
 		}
 	}
 	return false
 }
 
-func matchValue(value reflect.Value, check func(string) bool) bool {
+func matchValue(ctx BottomUpMutatorContext, value reflect.Value, check func(string) bool) bool {
 	if !value.IsValid() {
 		return false
 	}
@@ -698,19 +698,26 @@
 		value = value.Elem()
 	}
 
-	switch value.Kind() {
-	case reflect.String:
-		return check(value.String())
-	case reflect.Bool:
-		return check(strconv.FormatBool(value.Bool()))
-	case reflect.Int:
-		return check(strconv.FormatInt(value.Int(), 10))
-	case reflect.Slice:
-		slice, ok := value.Interface().([]string)
-		if !ok {
-			panic("Can only handle slice of string")
+	switch v := value.Interface().(type) {
+	case string:
+		return check(v)
+	case bool:
+		return check(strconv.FormatBool(v))
+	case int:
+		return check(strconv.FormatInt((int64)(v), 10))
+	case []string:
+		for _, v := range v {
+			if check(v) {
+				return true
+			}
 		}
-		for _, v := range slice {
+		return false
+	case proptools.Configurable[string]:
+		return check(v.GetOrDefault(ctx, ""))
+	case proptools.Configurable[bool]:
+		return check(strconv.FormatBool(v.GetOrDefault(ctx, false)))
+	case proptools.Configurable[[]string]:
+		for _, v := range v.GetOrDefault(ctx, nil) {
 			if check(v) {
 				return true
 			}