From 879bd2c88f81dda9292678d1b511b5ce6033abb0 Mon Sep 17 00:00:00 2001 From: Ian Wahbe Date: Wed, 10 Apr 2024 01:23:47 +0200 Subject: [PATCH] Allow applying ignore directives to type declarations Adds support for the syntax: ```go //exhaustive:ignore type DeclTypeIgnoredEnum int const ( DeclTypeIgnoredMamberA DeclTypeIgnoredEnum = 1 DeclTypeIgnoredMamberB DeclTypeIgnoredEnum = 2 ) ``` --- enum.go | 43 +++++++++++++++++++++++++++++++++++++++ enum_test.go | 28 +++++++++++++++++-------- testdata/src/enum/enum.go | 34 ++++++++++++++++++++++++------- 3 files changed, 90 insertions(+), 15 deletions(-) diff --git a/enum.go b/enum.go index e62f09a..2bc699d 100644 --- a/enum.go +++ b/enum.go @@ -67,6 +67,8 @@ 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 { @@ -85,6 +87,11 @@ func findEnums(pass *analysis.Pass, pkgScopeOnly bool, pkg *types.Package, inspe for _, s := range gen.Specs { for _, name := range s.(*ast.ValueSpec).Names { + + if _, ignored := ignoredTypes[info.Defs[name].Type()]; ignored { + continue + } + enumTyp, memberName, val, ok := possibleEnumMember(name, info) if !ok { continue @@ -152,6 +159,42 @@ 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 + } + + dirs, err := parseDirectives([]*ast.CommentGroup{gen.Doc}) + if err != nil { + pass.Report(makeInvalidDirectiveDiagnostic(gen, err)) + return + } + + doIgnoreDecl := dirs.has(ignoreDirective) + + for _, s := range gen.Specs { + t := s.(*ast.TypeSpec) + dirs, err := parseDirectives([]*ast.CommentGroup{t.Doc}) + if err != nil { + pass.Report(makeInvalidDirectiveDiagnostic(t, err)) + continue + } + doIgnoreSpec := doIgnoreDecl || dirs.has(ignoreDirective) + 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()) diff --git a/enum_test.go b/enum_test.go index 68cccaf..a7f658c 100644 --- a/enum_test.go +++ b/enum_test.go @@ -367,27 +367,39 @@ 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"}, }, }}, } diff --git a/testdata/src/enum/enum.go b/testdata/src/enum/enum.go index 72ae9f7..fd36d04 100644 --- a/testdata/src/enum/enum.go +++ b/testdata/src/enum/enum.go @@ -87,19 +87,39 @@ 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 +)