Skip to content

Commit

Permalink
support for checking values whose type is a type parameter
Browse files Browse the repository at this point in the history
Type parameters

This commit implements support for checking exhaustiveness when the
value's type is a type parameter. The defined behavior is (copied from
package documentation):

    A switch statement that switches on a value whose type is a type
    parameter is checked for exhaustiveness iff each type element in the
    type constraint is an enum type and shares the same underlying basic
    kind. For example, the following switch statement will be checked,
    assuming M, N, and O are enum types with the same underlying basic
    kind. To satisfy exhaustiveness, all enum members for each of the
    types M, N, and O must be listed in the switch statement's cases.

        func bar[T M | I](v T) {
            switch v {
            }
        }
        type I interface{ N | J }
        type J interface{ O }

Exhaustive supports go1.14 and later, but type parameters are only
supported from go1.18 or later. Symbols in e.g. package go/types related
to type parameters are not available in go version earlier than go1.18.
So source files, when necessary, are split into *_pre_go118.go and
*_go118.go portions.

The majority of the implementation is in common_go118.go.

Spurious diagnostic for type conversion (issue 42)

This commit also fixes spurious diagnostics that were produced when the
case clause expressions involved type conversions. See the relevant func
stripTypeConversions, and tests in testdata/general/x/typeconv.go.

Diagnostic format changes

The output diagnostics now always include the package name for the enum
type and the enum members. (Previously the package name was omitted if
the symbols were in the same package as the offending source code.) This
change was motivated by consistency: With type parameters, a value's
type in a switch statement tag can be composed of multiple enum types,
possibly from different packages. In such scenarios, consistently using
the package name for all of them makes for more comprehensible
diagnostics.

Many testdata lines are touched due to the diagnostic format change.

Internal changes

* Flag parsing: Parsing of the -check flag is now handled by a new
  stringsFlag type that implements flag.Value.
* Shared code: Code that was shared (or should have been shared between)
  switch.go and maps.go now lives in common.go.
* The enumMembers fact type has an additional NameToPos field.
* The checklist type is updated to account for the fact that enum types
  can possibly be from multiple packages.
* The Makefile now includes a "cover" target (HTML test coverage report)
  and an "all" target (runs build, vet, test).
* The new "member" type represents the concept of an enum member in
  switch.go and map.go API, replacing the prev. largely string-based
  API.

GitHub workflows

The workflow now runs tests for go versions < 1.16.

Fixes #31, #42
  • Loading branch information
nishanths committed Nov 26, 2022
1 parent 9860956 commit 0b09290
Show file tree
Hide file tree
Showing 60 changed files with 1,973 additions and 1,266 deletions.
37 changes: 37 additions & 0 deletions .github/workflows/all.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
on: [push, pull_request]
name: all
jobs:
main:
strategy:
matrix:
go-version: [1.14, 1.16, 1.18, 1.x]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: install go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go-version }}

- name: checkout code
uses: actions/checkout@v2

- name: build
run: make build

# for earlier go versions, staticcheck build fails due to
# ../../../go/pkg/mod/honnef.co/go/[email protected]/go/ir/builder.go:36:2: //go:build comment without // +build comment
- name: install vet tools (>= go1.17)
if: ${{ matrix.go-version >= '1.17' }}
run: |
go install github.com/nishanths/exhaustive/cmd/exhaustive@latest
go install github.com/gordonklaus/ineffassign@latest
go install github.com/kisielk/errcheck@latest
go install honnef.co/go/tools/cmd/staticcheck@latest
- name: vet (>= go1.17)
if: ${{ matrix.go-version >= '1.17' }}
run: make vet

- name: test
run: make test
29 changes: 0 additions & 29 deletions .github/workflows/main.yml

This file was deleted.

13 changes: 12 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,26 +1,37 @@
.PHONY: default
default: build

.PHONY: all
all: build vet test

.PHONY: build
build:
go build ./...
go build ./cmd/exhaustive

.PHONY: test
test:
go test -cover ./...
go test ./...

.PHONY: cover
cover:
go test -cover -coverprofile=coverage.out ./...
go tool cover -html=coverage.out

.PHONY: install-vet
install-vet:
go install github.com/nishanths/exhaustive/cmd/exhaustive@latest
go install github.com/gordonklaus/ineffassign@latest
go install github.com/kisielk/errcheck@latest
go install honnef.co/go/tools/cmd/staticcheck@latest

.PHONY: vet
vet:
go vet ./...
exhaustive ./...
ineffassign ./...
errcheck ./...
staticcheck -checks="inherit,-S1034" ./...

.PHONY: upgrade-deps
upgrade-deps:
Expand Down
57 changes: 30 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,35 @@
# exhaustive [![Godoc][godoc-svg]][repo]

Checks exhaustiveness of enum switch statements in Go source code.
Package exhaustive defines an analyzer that checks exhaustiveness of switch
statements of enum-like constants in Go source code. The analyzer can be
configured to additionally check exhaustiveness of map keys for map literals
whose key type is enum-like.

```
go install github.com/nishanths/exhaustive/cmd/exhaustive@latest
```
For documentation on the flags, the definition of enum, and the definition of
exhaustiveness, see [pkg.go.dev][godoc-doc]. For a changelog, see
[CHANGELOG][changelog] in the GitHub wiki.

For documentation on flags, the definition of enum, and the definition
of exhaustiveness, see [pkg.go.dev][godoc-doc]. For a changelog, see
[CHANGELOG][changelog] in the wiki.
The exported `analysis.Analyzer` uses the
[`golang.org/x/tools/go/analysis`][xanalysis] API. This should make it
possible to integrate `exhaustive` in your own analysis driver program.

The program may additionally be configured to check for exhaustiveness
of map literals with enum key types. See examples below.
## Install

The package provides an `analysis.Analyzer` value that follows the
guidelines in the [`golang.org/x/tools/go/analysis`][xanalysis] package.
This should make it possible to integrate `exhaustive` with your own
analysis driver programs.
Install the command line program:

## Bugs
```
go install github.com/nishanths/exhaustive/cmd/exhaustive@latest
```

## Usage

`exhaustive` does not report missing cases in a switch statement that
switches on a type-parameterized type. See [this issue][issue-typeparam]
for details.
```
exhaustive [flags] [packages]
```

## Examples
## Example

Given the enum
Given the enum:

```go
package token
Expand All @@ -42,7 +45,7 @@ const (
)
```

and code that switches on the enum
and code that switches on the enum:

```go
package calc
Expand All @@ -65,28 +68,28 @@ var m = map[token.Token]string{
}
```

running `exhaustive` with default options will print
running `exhaustive` with default options will print:

```
% exhaustive path/to/pkg/calc
% exhaustive
calc.go:6:2: missing cases in switch of type token.Token: Quotient, Remainder
%
```

To additionally check exhaustiveness of map literals, use
`-check=switch,map`.
To additionally check exhaustiveness of map literal keys, use
`-check=switch,map`:

```
% exhaustive -check=switch,map path/to/pkg/calc
% exhaustive -check=switch,map
calc.go:6:2: missing cases in switch of type token.Token: Quotient, Remainder
calc.go:14:9: missing keys in map of key type token.Token: Quotient, Remainder
%
```

## Contributing

Issues and pull requests are welcome. Before making a substantial
change please discuss it in an issue.
Issues and changes are welcome. Please discuss substantial changes
in an issue first.

[repo]: https://pkg.go.dev/github.com/nishanths/exhaustive
[godoc-svg]: https://pkg.go.dev/badge/github.com/nishanths/exhaustive.svg
Expand Down
58 changes: 0 additions & 58 deletions checklist.go

This file was deleted.

19 changes: 4 additions & 15 deletions cmd/exhaustive/exhaustive.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,9 @@
// Command exhaustive checks exhaustiveness of enum switch statements.
// Command exhaustive is a command line interface for the exhaustive
// package at github.com/nishanths/exhaustive.
//
// Usage
// # Usage
//
// The command line usage is:
//
// exhaustive [flags] [packages]
//
// The program checks exhaustiveness of enum switch statements found in the
// specified packages. The enums required for the analysis don't necessarily
// have to be declared in the specified packages.
//
// For more about specifying packages, see 'go help packages'.
//
// For help, run 'exhaustive -h'.
//
// For more documentation, see https://godocs.io/github.com/nishanths/exhaustive.
// exhaustive [flags] [packages]
package main

import (
Expand Down
Loading

0 comments on commit 0b09290

Please sign in to comment.