1package extensions
2
3import (
4	"strings"
5
6	"github.com/google/blueprint/parser"
7
8	"android/soong/bpfix/bpfix"
9)
10
11var fixSteps = bpfix.FixStepsExtension{
12	Name: "partner-include-dirs",
13	Steps: []bpfix.FixStep{
14		{
15			Name: "fixIncludeDirs",
16			Fix:  fixIncludeDirs,
17		},
18	},
19}
20
21func init() {
22	bpfix.RegisterFixStepExtension(&fixSteps)
23}
24
25type includeDirFix struct {
26	libName  string
27	libType  string
28	variable string
29	subdir   string
30}
31
32var commonIncludeDirs = []includeDirFix{
33	{
34		libName:  "my_header_lib",
35		libType:  "header_libs",
36		variable: "TARGET_OUT_HEADERS",
37		subdir:   "/my_headers",
38	},
39}
40
41func findHeaderLib(e parser.Expression) (*includeDirFix, bool) {
42	if op, ok := e.(*parser.Operator); ok {
43		if op.Operator != '+' {
44			return nil, false
45		}
46		arg0, ok := op.Args[0].(*parser.Variable)
47		arg1, ok1 := op.Args[1].(*parser.String)
48		if !ok || !ok1 {
49			return nil, false
50		}
51		for _, lib := range commonIncludeDirs {
52			if arg0.Name == lib.variable && arg1.Value == lib.subdir {
53				return &lib, true
54			}
55		}
56	}
57	return nil, false
58}
59func searchThroughOperatorList(mod *parser.Module, e parser.Expression) {
60	if list, ok := e.(*parser.List); ok {
61		newList := make([]parser.Expression, 0, len(list.Values))
62		for _, item := range list.Values {
63			if lib, found := findHeaderLib(item); found {
64				if lib.libName != "" {
65					addLibrary(mod, lib.libType, lib.libName)
66				}
67			} else {
68				newList = append(newList, item)
69			}
70		}
71		list.Values = newList
72	}
73	if op, ok := e.(*parser.Operator); ok {
74		searchThroughOperatorList(mod, op.Args[0])
75		searchThroughOperatorList(mod, op.Args[1])
76	}
77}
78func getLiteralListProperty(mod *parser.Module, name string) (list *parser.List, found bool) {
79	prop, ok := mod.GetProperty(name)
80	if !ok {
81		return nil, false
82	}
83	list, ok = prop.Value.(*parser.List)
84	return list, ok
85}
86func addLibrary(mod *parser.Module, libType string, libName string) {
87	var list, ok = getLiteralListProperty(mod, libType)
88	if !ok {
89		list = new(parser.List)
90		prop := new(parser.Property)
91		prop.Name = libType
92		prop.Value = list
93		mod.Properties = append(mod.Properties, prop)
94	} else {
95		for _, v := range list.Values {
96			if stringValue, ok := v.(*parser.String); ok && stringValue.Value == libName {
97				return
98			}
99		}
100	}
101	lib := new(parser.String)
102	lib.Value = libName
103	list.Values = append(list.Values, lib)
104}
105func fixIncludeDirs(f *bpfix.Fixer) error {
106	tree := f.Tree()
107	for _, def := range tree.Defs {
108		mod, ok := def.(*parser.Module)
109		if !ok {
110			continue
111		}
112		if !strings.HasPrefix(mod.Type, "cc_") {
113			continue
114		}
115		if prop, ok := mod.GetProperty("include_dirs"); ok {
116			searchThroughOperatorList(mod, prop.Value)
117		}
118	}
119	return nil
120}
121