• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2017 Google Inc. All rights reserved.
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
15// This file implements the logic of bpfix and also provides a programmatic interface
16
17package bpfix
18
19import (
20	"bytes"
21	"errors"
22	"fmt"
23	"io"
24	"path/filepath"
25	"strings"
26
27	"github.com/google/blueprint/parser"
28)
29
30// Reformat takes a blueprint file as a string and returns a formatted version
31func Reformat(input string) (string, error) {
32	tree, err := parse("<string>", bytes.NewBufferString(input))
33	if err != nil {
34		return "", err
35	}
36
37	res, err := parser.Print(tree)
38	if err != nil {
39		return "", err
40	}
41
42	return string(res), nil
43}
44
45// A FixRequest specifies the details of which fixes to apply to an individual file
46// A FixRequest doesn't specify whether to do a dry run or where to write the results; that's in cmd/bpfix.go
47type FixRequest struct {
48	steps []FixStep
49}
50type FixStepsExtension struct {
51	Name  string
52	Steps []FixStep
53}
54
55type FixStep struct {
56	Name string
57	Fix  func(f *Fixer) error
58}
59
60var fixStepsExtensions = []*FixStepsExtension(nil)
61
62func RegisterFixStepExtension(extension *FixStepsExtension) {
63	fixStepsExtensions = append(fixStepsExtensions, extension)
64}
65
66var fixSteps = []FixStep{
67	{
68		Name: "simplifyKnownRedundantVariables",
69		Fix:  runPatchListMod(simplifyKnownPropertiesDuplicatingEachOther),
70	},
71	{
72		Name: "rewriteIncorrectAndroidmkPrebuilts",
73		Fix:  rewriteIncorrectAndroidmkPrebuilts,
74	},
75	{
76		Name: "rewriteCtsModuleTypes",
77		Fix:  rewriteCtsModuleTypes,
78	},
79	{
80		Name: "rewriteIncorrectAndroidmkAndroidLibraries",
81		Fix:  rewriteIncorrectAndroidmkAndroidLibraries,
82	},
83	{
84		Name: "rewriteTestModuleTypes",
85		Fix:  rewriteTestModuleTypes,
86	},
87	{
88		Name: "rewriteAndroidmkJavaLibs",
89		Fix:  rewriteAndroidmkJavaLibs,
90	},
91	{
92		Name: "rewriteJavaStaticLibs",
93		Fix:  rewriteJavaStaticLibs,
94	},
95	{
96		Name: "rewritePrebuiltEtc",
97		Fix:  rewriteAndroidmkPrebuiltEtc,
98	},
99	{
100		Name: "mergeMatchingModuleProperties",
101		Fix:  runPatchListMod(mergeMatchingModuleProperties),
102	},
103	{
104		Name: "reorderCommonProperties",
105		Fix:  runPatchListMod(reorderCommonProperties),
106	},
107	{
108		Name: "removeTags",
109		Fix:  runPatchListMod(removeTags),
110	},
111	{
112		Name: "rewriteAndroidTest",
113		Fix:  rewriteAndroidTest,
114	},
115	{
116		Name: "rewriteAndroidAppImport",
117		Fix:  rewriteAndroidAppImport,
118	},
119	{
120		Name: "removeEmptyLibDependencies",
121		Fix:  removeEmptyLibDependencies,
122	},
123	{
124		Name: "removeHidlInterfaceTypes",
125		Fix:  removeHidlInterfaceTypes,
126	},
127	{
128		Name: "removeSoongConfigBoolVariable",
129		Fix:  removeSoongConfigBoolVariable,
130	},
131	{
132		Name: "removePdkProperty",
133		Fix:  runPatchListMod(removePdkProperty),
134	},
135}
136
137func NewFixRequest() FixRequest {
138	return FixRequest{}
139}
140
141func (r FixRequest) AddAll() (result FixRequest) {
142	result.steps = append([]FixStep(nil), r.steps...)
143	result.steps = append(result.steps, fixSteps...)
144	for _, extension := range fixStepsExtensions {
145		result.steps = append(result.steps, extension.Steps...)
146	}
147	return result
148}
149
150func (r FixRequest) AddBase() (result FixRequest) {
151	result.steps = append([]FixStep(nil), r.steps...)
152	result.steps = append(result.steps, fixSteps...)
153	return result
154}
155
156func (r FixRequest) AddMatchingExtensions(pattern string) (result FixRequest) {
157	result.steps = append([]FixStep(nil), r.steps...)
158	for _, extension := range fixStepsExtensions {
159		if match, _ := filepath.Match(pattern, extension.Name); match {
160			result.steps = append(result.steps, extension.Steps...)
161		}
162	}
163	return result
164}
165
166type Fixer struct {
167	tree *parser.File
168}
169
170func (f Fixer) Tree() *parser.File {
171	return f.tree
172}
173
174func NewFixer(tree *parser.File) *Fixer {
175	fixer := &Fixer{tree}
176
177	// make a copy of the tree
178	fixer.reparse()
179
180	return fixer
181}
182
183// Fix repeatedly applies the fixes listed in the given FixRequest to the given File
184// until there is no fix that affects the tree
185func (f *Fixer) Fix(config FixRequest) (*parser.File, error) {
186	prevIdentifier, err := f.fingerprint()
187	if err != nil {
188		return nil, err
189	}
190
191	maxNumIterations := 20
192	i := 0
193	for {
194		err = f.fixTreeOnce(config)
195		newIdentifier, err := f.fingerprint()
196		if err != nil {
197			return nil, err
198		}
199		if bytes.Equal(newIdentifier, prevIdentifier) {
200			break
201		}
202		prevIdentifier = newIdentifier
203		// any errors from a previous iteration generally get thrown away and overwritten by errors on the next iteration
204
205		// detect infinite loop
206		i++
207		if i >= maxNumIterations {
208			return nil, fmt.Errorf("Applied fixes %d times and yet the tree continued to change. Is there an infinite loop?", i)
209		}
210	}
211	return f.tree, err
212}
213
214// returns a unique identifier for the given tree that can be used to determine whether the tree changed
215func (f *Fixer) fingerprint() (fingerprint []byte, err error) {
216	bytes, err := parser.Print(f.tree)
217	if err != nil {
218		return nil, err
219	}
220	return bytes, nil
221}
222
223func (f *Fixer) reparse() ([]byte, error) {
224	buf, err := parser.Print(f.tree)
225	if err != nil {
226		return nil, err
227	}
228	newTree, err := parse(f.tree.Name, bytes.NewReader(buf))
229	if err != nil {
230		return nil, err
231	}
232	f.tree = newTree
233	return buf, nil
234}
235
236func parse(name string, r io.Reader) (*parser.File, error) {
237	tree, errs := parser.Parse(name, r, parser.NewScope(nil))
238	if errs != nil {
239		s := "parse error: "
240		for _, err := range errs {
241			s += "\n" + err.Error()
242		}
243		return nil, errors.New(s)
244	}
245	return tree, nil
246}
247
248func (f *Fixer) fixTreeOnce(config FixRequest) error {
249	for _, fix := range config.steps {
250		err := fix.Fix(f)
251		if err != nil {
252			return err
253		}
254	}
255	return nil
256}
257
258func simplifyKnownPropertiesDuplicatingEachOther(mod *parser.Module, buf []byte, patchList *parser.PatchList) error {
259	// remove from local_include_dirs anything in export_include_dirs
260	return removeMatchingModuleListProperties(mod, patchList,
261		"export_include_dirs", "local_include_dirs")
262}
263
264func rewriteIncorrectAndroidmkPrebuilts(f *Fixer) error {
265	for _, def := range f.tree.Defs {
266		mod, ok := def.(*parser.Module)
267		if !ok {
268			continue
269		}
270		if mod.Type != "java_import" {
271			continue
272		}
273		host, _ := getLiteralBoolPropertyValue(mod, "host")
274		if host {
275			mod.Type = "java_import_host"
276			removeProperty(mod, "host")
277		}
278		srcs, ok := getLiteralListProperty(mod, "srcs")
279		if !ok {
280			continue
281		}
282		if len(srcs.Values) == 0 {
283			continue
284		}
285		src, ok := srcs.Values[0].(*parser.String)
286		if !ok {
287			continue
288		}
289		switch filepath.Ext(src.Value) {
290		case ".jar":
291			renameProperty(mod, "srcs", "jars")
292
293		case ".aar":
294			renameProperty(mod, "srcs", "aars")
295			mod.Type = "android_library_import"
296
297			// An android_library_import doesn't get installed, so setting "installable = false" isn't supported
298			removeProperty(mod, "installable")
299		}
300	}
301
302	return nil
303}
304
305func rewriteCtsModuleTypes(f *Fixer) error {
306	for _, def := range f.tree.Defs {
307		mod, ok := def.(*parser.Module)
308		if !ok {
309			continue
310		}
311
312		if mod.Type != "cts_support_package" && mod.Type != "cts_package" &&
313			mod.Type != "cts_target_java_library" &&
314			mod.Type != "cts_host_java_library" {
315
316			continue
317		}
318
319		var defStr string
320		switch mod.Type {
321		case "cts_support_package":
322			mod.Type = "android_test"
323			defStr = "cts_support_defaults"
324		case "cts_package":
325			mod.Type = "android_test"
326			defStr = "cts_defaults"
327		case "cts_target_java_library":
328			mod.Type = "java_library"
329			defStr = "cts_defaults"
330		case "cts_host_java_library":
331			mod.Type = "java_library_host"
332			defStr = "cts_defaults"
333		}
334
335		defaults := &parser.Property{
336			Name: "defaults",
337			Value: &parser.List{
338				Values: []parser.Expression{
339					&parser.String{
340						Value: defStr,
341					},
342				},
343			},
344		}
345		mod.Properties = append(mod.Properties, defaults)
346	}
347
348	return nil
349}
350
351func rewriteIncorrectAndroidmkAndroidLibraries(f *Fixer) error {
352	for _, def := range f.tree.Defs {
353		mod, ok := def.(*parser.Module)
354		if !ok {
355			continue
356		}
357
358		if !strings.HasPrefix(mod.Type, "java_") && !strings.HasPrefix(mod.Type, "android_") {
359			continue
360		}
361
362		hasAndroidLibraries := hasNonEmptyLiteralListProperty(mod, "android_libs")
363		hasStaticAndroidLibraries := hasNonEmptyLiteralListProperty(mod, "android_static_libs")
364		hasResourceDirs := hasNonEmptyLiteralListProperty(mod, "resource_dirs")
365
366		if hasAndroidLibraries || hasStaticAndroidLibraries || hasResourceDirs {
367			if mod.Type == "java_library_static" || mod.Type == "java_library" {
368				mod.Type = "android_library"
369			}
370		}
371
372		if mod.Type == "java_import" && !hasStaticAndroidLibraries {
373			removeProperty(mod, "android_static_libs")
374		}
375
376		// These may conflict with existing libs and static_libs properties, but the
377		// mergeMatchingModuleProperties pass will fix it.
378		renameProperty(mod, "shared_libs", "libs")
379		renameProperty(mod, "android_libs", "libs")
380		renameProperty(mod, "android_static_libs", "static_libs")
381	}
382
383	return nil
384}
385
386// rewriteTestModuleTypes looks for modules that are identifiable as tests but for which Make doesn't have a separate
387// module class, and moves them to the appropriate Soong module type.
388func rewriteTestModuleTypes(f *Fixer) error {
389	for _, def := range f.tree.Defs {
390		mod, ok := def.(*parser.Module)
391		if !ok {
392			continue
393		}
394
395		if !strings.HasPrefix(mod.Type, "java_") && !strings.HasPrefix(mod.Type, "android_") {
396			continue
397		}
398
399		hasInstrumentationFor := hasNonEmptyLiteralStringProperty(mod, "instrumentation_for")
400		tags, _ := getLiteralListPropertyValue(mod, "tags")
401
402		var hasTestsTag bool
403		for _, tag := range tags {
404			if tag == "tests" {
405				hasTestsTag = true
406			}
407		}
408
409		isTest := hasInstrumentationFor || hasTestsTag
410
411		if isTest {
412			switch mod.Type {
413			case "android_app":
414				mod.Type = "android_test"
415			case "android_app_import":
416				mod.Type = "android_test_import"
417			case "java_library", "java_library_installable":
418				mod.Type = "java_test"
419			case "java_library_host":
420				mod.Type = "java_test_host"
421			}
422		}
423	}
424
425	return nil
426}
427
428// rewriteJavaStaticLibs rewrites java_library_static into java_library
429func rewriteJavaStaticLibs(f *Fixer) error {
430	for _, def := range f.tree.Defs {
431		mod, ok := def.(*parser.Module)
432		if !ok {
433			continue
434		}
435
436		if mod.Type == "java_library_static" {
437			mod.Type = "java_library"
438		}
439	}
440
441	return nil
442}
443
444// rewriteAndroidmkJavaLibs rewrites java_library_installable into java_library plus installable: true
445func rewriteAndroidmkJavaLibs(f *Fixer) error {
446	for _, def := range f.tree.Defs {
447		mod, ok := def.(*parser.Module)
448		if !ok {
449			continue
450		}
451
452		if mod.Type != "java_library_installable" {
453			continue
454		}
455
456		mod.Type = "java_library"
457
458		_, hasInstallable := mod.GetProperty("installable")
459		if !hasInstallable {
460			prop := &parser.Property{
461				Name: "installable",
462				Value: &parser.Bool{
463					Value: true,
464				},
465			}
466			mod.Properties = append(mod.Properties, prop)
467		}
468	}
469
470	return nil
471}
472
473// Helper function to get the value of a string-valued property in a given compound property.
474func getStringProperty(prop *parser.Property, fieldName string) string {
475	if propsAsMap, ok := prop.Value.(*parser.Map); ok {
476		for _, propField := range propsAsMap.Properties {
477			if fieldName == propField.Name {
478				if propFieldAsString, ok := propField.Value.(*parser.String); ok {
479					return propFieldAsString.Value
480				} else {
481					return ""
482				}
483			}
484		}
485	}
486	return ""
487}
488
489// Set the value of the given attribute to the error message
490func indicateAttributeError(mod *parser.Module, attributeName string, format string, a ...interface{}) error {
491	msg := fmt.Sprintf(format, a...)
492	mod.Properties = append(mod.Properties, &parser.Property{
493		Name:  attributeName,
494		Value: &parser.String{Value: "ERROR: " + msg},
495	})
496	return errors.New(msg)
497}
498
499// If a variable is LOCAL_MODULE, get its value from the 'name' attribute.
500// This handles the statement
501//    LOCAL_SRC_FILES := $(LOCAL_MODULE)
502// which occurs often.
503func resolveLocalModule(mod *parser.Module, val parser.Expression) parser.Expression {
504	if varLocalName, ok := val.(*parser.Variable); ok {
505		if varLocalName.Name == "LOCAL_MODULE" {
506			if v, ok := getLiteralStringProperty(mod, "name"); ok {
507				return v
508			}
509		}
510	}
511	return val
512}
513
514// etcPrebuiltModuleUpdate contains information on updating certain parts of a defined module such as:
515//    * changing the module type from prebuilt_etc to a different one
516//    * stripping the prefix of the install path based on the module type
517//    * appending additional boolean properties to the prebuilt module
518type etcPrebuiltModuleUpdate struct {
519	// The prefix of the install path defined in local_module_path. The prefix is removed from local_module_path
520	// before setting the 'filename' attribute.
521	prefix string
522
523	// There is only one prebuilt module type in makefiles. In Soong, there are multiple versions  of
524	// prebuilts based on local_module_path. By default, it is "prebuilt_etc" if modType is blank. An
525	// example is if the local_module_path contains $(TARGET_OUT)/usr/share, the module type is
526	// considered as prebuilt_usr_share.
527	modType string
528
529	// Additional boolean attributes to be added in the prebuilt module. Each added boolean attribute
530	// has a value of true.
531	flags []string
532}
533
534func (f etcPrebuiltModuleUpdate) update(m *parser.Module, path string) bool {
535	updated := false
536	if path == f.prefix {
537		updated = true
538	} else if trimmedPath := strings.TrimPrefix(path, f.prefix+"/"); trimmedPath != path {
539		m.Properties = append(m.Properties, &parser.Property{
540			Name:  "relative_install_path",
541			Value: &parser.String{Value: trimmedPath},
542		})
543		updated = true
544	}
545	if updated {
546		for _, flag := range f.flags {
547			m.Properties = append(m.Properties, &parser.Property{Name: flag, Value: &parser.Bool{Value: true, Token: "true"}})
548		}
549		if f.modType != "" {
550			m.Type = f.modType
551		}
552	}
553	return updated
554}
555
556var localModuleUpdate = map[string][]etcPrebuiltModuleUpdate{
557	"HOST_OUT":    {{prefix: "/etc", modType: "prebuilt_etc_host"}, {prefix: "/usr/share", modType: "prebuilt_usr_share_host"}},
558	"PRODUCT_OUT": {{prefix: "/system/etc"}, {prefix: "/vendor/etc", flags: []string{"proprietary"}}},
559	"TARGET_OUT": {{prefix: "/usr/share", modType: "prebuilt_usr_share"}, {prefix: "/fonts", modType: "prebuilt_font"},
560		{prefix: "/etc/firmware", modType: "prebuilt_firmware"}, {prefix: "/vendor/firmware", modType: "prebuilt_firmware", flags: []string{"proprietary"}},
561		{prefix: "/etc"}},
562	"TARGET_OUT_ETC":            {{prefix: "/firmware", modType: "prebuilt_firmware"}, {prefix: ""}},
563	"TARGET_OUT_PRODUCT":        {{prefix: "/etc", flags: []string{"product_specific"}}, {prefix: "/fonts", modType: "prebuilt_font", flags: []string{"product_specific"}}},
564	"TARGET_OUT_PRODUCT_ETC":    {{prefix: "", flags: []string{"product_specific"}}},
565	"TARGET_OUT_ODM":            {{prefix: "/etc", flags: []string{"device_specific"}}},
566	"TARGET_OUT_SYSTEM_EXT":     {{prefix: "/etc", flags: []string{"system_ext_specific"}}},
567	"TARGET_OUT_SYSTEM_EXT_ETC": {{prefix: "", flags: []string{"system_ext_specific"}}},
568	"TARGET_OUT_VENDOR":         {{prefix: "/etc", flags: []string{"proprietary"}}, {prefix: "/firmware", modType: "prebuilt_firmware", flags: []string{"proprietary"}}},
569	"TARGET_OUT_VENDOR_ETC":     {{prefix: "", flags: []string{"proprietary"}}},
570	"TARGET_RECOVERY_ROOT_OUT":  {{prefix: "/system/etc", flags: []string{"recovery"}}},
571}
572
573// rewriteAndroidPrebuiltEtc fixes prebuilt_etc rule
574func rewriteAndroidmkPrebuiltEtc(f *Fixer) error {
575	for _, def := range f.tree.Defs {
576		mod, ok := def.(*parser.Module)
577		if !ok {
578			continue
579		}
580
581		if mod.Type != "prebuilt_etc" && mod.Type != "prebuilt_etc_host" {
582			continue
583		}
584
585		// 'srcs' --> 'src' conversion
586		convertToSingleSource(mod, "src")
587
588		renameProperty(mod, "sub_dir", "relative_install_dir")
589
590		// The rewriter converts LOCAL_MODULE_PATH attribute into a struct attribute
591		// 'local_module_path'. Analyze its contents and create the correct sub_dir:,
592		// filename: and boolean attributes combination
593		const local_module_path = "local_module_path"
594		if prop_local_module_path, ok := mod.GetProperty(local_module_path); ok {
595			removeProperty(mod, local_module_path)
596			prefixVariableName := getStringProperty(prop_local_module_path, "var")
597			if moduleUpdates, ok := localModuleUpdate[prefixVariableName]; ok {
598				path := getStringProperty(prop_local_module_path, "fixed")
599				updated := false
600				for i := 0; i < len(moduleUpdates) && !updated; i++ {
601					updated = moduleUpdates[i].update(mod, path)
602				}
603				if !updated {
604					expectedPrefices := ""
605					sep := ""
606					for _, moduleUpdate := range moduleUpdates {
607						expectedPrefices += sep
608						sep = ", "
609						expectedPrefices += moduleUpdate.prefix
610					}
611					return indicateAttributeError(mod, "filename",
612						"LOCAL_MODULE_PATH value under $(%s) should start with %s", prefixVariableName, expectedPrefices)
613				}
614			} else {
615				return indicateAttributeError(mod, "filename", "Cannot handle $(%s) for the prebuilt_etc", prefixVariableName)
616			}
617		}
618	}
619	return nil
620}
621
622func rewriteAndroidTest(f *Fixer) error {
623	for _, def := range f.tree.Defs {
624		mod, ok := def.(*parser.Module)
625		if !(ok && mod.Type == "android_test") {
626			continue
627		}
628		// The rewriter converts LOCAL_MODULE_PATH attribute into a struct attribute
629		// 'local_module_path'. For the android_test module, it should be  $(TARGET_OUT_DATA_APPS),
630		// that is, `local_module_path: { var: "TARGET_OUT_DATA_APPS"}`
631		const local_module_path = "local_module_path"
632		if prop_local_module_path, ok := mod.GetProperty(local_module_path); ok {
633			removeProperty(mod, local_module_path)
634			prefixVariableName := getStringProperty(prop_local_module_path, "var")
635			path := getStringProperty(prop_local_module_path, "fixed")
636			if prefixVariableName == "TARGET_OUT_DATA_APPS" && path == "" {
637				continue
638			}
639			return indicateAttributeError(mod, "filename",
640				"Only LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) is allowed for the android_test")
641		}
642	}
643	return nil
644}
645
646func rewriteAndroidAppImport(f *Fixer) error {
647	for _, def := range f.tree.Defs {
648		mod, ok := def.(*parser.Module)
649		if !(ok && mod.Type == "android_app_import") {
650			continue
651		}
652		// 'srcs' --> 'apk' conversion
653		convertToSingleSource(mod, "apk")
654		// Handle special certificate value, "PRESIGNED".
655		if cert, ok := mod.GetProperty("certificate"); ok {
656			if certStr, ok := cert.Value.(*parser.String); ok {
657				if certStr.Value == "PRESIGNED" {
658					removeProperty(mod, "certificate")
659					prop := &parser.Property{
660						Name: "presigned",
661						Value: &parser.Bool{
662							Value: true,
663						},
664					}
665					mod.Properties = append(mod.Properties, prop)
666				}
667			}
668		}
669	}
670	return nil
671}
672
673func RewriteRuntimeResourceOverlay(f *Fixer) error {
674	for _, def := range f.tree.Defs {
675		mod, ok := def.(*parser.Module)
676		if !(ok && mod.Type == "runtime_resource_overlay") {
677			continue
678		}
679		// runtime_resource_overlays are always product specific in Make.
680		if _, ok := mod.GetProperty("product_specific"); !ok {
681			prop := &parser.Property{
682				Name: "product_specific",
683				Value: &parser.Bool{
684					Value: true,
685				},
686			}
687			mod.Properties = append(mod.Properties, prop)
688		}
689	}
690	return nil
691}
692
693// Removes library dependencies which are empty (and restricted from usage in Soong)
694func removeEmptyLibDependencies(f *Fixer) error {
695	emptyLibraries := []string{
696		"libhidltransport",
697		"libhwbinder",
698	}
699	relevantFields := []string{
700		"export_shared_lib_headers",
701		"export_static_lib_headers",
702		"static_libs",
703		"whole_static_libs",
704		"shared_libs",
705	}
706	for _, def := range f.tree.Defs {
707		mod, ok := def.(*parser.Module)
708		if !ok {
709			continue
710		}
711		for _, field := range relevantFields {
712			listValue, ok := getLiteralListProperty(mod, field)
713			if !ok {
714				continue
715			}
716			newValues := []parser.Expression{}
717			for _, v := range listValue.Values {
718				stringValue, ok := v.(*parser.String)
719				if !ok {
720					return fmt.Errorf("Expecting string for %s.%s fields", mod.Type, field)
721				}
722				if inList(stringValue.Value, emptyLibraries) {
723					continue
724				}
725				newValues = append(newValues, stringValue)
726			}
727			if len(newValues) == 0 && len(listValue.Values) != 0 {
728				removeProperty(mod, field)
729			} else {
730				listValue.Values = newValues
731			}
732		}
733	}
734	return nil
735}
736
737// Removes hidl_interface 'types' which are no longer needed
738func removeHidlInterfaceTypes(f *Fixer) error {
739	for _, def := range f.tree.Defs {
740		mod, ok := def.(*parser.Module)
741		if !(ok && mod.Type == "hidl_interface") {
742			continue
743		}
744		removeProperty(mod, "types")
745	}
746	return nil
747}
748
749func removeSoongConfigBoolVariable(f *Fixer) error {
750	found := map[string]bool{}
751	newDefs := make([]parser.Definition, 0, len(f.tree.Defs))
752	for _, def := range f.tree.Defs {
753		if mod, ok := def.(*parser.Module); ok && mod.Type == "soong_config_bool_variable" {
754			if name, ok := getLiteralStringPropertyValue(mod, "name"); ok {
755				found[name] = true
756			} else {
757				return fmt.Errorf("Found soong_config_bool_variable without a name")
758			}
759		} else {
760			newDefs = append(newDefs, def)
761		}
762	}
763	f.tree.Defs = newDefs
764
765	if len(found) == 0 {
766		return nil
767	}
768
769	return runPatchListMod(func(mod *parser.Module, buf []byte, patchList *parser.PatchList) error {
770		if mod.Type != "soong_config_module_type" {
771			return nil
772		}
773
774		variables, ok := getLiteralListProperty(mod, "variables")
775		if !ok {
776			return nil
777		}
778
779		boolValues := strings.Builder{}
780		empty := true
781		for _, item := range variables.Values {
782			nameValue, ok := item.(*parser.String)
783			if !ok {
784				empty = false
785				continue
786			}
787			if found[nameValue.Value] {
788				patchList.Add(item.Pos().Offset, item.End().Offset+2, "")
789
790				boolValues.WriteString(`"`)
791				boolValues.WriteString(nameValue.Value)
792				boolValues.WriteString(`",`)
793			} else {
794				empty = false
795			}
796		}
797		if empty {
798			*patchList = parser.PatchList{}
799
800			prop, _ := mod.GetProperty("variables")
801			patchList.Add(prop.Pos().Offset, prop.End().Offset+2, "")
802		}
803		if boolValues.Len() == 0 {
804			return nil
805		}
806
807		boolVariables, ok := getLiteralListProperty(mod, "bool_variables")
808		if ok {
809			patchList.Add(boolVariables.RBracePos.Offset, boolVariables.RBracePos.Offset, ","+boolValues.String())
810		} else {
811			patchList.Add(variables.RBracePos.Offset+2, variables.RBracePos.Offset+2,
812				fmt.Sprintf(`bool_variables: [%s],`, boolValues.String()))
813		}
814
815		return nil
816	})(f)
817
818	return nil
819}
820
821// Converts the default source list property, 'srcs', to a single source property with a given name.
822// "LOCAL_MODULE" reference is also resolved during the conversion process.
823func convertToSingleSource(mod *parser.Module, srcPropertyName string) {
824	if srcs, ok := mod.GetProperty("srcs"); ok {
825		if srcList, ok := srcs.Value.(*parser.List); ok {
826			removeProperty(mod, "srcs")
827			if len(srcList.Values) == 1 {
828				mod.Properties = append(mod.Properties,
829					&parser.Property{
830						Name:     srcPropertyName,
831						NamePos:  srcs.NamePos,
832						ColonPos: srcs.ColonPos,
833						Value:    resolveLocalModule(mod, srcList.Values[0])})
834			} else if len(srcList.Values) > 1 {
835				indicateAttributeError(mod, srcPropertyName, "LOCAL_SRC_FILES should contain at most one item")
836			}
837		} else if _, ok = srcs.Value.(*parser.Variable); ok {
838			removeProperty(mod, "srcs")
839			mod.Properties = append(mod.Properties,
840				&parser.Property{Name: srcPropertyName,
841					NamePos:  srcs.NamePos,
842					ColonPos: srcs.ColonPos,
843					Value:    resolveLocalModule(mod, srcs.Value)})
844		} else {
845			renameProperty(mod, "srcs", "apk")
846		}
847	}
848}
849
850func runPatchListMod(modFunc func(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error) func(*Fixer) error {
851	return func(f *Fixer) error {
852		// Make sure all the offsets are accurate
853		buf, err := f.reparse()
854		if err != nil {
855			return err
856		}
857
858		var patchlist parser.PatchList
859		for _, def := range f.tree.Defs {
860			mod, ok := def.(*parser.Module)
861			if !ok {
862				continue
863			}
864
865			err := modFunc(mod, buf, &patchlist)
866			if err != nil {
867				return err
868			}
869		}
870
871		newBuf := new(bytes.Buffer)
872		err = patchlist.Apply(bytes.NewReader(buf), newBuf)
873		if err != nil {
874			return err
875		}
876
877		// Save a copy of the buffer to print for errors below
878		bufCopy := append([]byte(nil), newBuf.Bytes()...)
879
880		newTree, err := parse(f.tree.Name, newBuf)
881		if err != nil {
882			return fmt.Errorf("Failed to parse: %v\nBuffer:\n%s", err, string(bufCopy))
883		}
884
885		f.tree = newTree
886
887		return nil
888	}
889}
890
891var commonPropertyPriorities = []string{
892	"name",
893	"defaults",
894	"device_supported",
895	"host_supported",
896	"installable",
897}
898
899func reorderCommonProperties(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error {
900	if len(mod.Properties) == 0 {
901		return nil
902	}
903
904	pos := mod.LBracePos.Offset + 1
905	stage := ""
906
907	for _, name := range commonPropertyPriorities {
908		idx := propertyIndex(mod.Properties, name)
909		if idx == -1 {
910			continue
911		}
912		if idx == 0 {
913			err := patchlist.Add(pos, pos, stage)
914			if err != nil {
915				return err
916			}
917			stage = ""
918
919			pos = mod.Properties[0].End().Offset + 1
920			mod.Properties = mod.Properties[1:]
921			continue
922		}
923
924		prop := mod.Properties[idx]
925		mod.Properties = append(mod.Properties[:idx], mod.Properties[idx+1:]...)
926
927		stage += string(buf[prop.Pos().Offset : prop.End().Offset+1])
928
929		err := patchlist.Add(prop.Pos().Offset, prop.End().Offset+2, "")
930		if err != nil {
931			return err
932		}
933	}
934
935	if stage != "" {
936		err := patchlist.Add(pos, pos, stage)
937		if err != nil {
938			return err
939		}
940	}
941
942	return nil
943}
944
945func removeTags(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error {
946	prop, ok := mod.GetProperty("tags")
947	if !ok {
948		return nil
949	}
950	list, ok := prop.Value.(*parser.List)
951	if !ok {
952		return nil
953	}
954
955	replaceStr := ""
956
957	for _, item := range list.Values {
958		str, ok := item.(*parser.String)
959		if !ok {
960			replaceStr += fmt.Sprintf("// ERROR: Unable to parse tag %q\n", item)
961			continue
962		}
963
964		switch str.Value {
965		case "optional":
966			continue
967		case "debug":
968			replaceStr += `// WARNING: Module tags are not supported in Soong.
969				// Add this module to PRODUCT_PACKAGES_DEBUG in your product file if you want to
970				// force installation for -userdebug and -eng builds.
971				`
972		case "eng":
973			replaceStr += `// WARNING: Module tags are not supported in Soong.
974				// Add this module to PRODUCT_PACKAGES_ENG in your product file if you want to
975				// force installation for -eng builds.
976				`
977		case "tests":
978			switch {
979			case strings.Contains(mod.Type, "cc_test"),
980				strings.Contains(mod.Type, "cc_library_static"),
981				strings.Contains(mod.Type, "java_test"),
982				mod.Type == "android_test",
983				mod.Type == "android_test_import":
984				continue
985			case strings.Contains(mod.Type, "cc_lib"):
986				replaceStr += `// WARNING: Module tags are not supported in Soong.
987					// To make a shared library only for tests, use the "cc_test_library" module
988					// type. If you don't use gtest, set "gtest: false".
989					`
990			case strings.Contains(mod.Type, "cc_bin"):
991				replaceStr += `// WARNING: Module tags are not supported in Soong.
992					// For native test binaries, use the "cc_test" module type. Some differences:
993					//  - If you don't use gtest, set "gtest: false"
994					//  - Binaries will be installed into /data/nativetest[64]/<name>/<name>
995					//  - Both 32 & 64 bit versions will be built (as appropriate)
996					`
997			case strings.Contains(mod.Type, "java_lib"):
998				replaceStr += `// WARNING: Module tags are not supported in Soong.
999					// For JUnit or similar tests, use the "java_test" module type. A dependency on
1000					// Junit will be added by default, if it is using some other runner, set "junit: false".
1001					`
1002			case mod.Type == "android_app":
1003				replaceStr += `// WARNING: Module tags are not supported in Soong.
1004					// For JUnit or instrumentataion app tests, use the "android_test" module type.
1005					`
1006			default:
1007				replaceStr += `// WARNING: Module tags are not supported in Soong.
1008					// In most cases, tests are now identified by their module type:
1009					// cc_test, java_test, python_test
1010					`
1011			}
1012		default:
1013			replaceStr += fmt.Sprintf("// WARNING: Unknown module tag %q\n", str.Value)
1014		}
1015	}
1016
1017	return patchlist.Add(prop.Pos().Offset, prop.End().Offset+2, replaceStr)
1018}
1019
1020func removePdkProperty(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error {
1021	prop, ok := mod.GetProperty("product_variables")
1022	if !ok {
1023		return nil
1024	}
1025	propMap, ok := prop.Value.(*parser.Map)
1026	if !ok {
1027		return nil
1028	}
1029	pdkProp, ok := propMap.GetProperty("pdk")
1030	if !ok {
1031		return nil
1032	}
1033	if len(propMap.Properties) > 1 {
1034		return patchlist.Add(pdkProp.Pos().Offset, pdkProp.End().Offset+2, "")
1035	}
1036	return patchlist.Add(prop.Pos().Offset, prop.End().Offset+2, "")
1037}
1038
1039func mergeMatchingModuleProperties(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error {
1040	return mergeMatchingProperties(&mod.Properties, buf, patchlist)
1041}
1042
1043func mergeMatchingProperties(properties *[]*parser.Property, buf []byte, patchlist *parser.PatchList) error {
1044	seen := make(map[string]*parser.Property)
1045	for i := 0; i < len(*properties); i++ {
1046		property := (*properties)[i]
1047		if prev, exists := seen[property.Name]; exists {
1048			err := mergeProperties(prev, property, buf, patchlist)
1049			if err != nil {
1050				return err
1051			}
1052			*properties = append((*properties)[:i], (*properties)[i+1:]...)
1053		} else {
1054			seen[property.Name] = property
1055			if mapProperty, ok := property.Value.(*parser.Map); ok {
1056				err := mergeMatchingProperties(&mapProperty.Properties, buf, patchlist)
1057				if err != nil {
1058					return err
1059				}
1060			}
1061		}
1062	}
1063	return nil
1064}
1065
1066func mergeProperties(a, b *parser.Property, buf []byte, patchlist *parser.PatchList) error {
1067	// The value of one of the properties may be a variable reference with no type assigned
1068	// Bail out in this case. Soong will notice duplicate entries and will tell to merge them.
1069	if _, isVar := a.Value.(*parser.Variable); isVar {
1070		return nil
1071	}
1072	if _, isVar := b.Value.(*parser.Variable); isVar {
1073		return nil
1074	}
1075	if a.Value.Type() != b.Value.Type() {
1076		return fmt.Errorf("type mismatch when merging properties %q: %s and %s", a.Name, a.Value.Type(), b.Value.Type())
1077	}
1078
1079	switch a.Value.Type() {
1080	case parser.StringType:
1081		return fmt.Errorf("conflicting definitions of string property %q", a.Name)
1082	case parser.ListType:
1083		return mergeListProperties(a, b, buf, patchlist)
1084	}
1085
1086	return nil
1087}
1088
1089func mergeListProperties(a, b *parser.Property, buf []byte, patchlist *parser.PatchList) error {
1090	aval, oka := a.Value.(*parser.List)
1091	bval, okb := b.Value.(*parser.List)
1092	if !oka || !okb {
1093		// Merging expressions not supported yet
1094		return nil
1095	}
1096
1097	s := string(buf[bval.LBracePos.Offset+1 : bval.RBracePos.Offset])
1098	if bval.LBracePos.Line != bval.RBracePos.Line {
1099		if s[0] != '\n' {
1100			panic("expected \n")
1101		}
1102		// If B is a multi line list, skip the first "\n" in case A already has a trailing "\n"
1103		s = s[1:]
1104	}
1105	if aval.LBracePos.Line == aval.RBracePos.Line {
1106		// A is a single line list with no trailing comma
1107		if len(aval.Values) > 0 {
1108			s = "," + s
1109		}
1110	}
1111
1112	err := patchlist.Add(aval.RBracePos.Offset, aval.RBracePos.Offset, s)
1113	if err != nil {
1114		return err
1115	}
1116	err = patchlist.Add(b.NamePos.Offset, b.End().Offset+2, "")
1117	if err != nil {
1118		return err
1119	}
1120
1121	return nil
1122}
1123
1124// removes from <items> every item present in <removals>
1125func filterExpressionList(patchList *parser.PatchList, items *parser.List, removals *parser.List) {
1126	writeIndex := 0
1127	for _, item := range items.Values {
1128		included := true
1129		for _, removal := range removals.Values {
1130			equal, err := parser.ExpressionsAreSame(item, removal)
1131			if err != nil {
1132				continue
1133			}
1134			if equal {
1135				included = false
1136				break
1137			}
1138		}
1139		if included {
1140			items.Values[writeIndex] = item
1141			writeIndex++
1142		} else {
1143			patchList.Add(item.Pos().Offset, item.End().Offset+2, "")
1144		}
1145	}
1146	items.Values = items.Values[:writeIndex]
1147}
1148
1149// Remove each modules[i].Properties[<legacyName>][j] that matches a modules[i].Properties[<canonicalName>][k]
1150func removeMatchingModuleListProperties(mod *parser.Module, patchList *parser.PatchList, canonicalName string, legacyName string) error {
1151	legacyProp, ok := mod.GetProperty(legacyName)
1152	if !ok {
1153		return nil
1154	}
1155	legacyList, ok := legacyProp.Value.(*parser.List)
1156	if !ok || len(legacyList.Values) == 0 {
1157		return nil
1158	}
1159	canonicalList, ok := getLiteralListProperty(mod, canonicalName)
1160	if !ok {
1161		return nil
1162	}
1163
1164	localPatches := parser.PatchList{}
1165	filterExpressionList(&localPatches, legacyList, canonicalList)
1166
1167	if len(legacyList.Values) == 0 {
1168		patchList.Add(legacyProp.Pos().Offset, legacyProp.End().Offset+2, "")
1169	} else {
1170		for _, p := range localPatches {
1171			patchList.Add(p.Start, p.End, p.Replacement)
1172		}
1173	}
1174
1175	return nil
1176}
1177
1178func hasNonEmptyLiteralListProperty(mod *parser.Module, name string) bool {
1179	list, found := getLiteralListProperty(mod, name)
1180	return found && len(list.Values) > 0
1181}
1182
1183func hasNonEmptyLiteralStringProperty(mod *parser.Module, name string) bool {
1184	s, found := getLiteralStringPropertyValue(mod, name)
1185	return found && len(s) > 0
1186}
1187
1188func getLiteralListProperty(mod *parser.Module, name string) (list *parser.List, found bool) {
1189	prop, ok := mod.GetProperty(name)
1190	if !ok {
1191		return nil, false
1192	}
1193	list, ok = prop.Value.(*parser.List)
1194	return list, ok
1195}
1196
1197func getLiteralListPropertyValue(mod *parser.Module, name string) (list []string, found bool) {
1198	listValue, ok := getLiteralListProperty(mod, name)
1199	if !ok {
1200		return nil, false
1201	}
1202	for _, v := range listValue.Values {
1203		stringValue, ok := v.(*parser.String)
1204		if !ok {
1205			return nil, false
1206		}
1207		list = append(list, stringValue.Value)
1208	}
1209
1210	return list, true
1211}
1212
1213func getLiteralStringProperty(mod *parser.Module, name string) (s *parser.String, found bool) {
1214	prop, ok := mod.GetProperty(name)
1215	if !ok {
1216		return nil, false
1217	}
1218	s, ok = prop.Value.(*parser.String)
1219	return s, ok
1220}
1221
1222func getLiteralStringPropertyValue(mod *parser.Module, name string) (s string, found bool) {
1223	stringValue, ok := getLiteralStringProperty(mod, name)
1224	if !ok {
1225		return "", false
1226	}
1227
1228	return stringValue.Value, true
1229}
1230
1231func getLiteralBoolProperty(mod *parser.Module, name string) (b *parser.Bool, found bool) {
1232	prop, ok := mod.GetProperty(name)
1233	if !ok {
1234		return nil, false
1235	}
1236	b, ok = prop.Value.(*parser.Bool)
1237	return b, ok
1238}
1239
1240func getLiteralBoolPropertyValue(mod *parser.Module, name string) (s bool, found bool) {
1241	boolValue, ok := getLiteralBoolProperty(mod, name)
1242	if !ok {
1243		return false, false
1244	}
1245
1246	return boolValue.Value, true
1247}
1248
1249func propertyIndex(props []*parser.Property, propertyName string) int {
1250	for i, prop := range props {
1251		if prop.Name == propertyName {
1252			return i
1253		}
1254	}
1255	return -1
1256}
1257
1258func renameProperty(mod *parser.Module, from, to string) {
1259	for _, prop := range mod.Properties {
1260		if prop.Name == from {
1261			prop.Name = to
1262		}
1263	}
1264}
1265
1266func removeProperty(mod *parser.Module, propertyName string) {
1267	newList := make([]*parser.Property, 0, len(mod.Properties))
1268	for _, prop := range mod.Properties {
1269		if prop.Name != propertyName {
1270			newList = append(newList, prop)
1271		}
1272	}
1273	mod.Properties = newList
1274}
1275
1276func inList(s string, list []string) bool {
1277	for _, v := range list {
1278		if s == v {
1279			return true
1280		}
1281	}
1282	return false
1283}
1284