diff --git a/unusedmethod/testdata/src/a/a.go b/unusedmethod/testdata/src/a/a.go deleted file mode 100644 index dfb2cd7..0000000 --- a/unusedmethod/testdata/src/a/a.go +++ /dev/null @@ -1,23 +0,0 @@ -package comm - -type MessageSender interface { - SendMessage(username, msg string) error - MustSendMessage(username, msg string) // want "method 'MustSendMessage\\(\\)' is declared on interface 'MessageSender' but not used within the package" - - // Close the resource. - Close() error // want "method 'Close\\(\\)' is declared on interface 'MessageSender' but not used within the package" -} - -type Service struct { - sender MessageSender -} - -func NewService(sender MessageSender) *Service { - return &Service{ - sender: sender, - } -} - -func (s *Service) GreetMorning(username string) error { - return s.sender.SendMessage(username, "Good morning") -} diff --git a/unusedmethod/testdata/src/a/a.go.golden b/unusedmethod/testdata/src/a/a.go.golden deleted file mode 100644 index 4bc4ac4..0000000 --- a/unusedmethod/testdata/src/a/a.go.golden +++ /dev/null @@ -1,19 +0,0 @@ -package comm - -type MessageSender interface { - SendMessage(username, msg string) error -} - -type Service struct { - sender MessageSender -} - -func NewService(sender MessageSender) *Service { - return &Service{ - sender: sender, - } -} - -func (s *Service) GreetMorning(username string) error { - return s.sender.SendMessage(username, "Good morning") -} diff --git a/unusedmethod/testdata/src/b/b.go b/unusedmethod/testdata/src/b/b.go deleted file mode 100644 index a4fc189..0000000 --- a/unusedmethod/testdata/src/b/b.go +++ /dev/null @@ -1,24 +0,0 @@ -package comm - -//iface:ignore=unusedmethod -type MessageSender interface { - SendMessage(username, msg string) error - MustSendMessage(username, msg string) - - // Close the resource. - Close() error -} - -type Service struct { - sender MessageSender -} - -func NewService(sender MessageSender) *Service { - return &Service{ - sender: sender, - } -} - -func (s *Service) GreetMorning(username string) error { - return s.sender.SendMessage(username, "Good morning") -} diff --git a/unusedmethod/testdata/src/basic/basic.go b/unusedmethod/testdata/src/basic/basic.go new file mode 100644 index 0000000..074fa4d --- /dev/null +++ b/unusedmethod/testdata/src/basic/basic.go @@ -0,0 +1,70 @@ +package basic + +import ( + "errors" + "time" +) + +type Logger interface { + Debug(msg string, args ...any) // want "^method 'Debug\\(\\)' is declared on interface 'Logger' but not used within the package$" + Info(msg string, args ...any) + + Warn(msg string, args ...any) //iface:ignore=unusedmethod + + //iface:ignore=unusedmethod + Error(msg string, args ...any) +} + +//iface:ignore=unusedmethod +type Meter interface { + CountInc(name string, val int, attrs map[string]any) + Record(name string, val int, attrs map[string]any) + Set(name string, val int, attrs map[string]any) +} + +type User struct { + Username string + Password string +} + +type UserRepository interface { + UserOfUsername(username string) (*User, error) +} + +type AuthService struct { + userRepo UserRepository + logger Logger + meter Meter +} + +func NewAuthService(userRepo UserRepository, logger Logger, meter Meter) *AuthService { + return &AuthService{ + userRepo: userRepo, + logger: logger, + meter: meter, + } +} + +func (as *AuthService) Authenticate(username, password string) error { + start := time.Now() + defer func() { + duration := time.Since(start) + as.meter.Record("authenticate.duration", int(duration.Milliseconds()), nil) + }() + + as.logger.Info("Authenticate %q", username) + + usr, err := as.userRepo.UserOfUsername(username) + if err != nil { + return err + } + + if usr.Password != password { + as.meter.CountInc("authenticate.failed", 1, map[string]any{"username": username}) + return errors.New("invalid username or password") + } + + as.meter.CountInc("authenticate.succeed", 1, map[string]any{"username": username}) + + return nil +} diff --git a/unusedmethod/testdata/src/basic/basic.go.golden b/unusedmethod/testdata/src/basic/basic.go.golden new file mode 100644 index 0000000..667c9ab --- /dev/null +++ b/unusedmethod/testdata/src/basic/basic.go.golden @@ -0,0 +1,69 @@ +package basic + +import ( + "errors" + "time" +) + +type Logger interface { + Info(msg string, args ...any) + + Warn(msg string, args ...any) //iface:ignore=unusedmethod + + //iface:ignore=unusedmethod + Error(msg string, args ...any) +} + +//iface:ignore=unusedmethod +type Meter interface { + CountInc(name string, val int, attrs map[string]any) + Record(name string, val int, attrs map[string]any) + Set(name string, val int, attrs map[string]any) +} + +type User struct { + Username string + Password string +} + +type UserRepository interface { + UserOfUsername(username string) (*User, error) +} + +type AuthService struct { + userRepo UserRepository + logger Logger + meter Meter +} + +func NewAuthService(userRepo UserRepository, logger Logger, meter Meter) *AuthService { + return &AuthService{ + userRepo: userRepo, + logger: logger, + meter: meter, + } +} + +func (as *AuthService) Authenticate(username, password string) error { + start := time.Now() + defer func() { + duration := time.Since(start) + as.meter.Record("authenticate.duration", int(duration.Milliseconds()), nil) + }() + + as.logger.Info("Authenticate %q", username) + + usr, err := as.userRepo.UserOfUsername(username) + if err != nil { + return err + } + + if usr.Password != password { + as.meter.CountInc("authenticate.failed", 1, map[string]any{"username": username}) + return errors.New("invalid username or password") + } + + as.meter.CountInc("authenticate.succeed", 1, map[string]any{"username": username}) + + return nil +} diff --git a/unusedmethod/testdata/src/c/c.go b/unusedmethod/testdata/src/c/c.go deleted file mode 100644 index baef5fc..0000000 --- a/unusedmethod/testdata/src/c/c.go +++ /dev/null @@ -1,25 +0,0 @@ -package comm - -type MessageSender interface { - SendMessage(username, msg string) error - - //iface:ignore=unusedmethod - MustSendMessage(username, msg string) - - // Close the resource. - Close() error // want "method 'Close\\(\\)' is declared on interface 'MessageSender' but not used within the package" -} - -type Service struct { - sender MessageSender -} - -func NewService(sender MessageSender) *Service { - return &Service{ - sender: sender, - } -} - -func (s *Service) GreetMorning(username string) error { - return s.sender.SendMessage(username, "Good morning") -} diff --git a/unusedmethod/testdata/src/d/d.go b/unusedmethod/testdata/src/d/d.go deleted file mode 100644 index ca9f7ac..0000000 --- a/unusedmethod/testdata/src/d/d.go +++ /dev/null @@ -1,23 +0,0 @@ -package comm - -type MessageSender interface { - SendMessage(username, msg string) error - MustSendMessage(username, msg string) //iface:ignore=unusedmethod - - // Close the resource. - Close() error // want "method 'Close\\(\\)' is declared on interface 'MessageSender' but not used within the package" -} - -type Service struct { - sender MessageSender -} - -func NewService(sender MessageSender) *Service { - return &Service{ - sender: sender, - } -} - -func (s *Service) GreetMorning(username string) error { - return s.sender.SendMessage(username, "Good morning") -} diff --git a/unusedmethod/testdata/src/e/e.go b/unusedmethod/testdata/src/e/e.go deleted file mode 100644 index 06845ff..0000000 --- a/unusedmethod/testdata/src/e/e.go +++ /dev/null @@ -1,13 +0,0 @@ -package comm - -type Callback interface { - Call(msg string) -} - -type Service struct { - callbacks []func(msg string) -} - -func (s *Service) RegisterCallaback(cb Callback) { - s.callbacks = append(s.callbacks, cb.Call) -} diff --git a/unusedmethod/testdata/src/excludepkg/excludepkg.go b/unusedmethod/testdata/src/excludepkg/excludepkg.go new file mode 100644 index 0000000..df52d12 --- /dev/null +++ b/unusedmethod/testdata/src/excludepkg/excludepkg.go @@ -0,0 +1,45 @@ +package excludepkg + +import "errors" + +type Logger interface { + Debug(msg string, args ...any) + Info(msg string, args ...any) + Error(msg string, args ...any) +} + +type User struct { + Username string + Password string +} + +type UserRepository interface { + UserOfUsername(username string) (*User, error) +} + +type AuthService struct { + userRepo UserRepository + logger Logger +} + +func NewAuthService(userRepo UserRepository, logger Logger) *AuthService { + return &AuthService{ + userRepo: userRepo, + logger: logger, + } +} + +func (as *AuthService) Authenticate(username, password string) error { + as.logger.Info("Authenticate %q", username) + + usr, err := as.userRepo.UserOfUsername(username) + if err != nil { + return err + } + + if usr.Password != password { + return errors.New("invalid username or password") + } + + return nil +} diff --git a/unusedmethod/testdata/src/f/f.go b/unusedmethod/testdata/src/f/f.go deleted file mode 100644 index 7fae34d..0000000 --- a/unusedmethod/testdata/src/f/f.go +++ /dev/null @@ -1,20 +0,0 @@ -package comm - -type Callback interface { - Call(msg string) -} - -type entry struct { - cb Callback - call func(cb Callback, msg string) -} -type Service struct { - callbacks []entry -} - -func (s *Service) RegisterCallaback(cb Callback) { - s.callbacks = append(s.callbacks, entry{ - cb: cb, - call: Callback.Call, - }) -} diff --git a/unusedmethod/testdata/src/g/a.go b/unusedmethod/testdata/src/g/a.go deleted file mode 100644 index 2e6b7f9..0000000 --- a/unusedmethod/testdata/src/g/a.go +++ /dev/null @@ -1,23 +0,0 @@ -package comm - -type MessageSender interface { - SendMessage(username, msg string) error - MustSendMessage(username, msg string) - - // Close the resource. - Close() error -} - -type Service struct { - sender MessageSender -} - -func NewService(sender MessageSender) *Service { - return &Service{ - sender: sender, - } -} - -func (s *Service) GreetMorning(username string) error { - return s.sender.SendMessage(username, "Good morning") -} diff --git a/unusedmethod/testdata/src/g/a.go.golden b/unusedmethod/testdata/src/g/a.go.golden deleted file mode 100644 index 4bc4ac4..0000000 --- a/unusedmethod/testdata/src/g/a.go.golden +++ /dev/null @@ -1,19 +0,0 @@ -package comm - -type MessageSender interface { - SendMessage(username, msg string) error -} - -type Service struct { - sender MessageSender -} - -func NewService(sender MessageSender) *Service { - return &Service{ - sender: sender, - } -} - -func (s *Service) GreetMorning(username string) error { - return s.sender.SendMessage(username, "Good morning") -} diff --git a/unusedmethod/testdata/src/methodexpr/methodexpr.go b/unusedmethod/testdata/src/methodexpr/methodexpr.go new file mode 100644 index 0000000..ba6ebc5 --- /dev/null +++ b/unusedmethod/testdata/src/methodexpr/methodexpr.go @@ -0,0 +1,20 @@ +package methodexpr + +type Callback interface { + Call(res any) +} + +type Registry struct { + callbacks []Callback +} + +func (reg *Registry) Register(cb Callback) { + reg.callbacks = append(reg.callbacks, cb) +} + +func (reg *Registry) Notify(res any) { + for _, cb := range reg.callbacks { + // we have usage to the Callback.Call usage as expression + Callback.Call(cb, res) + } +} diff --git a/unusedmethod/testdata/src/methodref/methodref.go b/unusedmethod/testdata/src/methodref/methodref.go new file mode 100644 index 0000000..885c92a --- /dev/null +++ b/unusedmethod/testdata/src/methodref/methodref.go @@ -0,0 +1,20 @@ +package methodref + +type Callback interface { + Call(res any) +} + +type Registry struct { + callbacks []func(res any) +} + +func (reg *Registry) Register(cb Callback) { + // we have usage to the Callback.Call as reference + reg.callbacks = append(reg.callbacks, cb.Call) +} + +func (reg *Registry) Notify(res any) { + for _, cb := range reg.callbacks { + cb(res) + } +} diff --git a/unusedmethod/unusedmethod_test.go b/unusedmethod/unusedmethod_test.go index 51bf5ff..6e9a814 100644 --- a/unusedmethod/unusedmethod_test.go +++ b/unusedmethod/unusedmethod_test.go @@ -8,22 +8,17 @@ import ( ) func Test(t *testing.T) { - testdata := analysistest.TestData() - analysistest.RunWithSuggestedFixes(t, testdata, unusedmethod.Analyzer, "a") - analysistest.Run(t, testdata, unusedmethod.Analyzer, "b") - analysistest.Run(t, testdata, unusedmethod.Analyzer, "c") - analysistest.Run(t, testdata, unusedmethod.Analyzer, "d") - analysistest.Run(t, testdata, unusedmethod.Analyzer, "e") - analysistest.Run(t, testdata, unusedmethod.Analyzer, "f") -} - -func TestExclusion(t *testing.T) { - err := unusedmethod.Analyzer.Flags.Set("exclude", "g") + err := unusedmethod.Analyzer.Flags.Set("exclude", "excludepkg") if err != nil { t.Fatal(err) } testdata := analysistest.TestData() - analysistest.RunWithSuggestedFixes(t, testdata, unusedmethod.Analyzer, "a") - analysistest.Run(t, testdata, unusedmethod.Analyzer, "g") + analysistest.RunWithSuggestedFixes(t, testdata, unusedmethod.Analyzer, + "basic") + + analysistest.Run(t, testdata, unusedmethod.Analyzer, + "excludepkg", + "methodref", + "methodexpr") }