Created
November 3, 2021 12:18
-
-
Save Syuparn/c0afb3f961f3dcc2a6147c461a33258d to your computer and use it in GitHub Desktop.
analyze interface methods
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
// parsed by main.go | |
type Example interface { | |
Foo(int, ...interface{}) (int, error) | |
Hello(name string) (string, error) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module analyzeexample | |
go 1.17 | |
require golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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