Skip to content

Commit

Permalink
Merge pull request #30 from gostaticanalysis/release-v1.6.0
Browse files Browse the repository at this point in the history
Release v1.6.0
  • Loading branch information
tenntenn authored Oct 18, 2020
2 parents 5511d91 + 2129af3 commit 9eb4705
Show file tree
Hide file tree
Showing 9 changed files with 237 additions and 4 deletions.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,31 @@ pkgname
└── go.mod
```

### Create skeleton codes of codegenerator

```
$ skeleton -type=codegen pkgname
pkgname
├── cmd
│   └── pkgname
│   └── main.go
├── go.mod
├── pkgname.go
├── pkgname_test.go
└── testdata
└── src
└── a
├── a.go
└── pkgname.golden
```

### Change type of skeleton code

skeleton accepts `-type` option which indicates type of skeleton code.

* `-type=inspect`(default): generate skeleton code with `inspect.Analyzer`
* `-type=ssa`: generate skeleton code with `buildssa.Analyzer`
* `-type=codegen`: generate skeleton code of a code generator

## Build as a plugin for golangci-lint

Expand Down
116 changes: 116 additions & 0 deletions _template/@@.Pkg@@.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,119 @@ func run(pass *analysis.Pass) (interface{}, error) {
return nil, nil
}
@@ end -@@
@@ if eq .Type "codegen" -@@
package @@.Pkg@@

import (
"bytes"
"fmt"
"go/format"
"go/types"
"os"

"github.com/gostaticanalysis/analysisutil"
"github.com/gostaticanalysis/codegen"
"github.com/gostaticanalysis/knife"
)

const doc = "@@.Pkg@@ is ..."

var (
flagOutput string
)

func init() {
Generator.Flags.StringVar(&flagOutput, "o", "", "output file name")
}

var Generator = &codegen.Generator{
Name: "@@.Pkg@@",
Doc: doc,
Run: run,
}

func run(pass *codegen.Pass) error {
ifaces := map[string]*knife.Interface{}

s := pass.Pkg.Scope()
for _, name := range s.Names() {
obj := s.Lookup(name)
if !obj.Exported() {
continue
}
iface, _ := analysisutil.Under(obj.Type()).(*types.Interface)
if iface != nil {
ifaces[name] = knife.NewInterface(iface)
}
}

td := &knife.TempalteData{
Fset: pass.Fset,
Files: pass.Files,
TypesInfo: pass.TypesInfo,
Pkg: pass.Pkg,
}
t, err := knife.NewTemplate(td).Parse(tmpl)
if err != nil {
return err
}

var buf bytes.Buffer
if err := t.Execute(&buf, ifaces); err != nil {
return err
}

src, err := format.Source(buf.Bytes())
if err != nil {
return err
}

if flagOutput == "" {
pass.Print(string(src))
return nil
}

f, err := os.Create(flagOutput)
if err != nil {
return err
}

fmt.Fprint(f, string(src))

if err := f.Close(); err != nil {
return err
}

return nil
}

var tmpl = `// Code generated by @@.Pkg@@; DO NOT EDIT.
package {{(pkg).Name}}
{{range $tn, $t := .}}
type Mock{{$tn}} struct {
{{- range $n, $f := $t.Methods}}
{{$n}}Func {{$f.Signature}}
{{- end}}
}
{{range $n, $f := $t.Methods}}
func (m *Mock{{$tn}}) {{$n}}({{range $f.Signature.Params}}
{{- if (and $f.Signature.Variadic (eq . (last $f.Signature.Params)))}}
{{- .Name}} ...{{(slice .Type).Elem}},
{{- else}}
{{- .Name}} {{.Type}},
{{- end}}
{{- end}}) ({{range $f.Signature.Results}}
{{- .Name}} {{.Type}},
{{- end}}) {
{{if $f.Signature.Results}}return {{end}}m.{{$n}}Func({{range $f.Signature.Params}}
{{- if (and $f.Signature.Variadic (eq . (last $f.Signature.Params)))}}
{{- .Name}}...,
{{- else}}
{{- .Name}},
{{- end}}
{{- end}})
}
{{end}}
{{end}}
`
@@ end -@@
26 changes: 26 additions & 0 deletions _template/@@.Pkg@@_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@@ if (or (eq .Type "inspect") (eq .Type "ssa")) -@@
package @@.Pkg@@_test

import (
Expand All @@ -13,4 +14,29 @@ func TestAnalyzer(t *testing.T) {
testdata := testutil.WithModules(t, analysistest.TestData(), nil)
analysistest.Run(t, testdata, @@.Pkg@@.Analyzer, "a")
}
@@ end -@@
@@ if eq .Type "codegen" -@@
package @@.Pkg@@_test

import (
"flag"
"os"
"testing"

"@@.ImportPath@@"
"github.com/gostaticanalysis/codegen/codegentest"
)

var flagUpdate bool

func TestMain(m *testing.M) {
flag.BoolVar(&flagUpdate, "update", false, "update the golden files")
flag.Parse()
os.Exit(m.Run())
}

func TestGenerator(t *testing.T) {
rs := codegentest.Run(t, codegentest.TestData(), @@.Pkg@@.Generator, "a")
codegentest.Golden(t, rs, flagUpdate)
}
@@ end -@@
14 changes: 14 additions & 0 deletions _template/cmd/@@.Pkg@@/main.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@@ if .Cmd -@@
@@ if (or (eq .Type "inspect") (eq .Type "ssa")) -@@
package main

import (
Expand All @@ -7,4 +8,17 @@ import (
)

func main() { @@.Checker@@checker.Main(@@.Pkg@@.Analyzer) }
@@ end -@@
@@ if eq .Type "codegen" -@@
package main

import (
"@@.ImportPath@@"
"github.com/gostaticanalysis/codegen/@@.Checker@@generator"
)

func main() {
@@.Checker@@generator.Main(@@.Pkg@@.Generator)
}
@@ end -@@
@@end@@
30 changes: 30 additions & 0 deletions _template/testdata/src/a/@@.Pkg@@.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@@ if eq .Type "codegen" -@@
// Code generated by @@.Pkg@@; DO NOT EDIT.
package a

type MockDB struct {
GetFunc func(id string) int
SetFunc func(id string, v int)
}

func (m *MockDB) Get(id string) int {
return m.GetFunc(id)
}

func (m *MockDB) Set(id string, v int) {
m.SetFunc(id, v)
}

type MockLogger struct {
ErrorfFunc func(format string, args ...interface{})
InfofFunc func(format string, args ...interface{})
}

func (m *MockLogger) Errorf(format string, args ...interface{}) {
m.ErrorfFunc(format, args...)
}

func (m *MockLogger) Infof(format string, args ...interface{}) {
m.InfofFunc(format, args...)
}
@@ end -@@
19 changes: 19 additions & 0 deletions _template/testdata/src/a/a.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,27 @@
@@ if (or (eq .Type "inspect") (eq .Type "ssa")) -@@
package a

func f() {
// The pattern can be written in regular expression.
var gopher int // want "pattern"
print(gopher) // want "identifier is gopher"
}
@@ end -@@
@@ if eq .Type "codegen" -@@
package a

type DB interface {
Get(id string) int
Set(id string, v int)
}

type db struct{}

func (db) Get(id string) int { return 0 }
func (db) Set(id string, v int) {}

type Logger interface {
Infof(format string, args ...interface{})
Errorf(format string, args ...interface{})
}
@@ end -@@
4 changes: 3 additions & 1 deletion _template/testdata/src/a/go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@@ if ne .Type "codegen" -@@
module a

go 1.15
go @@.GoVer@@
@@ end -@@
11 changes: 9 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func main() {
flag.BoolVar(&s.Cmd, "cmd", true, "create cmd directory")
flag.StringVar(&s.Checker, "checker", "unit", "checker which is used in main.go (unit,single,multi)")
flag.BoolVar(&s.Plugin, "plugin", true, "create plugin directory")
flag.StringVar(&s.Type, "type", "inspect", "type of skeleton code (inspect|ssa)")
flag.StringVar(&s.Type, "type", "inspect", "type of skeleton code (inspect|ssa|codegen)")
flag.BoolVar(&s.Mod, "mod", true, "generate empty go.mod")
flag.StringVar(&s.ImportPath, "path", "", "import path")
flag.Parse()
Expand All @@ -39,6 +39,13 @@ func main() {
s.Checker = "unit"
}

if s.Type == "codegen" {
if s.Checker != "single" {
s.Checker = "single"
}
s.Plugin = false
}

if err := s.Run(); err != nil {
fmt.Fprintln(os.Stderr, "Error:", err)
os.Exit(1)
Expand Down Expand Up @@ -106,7 +113,7 @@ func (s *Skeleton) Run() error {
}

switch s.Type {
case "inspect", "ssa":
case "inspect", "ssa", "codegen":
default:
return fmt.Errorf("unexpected type: %s", s.Type)
}
Expand Down
2 changes: 1 addition & 1 deletion template.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 9eb4705

Please sign in to comment.