Skip to content

Commit

Permalink
Allow applying ignore directives to type declarations
Browse files Browse the repository at this point in the history
Adds support for the syntax:

```go
//exhaustive:ignore
type DeclTypeIgnoredEnum int

const (
	DeclTypeIgnoredMamberA DeclTypeIgnoredEnum = 1
	DeclTypeIgnoredMamberB DeclTypeIgnoredEnum = 2
)
```
  • Loading branch information
iwahbe committed Apr 19, 2024
1 parent d9dc665 commit ce37a1d
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 23 deletions.
57 changes: 49 additions & 8 deletions enum.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,24 +67,30 @@ func (em *enumMembers) factString() string {
func findEnums(pass *analysis.Pass, pkgScopeOnly bool, pkg *types.Package, inspect *inspector.Inspector, info *types.Info) map[enumType]enumMembers {
result := make(map[enumType]enumMembers)

ignoredTypes := findIgnoredTypes(pass, inspect, info)

inspect.Preorder([]ast.Node{&ast.GenDecl{}}, func(n ast.Node) {
gen := n.(*ast.GenDecl)
if gen.Tok != token.CONST {
return
}

dirs, err := parseDirectives([]*ast.CommentGroup{gen.Doc})
if err != nil {
pass.Report(makeInvalidDirectiveDiagnostic(gen, err))
return
}

if dirs.has(ignoreDirective) {
if isIgnoreDecl(pass, gen.Doc) {
return
}

for _, s := range gen.Specs {
for _, name := range s.(*ast.ValueSpec).Names {
s := s.(*ast.ValueSpec)
if isIgnoreDecl(pass, s.Doc) {
return
}

for _, name := range s.Names {

if _, ignored := ignoredTypes[info.Defs[name].Type()]; ignored {
continue
}

enumTyp, memberName, val, ok := possibleEnumMember(name, info)
if !ok {
continue
Expand Down Expand Up @@ -152,6 +158,32 @@ func possibleEnumMember(constName *ast.Ident, info *types.Info) (et enumType, na
return enumType{tn}, obj.Name(), determineConstVal(constName, info), true
}

func findIgnoredTypes(pass *analysis.Pass, inspect *inspector.Inspector, info *types.Info) map[types.Type]struct{} {
ignoredTypes := map[types.Type]struct{}{}

inspect.Preorder([]ast.Node{&ast.GenDecl{}}, func(n ast.Node) {
gen := n.(*ast.GenDecl)
if gen.Tok != token.TYPE {
return
}

doIgnoreDecl := isIgnoreDecl(pass, gen.Doc)

for _, s := range gen.Specs {
t := s.(*ast.TypeSpec)

doIgnoreSpec := doIgnoreDecl || isIgnoreDecl(pass, t.Doc)
if !doIgnoreSpec {
continue
}

ignoredTypes[info.Defs[t.Name].Type()] = struct{}{}
}
})

return ignoredTypes
}

func determineConstVal(name *ast.Ident, info *types.Info) constantValue {
c := info.ObjectOf(name).(*types.Const)
return constantValue(c.Val().ExactString())
Expand All @@ -169,6 +201,15 @@ func validBasic(basic *types.Basic) bool {
return false
}

func isIgnoreDecl(pass *analysis.Pass, doc *ast.CommentGroup) bool {
dirs, err := parseDirectives([]*ast.CommentGroup{doc})
if err != nil {
pass.Report(makeInvalidDirectiveDiagnostic(doc, err))
return false
}
return dirs.has(ignoreDirective)
}

// validNamedBasic returns whether the type t is a named type whose underlying
// type is a valid basic type to form an enum. A type that passes this check
// meets the definition of an enum type.
Expand Down
40 changes: 32 additions & 8 deletions enum_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,27 +367,51 @@ func checkEnums(t *testing.T, got []checkEnum, pkgOnly bool) {
},
}},
{"DeclGroupIgnoredEnum", enumMembers{
[]string{"DeclGroupIgnoredMamberC"},
[]string{"DeclGroupIgnoredMemberC"},
map[string]token.Pos{
"DeclGroupIgnoredMamberC": 0,
"DeclGroupIgnoredMemberC": 0,
},
map[string]constantValue{
"DeclGroupIgnoredMamberC": `3`,
"DeclGroupIgnoredMemberC": `3`,
},
map[constantValue][]string{
`3`: {"DeclGroupIgnoredMamberC"},
`3`: {"DeclGroupIgnoredMemberC"},
},
}},
{"DeclIgnoredEnum", enumMembers{
[]string{"DeclIgnoredMamberB"},
[]string{"DeclIgnoredMemberB"},
map[string]token.Pos{
"DeclIgnoredMamberB": 0,
"DeclIgnoredMemberB": 0,
},
map[string]constantValue{
"DeclIgnoredMamberB": `2`,
"DeclIgnoredMemberB": `2`,
},
map[constantValue][]string{
`2`: {"DeclIgnoredMamberB"},
`2`: {"DeclIgnoredMemberB"},
},
}},
{"DeclTypeInnerNotIgnore", enumMembers{
[]string{"DeclTypeInnerNotIgnoreMember"},
map[string]token.Pos{
"DeclTypeInnerNotIgnoreMember": 0,
},
map[string]constantValue{
"DeclTypeInnerNotIgnoreMember": `5`,
},
map[constantValue][]string{
`5`: {"DeclTypeInnerNotIgnoreMember"},
},
}},
{"DeclTypeIgnoredValue", enumMembers{
[]string{"DeclTypeNotIgnoredValue"},
map[string]token.Pos{
"DeclTypeNotIgnoredValue": 0,
},
map[string]constantValue{
"DeclTypeNotIgnoredValue": `1`,
},
map[constantValue][]string{
`1`: {"DeclTypeNotIgnoredValue"},
},
}},
}
Expand Down
42 changes: 35 additions & 7 deletions testdata/src/enum/enum.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,19 +87,47 @@ const (

func (WithMethod) String() string { return "whatever" }

type DeclGroupIgnoredEnum int // want DeclGroupIgnoredEnum:"^DeclGroupIgnoredMamberC$"
type DeclGroupIgnoredEnum int // want DeclGroupIgnoredEnum:"^DeclGroupIgnoredMemberC$"

//exhaustive:ignore
const (
DeclGroupIgnoredMamberA DeclGroupIgnoredEnum = 1
DeclGroupIgnoredMamberB DeclGroupIgnoredEnum = 2
DeclGroupIgnoredMemberA DeclGroupIgnoredEnum = 1
DeclGroupIgnoredMemberB DeclGroupIgnoredEnum = 2
)

const DeclGroupIgnoredMamberC DeclGroupIgnoredEnum = 3
const DeclGroupIgnoredMemberC DeclGroupIgnoredEnum = 3

type DeclIgnoredEnum int // want DeclIgnoredEnum:"^DeclIgnoredMamberB$"
type DeclIgnoredEnum int // want DeclIgnoredEnum:"^DeclIgnoredMemberB$"

//exhaustive:ignore
const DeclIgnoredMamberA DeclIgnoredEnum = 1
const DeclIgnoredMemberA DeclIgnoredEnum = 1

const DeclIgnoredMamberB DeclIgnoredEnum = 2
const DeclIgnoredMemberB DeclIgnoredEnum = 2

//exhaustive:ignore
type DeclTypeIgnoredEnum int

const (
DeclTypeIgnoredMemberA DeclTypeIgnoredEnum = 1
DeclTypeIgnoredMemberB DeclTypeIgnoredEnum = 2
)

type (
//exhaustive:ignore
DeclTypeInnerIgnore int
DeclTypeInnerNotIgnore int // want DeclTypeInnerNotIgnore:"^DeclTypeInnerNotIgnoreMember$"
)

const (
DeclTypeInnerIgnoreMemberA DeclTypeInnerIgnore = 3
DeclTypeInnerIgnoreMemberB DeclTypeInnerIgnore = 4
DeclTypeInnerNotIgnoreMember DeclTypeInnerNotIgnore = 5
)

type DeclTypeIgnoredValue int // want DeclTypeIgnoredValue:"^DeclTypeNotIgnoredValue$"

const (
DeclTypeNotIgnoredValue DeclTypeIgnoredValue = 1
//exhaustive:ignore
DeclTypeIsIgnoredValue DeclTypeIgnoredValue = 2
)

0 comments on commit ce37a1d

Please sign in to comment.