in warn/warn_cosmetic.go [295:384]
func unsortedDictItemsWarning(f *build.File) []*LinterFinding {
var findings []*LinterFinding
compareItems := func(item1, item2 *build.KeyValueExpr) bool {
key1 := item1.Key.(*build.StringExpr).Value
key2 := item2.Key.(*build.StringExpr).Value
// regular keys should precede private ones (start with "_")
if strings.HasPrefix(key1, "_") {
return strings.HasPrefix(key2, "_") && key1 < key2
}
if strings.HasPrefix(key2, "_") {
return true
}
// "//conditions:default" should always be the last
const conditionsDefault = "//conditions:default"
if key1 == conditionsDefault {
return false
} else if key2 == conditionsDefault {
return true
}
return key1 < key2
}
build.WalkPointers(f, func(expr *build.Expr, stack []build.Expr) {
dict, ok := (*expr).(*build.DictExpr)
mustSkipCheck := func(expr build.Expr) bool {
return edit.ContainsComments(expr, "@unsorted-dict-items")
}
if !ok || mustSkipCheck(dict) {
return
}
// do not process dictionaries nested within expressions that do not
// want dict items to be sorted
for i := len(stack) - 1; i >= 0; i-- {
if mustSkipCheck(stack[i]) {
return
}
}
var sortedItems []*build.KeyValueExpr
for _, item := range dict.List {
// include only string literal keys into consideration
if _, ok = item.Key.(*build.StringExpr); !ok {
continue
}
sortedItems = append(sortedItems, item)
}
// Fix
comp := func(i, j int) bool {
return compareItems(sortedItems[i], sortedItems[j])
}
var misplacedItems []*build.KeyValueExpr
for i := 1; i < len(sortedItems); i++ {
if comp(i, i-1) {
misplacedItems = append(misplacedItems, sortedItems[i])
}
}
if len(misplacedItems) == 0 {
// Already sorted
return
}
newDict := *dict
newDict.List = append([]*build.KeyValueExpr{}, dict.List...)
sort.SliceStable(sortedItems, comp)
sortedItemIndex := 0
for originalItemIndex := 0; originalItemIndex < len(dict.List); originalItemIndex++ {
item := dict.List[originalItemIndex]
if _, ok := item.Key.(*build.StringExpr); !ok {
continue
}
newDict.List[originalItemIndex] = sortedItems[sortedItemIndex]
sortedItemIndex++
}
for _, item := range misplacedItems {
findings = append(findings, makeLinterFinding(item,
"Dictionary items are out of their lexicographical order.",
LinterReplacement{expr, &newDict}))
}
return
})
return findings
}