Skip to content

Commit

Permalink
use AST order to report missing names (#44)
Browse files Browse the repository at this point in the history
  • Loading branch information
maratori committed Jul 24, 2022
1 parent b974ba3 commit d513b10
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 15 deletions.
28 changes: 19 additions & 9 deletions switch.go
Expand Up @@ -5,7 +5,6 @@ import (
"go/ast"
"go/types"
"regexp"
"sort"
"strings"

"golang.org/x/tools/go/analysis"
Expand Down Expand Up @@ -262,19 +261,30 @@ func analyzeCaseClauseExpr(e ast.Expr, info *types.Info, found func(val constant

// diagnosticMissingMembers constructs the list of missing enum members,
// suitable for use in a reported diagnostic message.
// Order is the same as in enumMembers.Names.
func diagnosticMissingMembers(missingMembers map[string]struct{}, em enumMembers) []string {
missingByConstVal := make(map[constantValue][]string) // missing members, keyed by constant value.
for m := range missingMembers {
val := em.NameToValue[m]
missingByConstVal[val] = append(missingByConstVal[val], m)
missingNamesGroupedByValue := make([][]string, len(em.Names)) // empty groups will be filtered out later
firstIndex := make(map[constantValue]int, len(em.ValueToNames))
for i, name := range em.Names {
value := em.NameToValue[name]
j, ok := firstIndex[value]
if !ok {
firstIndex[value] = i
j = i
}

if _, missing := missingMembers[name]; missing {
missingNamesGroupedByValue[j] = append(missingNamesGroupedByValue[j], name)
}
}

var out []string
for _, names := range missingByConstVal {
sort.Strings(names)
out := make([]string, 0, len(missingMembers))
for _, names := range missingNamesGroupedByValue {
if len(names) == 0 {
continue
}
out = append(out, strings.Join(names, "|"))
}
sort.Strings(out)
return out
}

Expand Down
6 changes: 3 additions & 3 deletions switch_test.go
Expand Up @@ -60,7 +60,7 @@ func TestDiagnosticMissingMembers(t *testing.T) {

t.Run("missing some: unique or unknown values", func(t *testing.T) {
got := diagnosticMissingMembers(map[string]struct{}{"Yamuna": {}, "Kaveri": {}}, em)
want := []string{"Kaveri", "Yamuna"}
want := []string{"Yamuna", "Kaveri"}
if !reflect.DeepEqual(want, got) {
t.Errorf("want %v, got %v", want, got)
}
Expand All @@ -75,7 +75,7 @@ func TestDiagnosticMissingMembers(t *testing.T) {

t.Run("missing all", func(t *testing.T) {
got := diagnosticMissingMembers(map[string]struct{}{"Ganga": {}, "Kaveri": {}, "Yamuna": {}, "Unspecified": {}}, em)
want := []string{"Ganga|Unspecified", "Kaveri", "Yamuna"}
want := []string{"Ganga|Unspecified", "Yamuna", "Kaveri"}
if !reflect.DeepEqual(want, got) {
t.Errorf("want %v, got %v", want, got)
}
Expand Down Expand Up @@ -114,7 +114,7 @@ func TestMakeDiagnostic(t *testing.T) {
want := analysis.Diagnostic{
Pos: 1,
End: 11,
Message: "missing cases in switch of type enumpkg.Biome: Desert, Savanna",
Message: "missing cases in switch of type enumpkg.Biome: Savanna, Desert",
}
if !reflect.DeepEqual(want, got) {
t.Errorf("want %+v, got %+v", want, got)
Expand Down
2 changes: 1 addition & 1 deletion testdata/src/duplicate-enum-value/otherpkg/otherpkg.go
Expand Up @@ -37,7 +37,7 @@ func _r() {
}

var s d.State
switch s { // want "^missing cases in switch of type duplicateenumvalue.State: DefaultState\\|TamilNadu, Kerala$"
switch s { // want "^missing cases in switch of type duplicateenumvalue.State: TamilNadu\\|DefaultState, Kerala$"
case d.Karnataka:
}
}
Expand Down
2 changes: 1 addition & 1 deletion testdata/src/general/x/general.go
Expand Up @@ -162,7 +162,7 @@ func _q() {
fi, err := os.Lstat(".")
fmt.Println(err)

switch fi.Mode() { // want "^missing cases in switch of type fs.FileMode: ModeDevice, ModePerm, ModeSetgid, ModeSetuid, ModeType$"
switch fi.Mode() { // want "^missing cases in switch of type fs.FileMode: ModeDevice, ModeSetuid, ModeSetgid, ModeType, ModePerm$"
case os.ModeDir:
case os.ModeAppend:
case os.ModeExclusive:
Expand Down
2 changes: 1 addition & 1 deletion testdata/src/ignore-enum-member/same_value.go
Expand Up @@ -13,6 +13,6 @@ const (
// The member Standard, though it has the same constant value as User, must
// still be reported in the diagnostic.
func _c(a Access) {
switch a { // want "^missing cases in switch of type Access: Group, Standard$"
switch a { // want "^missing cases in switch of type Access: Standard, Group$"
}
}

0 comments on commit d513b10

Please sign in to comment.