Skip to content

Commit

Permalink
address issue #23 and issue #11 (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
nishanths authored Nov 6, 2021
1 parent 26eacc3 commit 1e8dc9d
Show file tree
Hide file tree
Showing 24 changed files with 776 additions and 398 deletions.
57 changes: 48 additions & 9 deletions checklist_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func TestChecklist(t *testing.T) {
"5": {"C"},
},
}
checkEnumMembersLiteral(t, "TestChecklist", em)

checkRemaining := func(t *testing.T, h *checklist, want map[string]struct{}) {
t.Helper()
Expand Down Expand Up @@ -140,11 +141,30 @@ func TestChecklist(t *testing.T) {
})

t.Run("blank identifier", func(t *testing.T) {
em := *em
em.Names = append([]string{}, em.Names...)
em.Names = append(em.Names, "_")
em := &enumMembers{
Names: []string{"A", "B", "C", "D", "E", "F", "G", "_"},
NameToValue: map[string]constantValue{
"A": "1",
"B": "2",
"C": "5",
"D": "2",
"E": "3",
"F": "2",
"G": "4",
"_": "0",
},
ValueToNames: map[constantValue][]string{
"0": {"_"},
"1": {"A"},
"2": {"B", "D", "F"},
"3": {"E"},
"4": {"G"},
"5": {"C"},
},
}
checkEnumMembersLiteral(t, "TestChecklist blank identifier", em)

checklist := makeChecklist(&em, enumPkg, true, nil)
checklist := makeChecklist(em, enumPkg, true, nil)
checkRemaining(t, checklist, map[string]struct{}{
"A": {},
"B": {},
Expand All @@ -157,12 +177,31 @@ func TestChecklist(t *testing.T) {
})

t.Run("include unexported", func(t *testing.T) {
em := *em
em.Names = append([]string{}, em.Names...)
em.Names = append(em.Names, "lowercase")
em := &enumMembers{
Names: []string{"A", "B", "C", "D", "E", "F", "G", "lowercase"},
NameToValue: map[string]constantValue{
"A": "1",
"B": "2",
"C": "5",
"D": "2",
"E": "3",
"F": "2",
"G": "4",
"lowercase": "42",
},
ValueToNames: map[constantValue][]string{
"1": {"A"},
"2": {"B", "D", "F"},
"3": {"E"},
"4": {"G"},
"5": {"C"},
"42": {"lowercase"},
},
}
checkEnumMembersLiteral(t, "TestChecklist lowercase", em)

t.Run("include", func(t *testing.T) {
checklist := makeChecklist(&em, enumPkg, true, nil)
checklist := makeChecklist(em, enumPkg, true, nil)
checkRemaining(t, checklist, map[string]struct{}{
"A": {},
"B": {},
Expand All @@ -176,7 +215,7 @@ func TestChecklist(t *testing.T) {
})

t.Run("don't include", func(t *testing.T) {
checklist := makeChecklist(&em, enumPkg, false, nil)
checklist := makeChecklist(em, enumPkg, false, nil)
checkRemaining(t, checklist, map[string]struct{}{
"A": {},
"B": {},
Expand Down
114 changes: 62 additions & 52 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,75 +5,85 @@ switch statements in Go code.
Definition of enum
The Go language spec does not provide an explicit definition for enums. For the
purpose of this analyzer, an enum type is a package-level named type whose
purpose of this analyzer, an enum type is a named (defined) type whose
underlying type is an integer (includes byte and rune), a float, or a string
type. An enum type must have associated with it one or more package-level
constants of the named type in the same package. These constants constitute the
enum's members.
type. An enum type must have associated with it one or more constants of the
named type. These constants constitute the enum's members.
In the code snippet below, Biome is an enum type with 3 members.
In the example below, Biome is an enum type with 3 members.
type Biome int
type Biome int
const (
Tundra Biome = 1
Savanna Biome = 2
Desert Biome = 3
)
const (
Tundra Biome = 1
Savanna Biome = 2
Desert Biome = 3
)
Enum member values may also be specified using iota; they don't necessarily have
to be explicit values, like in the snippet. Enum members don't necessarily have
to all be defined in the same const block.
For a constant to be an enum member, it must be declared in the same scope as
the enum type. That said, enum member constants don't necessarily have to all be
declared in the same const block. Enum member constant values may be specified
using iota or using explicit values (like in the example).
The analyzer's behavior is undefined for type aliases. This may change in the
future.
Definition of exhaustiveness
An enum switch statement is exhaustive if all of the enum's members are listed
in the switch statement's cases.
For an enum type defined in the same package as the switch statement, both
exported and unexported enum members must be present in order to consider the
switch statement exhaustive. For an enum type defined in an external package, it
is sufficient for just the exported enum members to be present in order to
consider the switch statement exhaustive.
Notable flags
The notable flags used by the analyzer are:
-default-signifies-exhaustive
If enabled, the presence of a "default" case in switch statements satisfies
exhaustiveness, even if all enum members are not listed.
-check-generated
If enabled, switch statements in generated Go source files are also checked.
Otherwise switch statements in generated files are ignored by default.
-ignore-enum-members <regex>
Specifies a regular expression; enum members matching the regular expression are
ignored. Ignored enum members don't have to be present in switch statements to
satisfy exhaustiveness. The regular expression is matched against enum member
names inclusive of the enum package import path, e.g.
"github.com/foo/bar.Tundra", where the enum package import path is
"github.com/foo/bar" and the enum member name is "Tundra".
exported and unexported enum members must be listed to satisfy exhaustiveness.
For an enum type defined in an external package, it is sufficient that only the
exported enum members be listed to satisfy exhaustiveness.
Flags
The notable flags used by the analyzer are below. All of these flags are
optional.
Flag name Type Default value
-check-generated bool false
-default-signifies-exhaustive bool false
-ignore-enum-members string (none)
-package-scope-only bool false
If the -check-generated flag is enabled, switch statements in generated Go
source files are also checked. Otherwise switch statements in generated files
are ignored by default.
If the default-signifies-exhaustive flag is enabled, the presence of a "default"
case in switch statements satisfies exhaustiveness, even if all enum members are
not listed. It is recommended that you do not enable this flag; enabling it
generally defeats the purpose of exhaustiveness checking.
The -ignore-enum-members flag specifies a regular expression, in the syntax
accepted by the Go regexp package. Enum members matching the regular expression
are ignored, i.e. these enum member names don't have to be listed in switch
statements to satisfy exhaustiveness. The specified regular expression is
matched against an enum member name inclusive of the enum package import path:
for example, "example.com/pkg.Tundra" where where the import path is
"example.com/pkg" and the enum member name is "Tundra".
If the -package-scope-only flag is enabled, the analyzer only finds enums
defined in package scope, and consequently only switch statements that switch
on package-scoped enums will be checked for exhaustiveness. By default, the
analyzer finds enums defined in all scopes, and checks switch statements that
switch on all these enums.
Skipping analysis
If the following comment:
//exhaustive:ignore
is associated with a switch statement, the analyzer skips inspection of the
switch statement and no diagnostics are reported. Note the lack of whitespace
To skip analysis of a specific switch statement, associate the following
comment with the switch statement. Note the lack of whitespace
between the comment marker ("//") and the comment text.
Additionally, no diagnostics are reported for switch statements in generated
files unless the -check-generated flag is enabled. See
https://golang.org/s/generatedcode for the definition of generated file.
//exhaustive:ignore
To ignore specific enum members, see the -ignore-enum-members flag.
Additionally, see the -ignore-enum-members flag, which can be used
to ignore specific enum members.
By default, the analyzer skips analysis of switch statements in generated
Go source files. Use the -check-generated flag to change this behavior.
See https://golang.org/s/generatedcode for the definition of generated file.
*/
package exhaustive
Loading

0 comments on commit 1e8dc9d

Please sign in to comment.