diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 3f0e45e..26242e6 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -16,7 +16,7 @@ jobs: fetch-depth: 0 - name: Set up Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v4 with: go-version: 1.19 diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml new file mode 100644 index 0000000..dd6f4a7 --- /dev/null +++ b/.github/workflows/golangci-lint.yml @@ -0,0 +1,53 @@ +name: golangci-lint +on: + push: + tags: + - v* + branches: + - master + - main + pull_request: + +permissions: + contents: read + # Optional: allow read access to pull request. Use with `only-new-issues` option. + # pull-requests: read + +jobs: + golangci: + name: lint + runs-on: ubuntu-latest + steps: + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: '1.19' + cache: false + + - name: Checkout + uses: actions/checkout@v3 + + - name: golangci-lint + uses: golangci/golangci-lint-action@v3 + with: + # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version + version: v1.52.2 + + # Optional: working directory, useful for monorepos + # working-directory: somedir + + # Optional: golangci-lint command line arguments. + # args: --issues-exit-code=0 + + # Optional: show only new issues if it's a pull request. The default value is `false`. + # only-new-issues: true + + # Optional: if set to true then the all caching functionality will be complete disabled, + # takes precedence over all other caching options. + # skip-cache: true + + # Optional: if set to true then the action don't cache or restore ~/go/pkg. + # skip-pkg-cache: true + + # Optional: if set to true then the action don't cache or restore ~/.cache/go-build. + # skip-build-cache: true diff --git a/_testdata/foo.go b/_testdata/foo.go index 92e5fb9..e549b66 100644 --- a/_testdata/foo.go +++ b/_testdata/foo.go @@ -200,3 +200,30 @@ func F27(r *os.File) (data []byte, err error) { func F28(r *os.File) map[int]io.Reader { return map[int]io.Reader{7: r} } + +func F29(r *os.File) ([]byte, error) { + s := struct { + rd io.Reader + }{rd: r} + return io.ReadAll(s.rd) +} + +func F30(f *os.File) ([]byte, error) { + s := struct { + file *os.File + }{file: f} + return io.ReadAll(s.file) +} + +func F31(r *os.File) ([]byte, error) { + fn := func(readers ...io.Reader) ([]byte, error) { + for _, reader := range readers { + if reader != nil { + return io.ReadAll(reader) + } + } + return nil, nil + } + + return fn(nil, r) +} diff --git a/debug.go b/debug.go index 9841b57..f3d48da 100644 --- a/debug.go +++ b/debug.go @@ -11,9 +11,9 @@ func (a *analyzer) debugf(format string, args ...any) { return } s := fmt.Sprintf(format, args...) - strings.TrimRight(s, "\r\n") + s = strings.TrimRight(s, "\r\n") if a.level > 0 { - fmt.Fprintf(os.Stderr, strings.Repeat(" ", a.level)) + fmt.Fprint(os.Stderr, strings.Repeat(" ", a.level)) } fmt.Fprintln(os.Stderr, s) } diff --git a/decouple.go b/decouple.go index 5a49090..de9abfe 100644 --- a/decouple.go +++ b/decouple.go @@ -349,21 +349,27 @@ func (a *analyzer) stmt(stmt ast.Stmt) (ok bool) { } for i, rhs := range stmt.Rhs { // xxx do a recursive analysis of how this var is used! - if a.isObj(rhs) && stmt.Tok != token.DEFINE { - if stmt.Tok != token.ASSIGN { - // Reject OP= - return false - } - tv, ok := a.pkg.TypesInfo.Types[stmt.Lhs[i]] - if !ok { - panic(errf("no type info for lvalue %d in assignment at %s", i, a.pos(stmt))) - } - intf := getInterface(tv.Type) - if intf == nil { + if a.isObj(rhs) { + switch stmt.Tok { + case token.DEFINE: + continue + + case token.ASSIGN: + tv, ok := a.pkg.TypesInfo.Types[stmt.Lhs[i]] + if !ok { + panic(errf("no type info for lvalue %d in assignment at %s", i, a.pos(stmt))) + } + intf := getInterface(tv.Type) + if intf == nil { + return false + } + a.addMethods(intf) + continue + + default: + // Reject OP= (e.g., foo += obj) return false } - a.addMethods(intf) - continue } if !a.expr(rhs) { return false diff --git a/decouple_test.go b/decouple_test.go index fbc8164..53591e4 100644 --- a/decouple_test.go +++ b/decouple_test.go @@ -13,7 +13,7 @@ import ( // "github.com/davecgh/go-spew/spew" ) -func TestAnalyze(t *testing.T) { +func TestCheckParam(t *testing.T) { ctx := context.Background() conf := &packages.Config{ diff --git a/fab.d/fab.go b/fab.d/fab.go new file mode 100644 index 0000000..68c4640 --- /dev/null +++ b/fab.d/fab.go @@ -0,0 +1,30 @@ +package fab + +import ( + "context" + "os" + + "github.com/bobg/fab" + "github.com/bobg/fab/deps" + "github.com/pkg/errors" +) + +var ( + Cover = fab.Deps(showCoverage, computeCoverage) + Clean = fab.Clean("cover.out") + + showCoverage = fab.Command("go tool cover -html cover.out") +) + +var computeCoverage = fab.Register("computeCoverage", "compute coverage profile", fab.F(func(ctx context.Context) error { + in, err := deps.Go(".", true) + if err != nil { + return errors.Wrap(err, "in deps.Go") + } + filesTarget := fab.Files{ + Target: fab.Command("go test -coverprofile cover.out ./...", fab.CmdStdout(os.Stdout)), + In: in, + Out: []string{"cover.out"}, + } + return filesTarget.Run(ctx) +}))