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