diff options
Diffstat (limited to 'bpfix/bpfix/bpfix.go')
-rw-r--r-- | bpfix/bpfix/bpfix.go | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go index 4300e81b..4ab42a4e 100644 --- a/bpfix/bpfix/bpfix.go +++ b/bpfix/bpfix/bpfix.go @@ -26,11 +26,27 @@ import ( "github.com/google/blueprint/parser" ) +// Reformat takes a blueprint file as a string and returns a formatted version +func Reformat(input string) (string, error) { + tree, err := parse("<string>", bytes.NewBufferString(input)) + if err != nil { + return "", err + } + + res, err := parser.Print(tree) + if err != nil { + return "", err + } + + return string(res), nil +} + // A FixRequest specifies the details of which fixes to apply to an individual file // A FixRequest doesn't specify whether to do a dry run or where to write the results; that's in cmd/bpfix.go type FixRequest struct { simplifyKnownRedundantVariables bool rewriteIncorrectAndroidmkPrebuilts bool + mergeMatchingModuleProperties bool } func NewFixRequest() FixRequest { @@ -41,6 +57,7 @@ func (r FixRequest) AddAll() (result FixRequest) { result = r result.simplifyKnownRedundantVariables = true result.rewriteIncorrectAndroidmkPrebuilts = true + result.mergeMatchingModuleProperties = true return result } @@ -136,6 +153,13 @@ func (f *Fixer) fixTreeOnce(config FixRequest) error { return err } } + + if config.mergeMatchingModuleProperties { + err := f.mergeMatchingModuleProperties() + if err != nil { + return err + } + } return nil } @@ -179,6 +203,115 @@ func (f *Fixer) rewriteIncorrectAndroidmkPrebuilts() error { return nil } +func (f *Fixer) mergeMatchingModuleProperties() error { + // Make sure all the offsets are accurate + buf, err := f.reparse() + if err != nil { + return err + } + + var patchlist parser.PatchList + for _, def := range f.tree.Defs { + mod, ok := def.(*parser.Module) + if !ok { + continue + } + + err := mergeMatchingProperties(&mod.Properties, buf, &patchlist) + if err != nil { + return err + } + } + + newBuf := new(bytes.Buffer) + err = patchlist.Apply(bytes.NewReader(buf), newBuf) + if err != nil { + return err + } + + newTree, err := parse(f.tree.Name, newBuf) + if err != nil { + return err + } + + f.tree = newTree + + return nil +} + +func mergeMatchingProperties(properties *[]*parser.Property, buf []byte, patchlist *parser.PatchList) error { + seen := make(map[string]*parser.Property) + for i := 0; i < len(*properties); i++ { + property := (*properties)[i] + if prev, exists := seen[property.Name]; exists { + err := mergeProperties(prev, property, buf, patchlist) + if err != nil { + return err + } + *properties = append((*properties)[:i], (*properties)[i+1:]...) + } else { + seen[property.Name] = property + if mapProperty, ok := property.Value.(*parser.Map); ok { + err := mergeMatchingProperties(&mapProperty.Properties, buf, patchlist) + if err != nil { + return err + } + } + } + } + return nil +} + +func mergeProperties(a, b *parser.Property, buf []byte, patchlist *parser.PatchList) error { + if a.Value.Type() != b.Value.Type() { + return fmt.Errorf("type mismatch when merging properties %q: %s and %s", a.Name, a.Value.Type(), b.Value.Type()) + } + + switch a.Value.Type() { + case parser.StringType: + return fmt.Errorf("conflicting definitions of string property %q", a.Name) + case parser.ListType: + return mergeListProperties(a, b, buf, patchlist) + } + + return nil +} + +func mergeListProperties(a, b *parser.Property, buf []byte, patchlist *parser.PatchList) error { + aval, oka := a.Value.(*parser.List) + bval, okb := b.Value.(*parser.List) + if !oka || !okb { + // Merging expressions not supported yet + return nil + } + + s := string(buf[bval.LBracePos.Offset+1 : bval.RBracePos.Offset]) + if bval.LBracePos.Line != bval.RBracePos.Line { + if s[0] != '\n' { + panic("expected \n") + } + // If B is a multi line list, skip the first "\n" in case A already has a trailing "\n" + s = s[1:] + } + if aval.LBracePos.Line == aval.RBracePos.Line { + // A is a single line list with no trailing comma + if len(aval.Values) > 0 { + s = "," + s + } + } + + err := patchlist.Add(aval.RBracePos.Offset, aval.RBracePos.Offset, s) + if err != nil { + return err + } + err = patchlist.Add(b.NamePos.Offset, b.End().Offset+2, "") + if err != nil { + return err + } + + return nil +} + // removes from <items> every item present in <removals> func filterExpressionList(items *parser.List, removals *parser.List) { writeIndex := 0 |