Skip to content

Instantly share code, notes, and snippets.

@mantyr
Last active March 1, 2018 17:50
Show Gist options
  • Select an option

  • Save mantyr/036e8aca6cb0fdfaea49d801d37a13bd to your computer and use it in GitHub Desktop.

Select an option

Save mantyr/036e8aca6cb0fdfaea49d801d37a13bd to your computer and use it in GitHub Desktop.
Выводим входные и выходные параметры
package main
import (
"fmt"
"go/parser"
"go/token"
"go/ast"
"os"
"log"
)
func main() {
err := PrintFuncs("./testdata")
if err != nil {
log.Fatalf("print func params error: %v", err)
}
}
// PrintFuncParams печатает список функций и параметров
func PrintFuncs(path string) error {
fset := token.NewFileSet()
pkgs, err := parser.ParseDir(fset, path, filter, parser.AllErrors)
if err != nil {
return err
}
for _, pack := range pkgs {
for _, file := range pack.Files {
for _, decl := range file.Decls {
switch t := decl.(type) {
case *ast.FuncDecl:
position := fset.Position(t.Type.Func)
fmt.Printf("%s:%d func %s\r\n", position.Filename, position.Line, t.Name)
fmt.Printf("params: \r\n")
for _, f := range t.Type.Params.List {
switch {
case f.Tag != nil:
fmt.Printf(" %s %s `%s`\r\n", f.Names[0], f.Type, f.Tag)
default:
fmt.Printf(" %T\r\n", f)
fmt.Printf(" %s %s\r\n", f.Names[0], f.Type)
}
}
fmt.Printf("results: \r\n")
for _, f := range t.Type.Results.List {
switch {
case f.Tag != nil:
fmt.Printf(" %s %s `%s`\r\n", f.Names[0], f.Type, f.Tag)
default:
switch t := f.Type.(type) {
case *ast.StarExpr:
switch str := t.X.(type) {
case *ast.Ident:
position := fset.Position(str.NamePos)
fmt.Printf(" %s:%d %s\r\n", position.Filename, position.Line, str.Name)
}
}
}
}
}
}
}
}
return nil
}
func filter(os.FileInfo) bool {
return true
}
package main
import (
"fmt"
"go/parser"
"go/token"
"go/ast"
"os"
"log"
)
func main() {
err := PrintFuncs("./testdata")
if err != nil {
log.Fatalf("print func params error: %v", err)
}
}
// PrintFuncParams печатает список функций и параметров
func PrintFuncs(path string) error {
fset := token.NewFileSet()
pkgs, err := parser.ParseDir(fset, path, filter, parser.AllErrors)
if err != nil {
return err
}
for _, pack := range pkgs {
for _, file := range pack.Files {
for _, decl := range file.Decls {
switch t := decl.(type) {
case *ast.FuncDecl:
PrintFunction(fset, t)
}
}
}
}
return nil
}
func filter(os.FileInfo) bool {
return true
}
func PrintFunction(
fset *token.FileSet,
f *ast.FuncDecl,
) {
pos := fset.Position(f.Type.Func)
fmt.Printf("address: %s:%d\r\n", pos.Filename, pos.Line)
fmt.Printf("func name: %s\r\n", f.Name)
fmt.Println("params:")
for _, param := range f.Type.Params.List {
PrintParam(param)
}
fmt.Println("results:")
for _, param := range f.Type.Results.List {
PrintResult(fset, param)
}
}
func PrintParam(param *ast.Field) {
if param.Tag != nil {
fmt.Printf(
" %s %s `%s`\r\n",
param.Names[0],
param.Type,
param.Tag,
)
return
}
fmt.Printf(
" %s %s\r\n",
param.Names[0],
param.Type,
)
}
func PrintResult(fset *token.FileSet, param *ast.Field) {
switch t := param.Type.(type) {
case *ast.StarExpr:
switch str := t.X.(type) {
case *ast.Ident:
pos := fset.Position(str.NamePos)
fmt.Printf(
" %s:%d %s\r\n",
pos.Filename,
pos.Line,
str.Name,
)
}
}
}
package example
// Struct это структура с данными
type Struct struct {
Name string
}
// New возвращает ссылку на новую структуру
// здесь должен сработать линтер на отсутствие err последним элементом
func New(name string) *Struct {
return &Struct{
Name: name,
}
}
// Этот линтер умеет выводить комментарии и умеет определять что последний выходной параметр не ошибка
// так же он исключает все методы структур и реагирует только на отдельные функции (которые мы по сути можем назвать конструкторами)
package main
import (
"fmt"
"go/parser"
"go/token"
"go/ast"
"os"
"log"
)
func main() {
fset := token.NewFileSet()
pkgs, err := parser.ParseDir(fset, "./testdata/", filter, parser.ParseComments)
if err != nil {
log.Fatal(err)
}
for _, pack := range pkgs {
for _, file := range pack.Files {
for _, decl := range file.Decls {
switch t := decl.(type) {
case *ast.FuncDecl:
if t.Recv == nil {
PrintFunction(fset, t)
}
}
}
}
}
}
func filter(os.FileInfo) bool {
return true
}
func PrintFunction(
fset *token.FileSet,
f *ast.FuncDecl,
) {
if len(f.Type.Results.List) == 0 {
return
}
param := f.Type.Results.List[len(f.Type.Results.List)-1]
pos := fset.Position(f.Type.Func)
fmt.Println(f.Doc.Text())
ident, err := Ident(param.Type)
if err != nil {
fmt.Printf(
"%s:%d unexpected output parameter error: %v\r\n",
pos.Filename,
pos.Line,
err,
)
return
}
if ident.Name != "error" {
fmt.Printf(
"%s:%d last output parameter in func %s() is not an error but actual %s\r\n",
pos.Filename,
pos.Line,
f.Name,
ident.Name,
)
}
}
// Ident возвращает Ident параметра если таковой есть
func Ident(param interface{}) (*ast.Ident, error) {
switch t := param.(type) {
case *ast.Ident:
return t, nil
case *ast.StarExpr:
return Ident(t.X)
}
return nil, fmt.Errorf(
"expected ast.Ident or ast.StarExpt but actual %T",
param,
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment