Skip to content

Commit

Permalink
formatter: support require only and suite only packages (#188)
Browse files Browse the repository at this point in the history
* formatter: support require only and suite only packages

* self-review fixes
  • Loading branch information
Antonboom authored Oct 3, 2024
1 parent c6d5f4e commit 3c9db93
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 6 deletions.
14 changes: 14 additions & 0 deletions analyzer/analyzer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,20 @@ func TestTestifyLint(t *testing.T) {
"expected-actual.pattern": "goldenValue",
},
},
{
dir: "formatter-issue170",
flags: map[string]string{
"disable-all": "true",
"enable": checkers.NewFormatter().Name(),
},
},
{
dir: "formatter-issue170-suite",
flags: map[string]string{
"disable-all": "true",
"enable": checkers.NewFormatter().Name(),
},
},
{
dir: "formatter-not-defaults",
flags: map[string]string{
Expand Down
24 changes: 24 additions & 0 deletions analyzer/testdata/src/formatter-issue170-suite/suie_only_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package formatterissue170

import (
"fmt"
"testing"

"github.com/stretchr/testify/suite"
)

func TestFormatter(t *testing.T) {
suite.Run(t, new(FormatterSuite))
}

type FormatterSuite struct {
suite.Suite
}

func (s *FormatterSuite) TestFormatter() {
s.True(false, fmt.Sprintf("expected %v, got %v", true, false)) // want "formatter: remove unnecessary fmt\\.Sprintf"
}

func (s FormatterSuite) TestFormatterValueRecv() {
s.False(true, fmt.Sprintf("expected %v, got %v", true, false)) // want "formatter: remove unnecessary fmt\\.Sprintf"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package formatterissue170

import (
"fmt"
"testing"

"github.com/stretchr/testify/suite"
)

func TestFormatter(t *testing.T) {
suite.Run(t, new(FormatterSuite))
}

type FormatterSuite struct {
suite.Suite
}

func (s *FormatterSuite) TestFormatter() {
s.True(false, "expected %v, got %v", true, false) // want "formatter: remove unnecessary fmt\\.Sprintf"
}

func (s FormatterSuite) TestFormatterValueRecv() {
s.False(true, "expected %v, got %v", true, false) // want "formatter: remove unnecessary fmt\\.Sprintf"
}
12 changes: 12 additions & 0 deletions analyzer/testdata/src/formatter-issue170/require_only_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package formatterissue170

import (
"fmt"
"testing"

"github.com/stretchr/testify/require"
)

func TestFormatter(t *testing.T) {
require.True(t, false, fmt.Sprintf("expected %v, got %v", true, false)) // want "formatter: remove unnecessary fmt\\.Sprintf"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package formatterissue170

import (
"fmt"
"testing"

"github.com/stretchr/testify/require"
)

func TestFormatter(t *testing.T) {
require.True(t, false, "expected %v, got %v", true, false) // want "formatter: remove unnecessary fmt\\.Sprintf"
}
42 changes: 36 additions & 6 deletions internal/checkers/formatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (checker Formatter) Check(pass *analysis.Pass, call *CallMeta) (result *ana
}

func (checker Formatter) checkNotFmtAssertion(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic {
msgAndArgsPos, ok := isPrintfLikeCall(pass, call, call.Fn.Signature)
msgAndArgsPos, ok := isPrintfLikeCall(pass, call)
if !ok {
return nil
}
Expand Down Expand Up @@ -121,21 +121,51 @@ func (checker Formatter) checkFmtAssertion(pass *analysis.Pass, call *CallMeta)
return result
}

func isPrintfLikeCall(pass *analysis.Pass, call *CallMeta, sig *types.Signature) (int, bool) {
msgAndArgsPos := getMsgAndArgsPosition(sig)
func isPrintfLikeCall(pass *analysis.Pass, call *CallMeta) (int, bool) {
msgAndArgsPos := getMsgAndArgsPosition(call.Fn.Signature)
if msgAndArgsPos < 0 {
return -1, false
}

fmtFn := analysisutil.ObjectOf(pass.Pkg, testify.AssertPkgPath, call.Fn.Name+"f")
if fmtFn == nil {
// NOTE(a.telyshev): No formatted analogue of assertion.
if !assertHasFormattedAnalogue(pass, call) {
return -1, false
}

return msgAndArgsPos, len(call.ArgsRaw) > msgAndArgsPos
}

func assertHasFormattedAnalogue(pass *analysis.Pass, call *CallMeta) bool {
if fn := analysisutil.ObjectOf(pass.Pkg, testify.AssertPkgPath, call.Fn.Name+"f"); fn != nil {
return true
}

if fn := analysisutil.ObjectOf(pass.Pkg, testify.RequirePkgPath, call.Fn.Name+"f"); fn != nil {
return true
}

recv := call.Fn.Signature.Recv()
if recv == nil {
return false
}

recvT := recv.Type()
if ptr, ok := recv.Type().(*types.Pointer); ok {
recvT = ptr.Elem()
}

suite, ok := recvT.(*types.Named)
if !ok {
return false
}
for i := 0; i < suite.NumMethods(); i++ {
if suite.Method(i).Name() == call.Fn.Name+"f" {
return true
}
}

return false
}

func getMsgAndArgsPosition(sig *types.Signature) int {
params := sig.Params()
if params.Len() < 1 {
Expand Down

0 comments on commit 3c9db93

Please sign in to comment.