Skip to content

Instantly share code, notes, and snippets.

@Syuparn
Created November 3, 2021 12:18
Show Gist options
  • Save Syuparn/c0afb3f961f3dcc2a6147c461a33258d to your computer and use it in GitHub Desktop.
Save Syuparn/c0afb3f961f3dcc2a6147c461a33258d to your computer and use it in GitHub Desktop.
analyze interface methods
package main
// parsed by main.go
type Example interface {
Foo(int, ...interface{}) (int, error)
Hello(name string) (string, error)
}
module analyzeexample
go 1.17
require golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
package main
import (
"fmt"
"go/ast"
"go/importer"
"go/parser"
"go/token"
"go/types"
"os"
"golang.org/x/xerrors"
)
func interfaceInfo(fileName, interfaceName string) (*types.Interface, error) {
fset := token.NewFileSet()
conf := types.Config{
// NOTE: use "source" to import directly from source
// ("cg" cannot work if dependent package is not installed globally)
Importer: importer.ForCompiler(fset, "source", nil),
}
// src, mode
f, err := parser.ParseFile(fset, fileName, nil, parser.ParseComments)
if err != nil {
return nil, xerrors.Errorf("failed to parse code: %w", err)
}
if f.Name == nil {
return nil, xerrors.Errorf("failed to obtain package name")
}
packageName := f.Name.Name
info := &types.Info{
Defs: map[*ast.Ident]types.Object{},
}
pkg, err := conf.Check(packageName, fset, []*ast.File{f}, info)
if err != nil {
return nil, xerrors.Errorf("failed to extract package: %w", err)
}
obj := pkg.Scope().Lookup(interfaceName)
if obj == nil {
return nil, xerrors.Errorf("interface %s is not found", interfaceName)
}
it, ok := obj.Type().Underlying().(*types.Interface)
if !ok {
return nil, xerrors.Errorf("%s is not an interface", interfaceName)
}
return it, nil
}
func interfaceMethods(it *types.Interface) []*types.Func {
fns := make([]*types.Func, it.NumMethods())
for i := 0; i < it.NumMethods(); i++ {
fns[i] = it.Method(i)
}
return fns
}
func main() {
it, err := interfaceInfo("example.go", "Example")
if err != nil {
fmt.Fprintf(os.Stderr, "%+v\n", err)
}
for _, m := range interfaceMethods(it) {
fmt.Println(m)
}
}
/*
$ go run main.go
func (main.Example).Foo(int, ...interface{}) (int, error)
func (main.Example).Hello(name string) (string, error)
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment