xref: /aosp_15_r20/build/soong/sdk/member_type.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1// Copyright (C) 2021 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package sdk
16
17import (
18	"reflect"
19
20	"android/soong/android"
21	"github.com/google/blueprint/proptools"
22)
23
24// Contains information about the sdk properties that list sdk members by type, e.g.
25// Java_header_libs.
26type sdkMemberTypeListProperty struct {
27	// getter for the list of member names
28	getter func(properties interface{}) []string
29
30	// setter for the list of member names
31	setter func(properties interface{}, list []string)
32
33	// the type of member referenced in the list
34	memberType android.SdkMemberType
35
36	// the dependency tag used for items in this list that can be used to determine the memberType
37	// for a resolved dependency.
38	dependencyTag android.SdkMemberDependencyTag
39}
40
41func (p *sdkMemberTypeListProperty) propertyName() string {
42	return p.memberType.SdkPropertyName()
43}
44
45// Cache of dynamically generated dynamicSdkMemberTypes objects. The key is the pointer
46// to a slice of SdkMemberType instances held in android.SdkMemberTypes.
47var dynamicSdkMemberTypesMap android.OncePer
48
49// A dynamically generated set of member list properties and associated structure type.
50type dynamicSdkMemberTypes struct {
51	// The dynamically generated structure type.
52	//
53	// Contains one []string exported field for each android.SdkMemberTypes. The name of the field
54	// is the exported form of the value returned by SdkMemberType.SdkPropertyName().
55	propertiesStructType reflect.Type
56
57	// Information about each of the member type specific list properties.
58	memberTypeListProperties []*sdkMemberTypeListProperty
59
60	memberTypeToProperty map[android.SdkMemberType]*sdkMemberTypeListProperty
61}
62
63func (d *dynamicSdkMemberTypes) createMemberTypeListProperties() interface{} {
64	return reflect.New(d.propertiesStructType).Interface()
65}
66
67func getDynamicSdkMemberTypes(key android.OnceKey, registeredTypes []android.SdkMemberType) *dynamicSdkMemberTypes {
68	// Get the cached value, creating new instance if necessary.
69	return dynamicSdkMemberTypesMap.Once(key, func() interface{} {
70		return createDynamicSdkMemberTypes(registeredTypes)
71	}).(*dynamicSdkMemberTypes)
72}
73
74// Create the dynamicSdkMemberTypes from the list of registered member types.
75//
76// A struct is created which contains one exported field per member type corresponding to
77// the SdkMemberType.SdkPropertyName() value.
78//
79// A list of sdkMemberTypeListProperty instances is created, one per member type that provides:
80// * a reference to the member type.
81// * a getter for the corresponding field in the properties struct.
82// * a dependency tag that identifies the member type of a resolved dependency.
83func createDynamicSdkMemberTypes(sdkMemberTypes []android.SdkMemberType) *dynamicSdkMemberTypes {
84
85	var listProperties []*sdkMemberTypeListProperty
86	memberTypeToProperty := map[android.SdkMemberType]*sdkMemberTypeListProperty{}
87	var fields []reflect.StructField
88
89	// Iterate over the member types creating StructField and sdkMemberTypeListProperty objects.
90	nextFieldIndex := 0
91	for _, memberType := range sdkMemberTypes {
92
93		p := memberType.SdkPropertyName()
94
95		var getter func(properties interface{}) []string
96		var setter func(properties interface{}, list []string)
97		if memberType.RequiresBpProperty() {
98			// Create a dynamic exported field for the member type's property.
99			fields = append(fields, reflect.StructField{
100				Name: proptools.FieldNameForProperty(p),
101				Type: reflect.TypeOf([]string{}),
102				Tag:  `android:"arch_variant"`,
103			})
104
105			// Copy the field index for use in the getter func as using the loop variable directly will
106			// cause all funcs to use the last value.
107			fieldIndex := nextFieldIndex
108			nextFieldIndex += 1
109
110			getter = func(properties interface{}) []string {
111				// The properties is expected to be of the following form (where
112				// <Module_types> is the name of an SdkMemberType.SdkPropertyName().
113				//     properties *struct {<Module_types> []string, ....}
114				//
115				// Although it accesses the field by index the following reflection code is equivalent to:
116				//    *properties.<Module_types>
117				//
118				list := reflect.ValueOf(properties).Elem().Field(fieldIndex).Interface().([]string)
119				return list
120			}
121
122			setter = func(properties interface{}, list []string) {
123				// The properties is expected to be of the following form (where
124				// <Module_types> is the name of an SdkMemberType.SdkPropertyName().
125				//     properties *struct {<Module_types> []string, ....}
126				//
127				// Although it accesses the field by index the following reflection code is equivalent to:
128				//    *properties.<Module_types> = list
129				//
130				reflect.ValueOf(properties).Elem().Field(fieldIndex).Set(reflect.ValueOf(list))
131			}
132		}
133
134		// Create an sdkMemberTypeListProperty for the member type.
135		memberListProperty := &sdkMemberTypeListProperty{
136			getter:     getter,
137			setter:     setter,
138			memberType: memberType,
139
140			// Dependencies added directly from member properties are always exported.
141			dependencyTag: android.DependencyTagForSdkMemberType(memberType, true),
142		}
143
144		memberTypeToProperty[memberType] = memberListProperty
145		listProperties = append(listProperties, memberListProperty)
146	}
147
148	// Create a dynamic struct from the collated fields.
149	propertiesStructType := reflect.StructOf(fields)
150
151	return &dynamicSdkMemberTypes{
152		memberTypeListProperties: listProperties,
153		memberTypeToProperty:     memberTypeToProperty,
154		propertiesStructType:     propertiesStructType,
155	}
156}
157