Skip to content

Commit 1e8dc9d

Browse files
authored
address issue #23 and issue #11 (#24)
1 parent 26eacc3 commit 1e8dc9d

File tree

24 files changed

+776
-398
lines changed

24 files changed

+776
-398
lines changed

checklist_test.go

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ func TestChecklist(t *testing.T) {
2929
"5": {"C"},
3030
},
3131
}
32+
checkEnumMembersLiteral(t, "TestChecklist", em)
3233

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

142143
t.Run("blank identifier", func(t *testing.T) {
143-
em := *em
144-
em.Names = append([]string{}, em.Names...)
145-
em.Names = append(em.Names, "_")
144+
em := &enumMembers{
145+
Names: []string{"A", "B", "C", "D", "E", "F", "G", "_"},
146+
NameToValue: map[string]constantValue{
147+
"A": "1",
148+
"B": "2",
149+
"C": "5",
150+
"D": "2",
151+
"E": "3",
152+
"F": "2",
153+
"G": "4",
154+
"_": "0",
155+
},
156+
ValueToNames: map[constantValue][]string{
157+
"0": {"_"},
158+
"1": {"A"},
159+
"2": {"B", "D", "F"},
160+
"3": {"E"},
161+
"4": {"G"},
162+
"5": {"C"},
163+
},
164+
}
165+
checkEnumMembersLiteral(t, "TestChecklist blank identifier", em)
146166

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

159179
t.Run("include unexported", func(t *testing.T) {
160-
em := *em
161-
em.Names = append([]string{}, em.Names...)
162-
em.Names = append(em.Names, "lowercase")
180+
em := &enumMembers{
181+
Names: []string{"A", "B", "C", "D", "E", "F", "G", "lowercase"},
182+
NameToValue: map[string]constantValue{
183+
"A": "1",
184+
"B": "2",
185+
"C": "5",
186+
"D": "2",
187+
"E": "3",
188+
"F": "2",
189+
"G": "4",
190+
"lowercase": "42",
191+
},
192+
ValueToNames: map[constantValue][]string{
193+
"1": {"A"},
194+
"2": {"B", "D", "F"},
195+
"3": {"E"},
196+
"4": {"G"},
197+
"5": {"C"},
198+
"42": {"lowercase"},
199+
},
200+
}
201+
checkEnumMembersLiteral(t, "TestChecklist lowercase", em)
163202

164203
t.Run("include", func(t *testing.T) {
165-
checklist := makeChecklist(&em, enumPkg, true, nil)
204+
checklist := makeChecklist(em, enumPkg, true, nil)
166205
checkRemaining(t, checklist, map[string]struct{}{
167206
"A": {},
168207
"B": {},
@@ -176,7 +215,7 @@ func TestChecklist(t *testing.T) {
176215
})
177216

178217
t.Run("don't include", func(t *testing.T) {
179-
checklist := makeChecklist(&em, enumPkg, false, nil)
218+
checklist := makeChecklist(em, enumPkg, false, nil)
180219
checkRemaining(t, checklist, map[string]struct{}{
181220
"A": {},
182221
"B": {},

doc.go

Lines changed: 62 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5,75 +5,85 @@ switch statements in Go code.
55
Definition of enum
66
77
The Go language spec does not provide an explicit definition for enums. For the
8-
purpose of this analyzer, an enum type is a package-level named type whose
8+
purpose of this analyzer, an enum type is a named (defined) type whose
99
underlying type is an integer (includes byte and rune), a float, or a string
10-
type. An enum type must have associated with it one or more package-level
11-
constants of the named type in the same package. These constants constitute the
12-
enum's members.
10+
type. An enum type must have associated with it one or more constants of the
11+
named type. These constants constitute the enum's members.
1312
14-
In the code snippet below, Biome is an enum type with 3 members.
13+
In the example below, Biome is an enum type with 3 members.
1514
16-
type Biome int
15+
type Biome int
1716
18-
const (
19-
Tundra Biome = 1
20-
Savanna Biome = 2
21-
Desert Biome = 3
22-
)
17+
const (
18+
Tundra Biome = 1
19+
Savanna Biome = 2
20+
Desert Biome = 3
21+
)
2322
24-
Enum member values may also be specified using iota; they don't necessarily have
25-
to be explicit values, like in the snippet. Enum members don't necessarily have
26-
to all be defined in the same const block.
23+
For a constant to be an enum member, it must be declared in the same scope as
24+
the enum type. That said, enum member constants don't necessarily have to all be
25+
declared in the same const block. Enum member constant values may be specified
26+
using iota or using explicit values (like in the example).
27+
28+
The analyzer's behavior is undefined for type aliases. This may change in the
29+
future.
2730
2831
Definition of exhaustiveness
2932
3033
An enum switch statement is exhaustive if all of the enum's members are listed
3134
in the switch statement's cases.
3235
3336
For an enum type defined in the same package as the switch statement, both
34-
exported and unexported enum members must be present in order to consider the
35-
switch statement exhaustive. For an enum type defined in an external package, it
36-
is sufficient for just the exported enum members to be present in order to
37-
consider the switch statement exhaustive.
38-
39-
Notable flags
40-
41-
The notable flags used by the analyzer are:
42-
43-
-default-signifies-exhaustive
44-
45-
If enabled, the presence of a "default" case in switch statements satisfies
46-
exhaustiveness, even if all enum members are not listed.
47-
48-
-check-generated
49-
50-
If enabled, switch statements in generated Go source files are also checked.
51-
Otherwise switch statements in generated files are ignored by default.
52-
53-
-ignore-enum-members <regex>
54-
55-
Specifies a regular expression; enum members matching the regular expression are
56-
ignored. Ignored enum members don't have to be present in switch statements to
57-
satisfy exhaustiveness. The regular expression is matched against enum member
58-
names inclusive of the enum package import path, e.g.
59-
"github.com/foo/bar.Tundra", where the enum package import path is
60-
"github.com/foo/bar" and the enum member name is "Tundra".
37+
exported and unexported enum members must be listed to satisfy exhaustiveness.
38+
For an enum type defined in an external package, it is sufficient that only the
39+
exported enum members be listed to satisfy exhaustiveness.
40+
41+
Flags
42+
43+
The notable flags used by the analyzer are below. All of these flags are
44+
optional.
45+
46+
Flag name Type Default value
47+
-check-generated bool false
48+
-default-signifies-exhaustive bool false
49+
-ignore-enum-members string (none)
50+
-package-scope-only bool false
51+
52+
If the -check-generated flag is enabled, switch statements in generated Go
53+
source files are also checked. Otherwise switch statements in generated files
54+
are ignored by default.
55+
56+
If the default-signifies-exhaustive flag is enabled, the presence of a "default"
57+
case in switch statements satisfies exhaustiveness, even if all enum members are
58+
not listed. It is recommended that you do not enable this flag; enabling it
59+
generally defeats the purpose of exhaustiveness checking.
60+
61+
The -ignore-enum-members flag specifies a regular expression, in the syntax
62+
accepted by the Go regexp package. Enum members matching the regular expression
63+
are ignored, i.e. these enum member names don't have to be listed in switch
64+
statements to satisfy exhaustiveness. The specified regular expression is
65+
matched against an enum member name inclusive of the enum package import path:
66+
for example, "example.com/pkg.Tundra" where where the import path is
67+
"example.com/pkg" and the enum member name is "Tundra".
68+
69+
If the -package-scope-only flag is enabled, the analyzer only finds enums
70+
defined in package scope, and consequently only switch statements that switch
71+
on package-scoped enums will be checked for exhaustiveness. By default, the
72+
analyzer finds enums defined in all scopes, and checks switch statements that
73+
switch on all these enums.
6174
6275
Skipping analysis
6376
64-
If the following comment:
65-
66-
//exhaustive:ignore
67-
68-
is associated with a switch statement, the analyzer skips inspection of the
69-
switch statement and no diagnostics are reported. Note the lack of whitespace
77+
To skip analysis of a specific switch statement, associate the following
78+
comment with the switch statement. Note the lack of whitespace
7079
between the comment marker ("//") and the comment text.
7180
72-
Additionally, no diagnostics are reported for switch statements in generated
73-
files unless the -check-generated flag is enabled. See
74-
https://golang.org/s/generatedcode for the definition of generated file.
81+
//exhaustive:ignore
82+
83+
To ignore specific enum members, see the -ignore-enum-members flag.
7584
76-
Additionally, see the -ignore-enum-members flag, which can be used
77-
to ignore specific enum members.
85+
By default, the analyzer skips analysis of switch statements in generated
86+
Go source files. Use the -check-generated flag to change this behavior.
87+
See https://golang.org/s/generatedcode for the definition of generated file.
7888
*/
7989
package exhaustive

0 commit comments

Comments
 (0)