Files
gocp/tool_extract_interfaces.go

123 lines
3.2 KiB
Go
Raw Normal View History

package main
import (
"go/ast"
"go/token"
)
// Interface analysis types
type InterfaceInfo struct {
Name string `json:"name"`
Package string `json:"package"`
Position Position `json:"position"`
Methods []MethodInfo `json:"methods"`
Implementations []ImplementationType `json:"implementations,omitempty"`
}
type ImplementationType struct {
Type string `json:"type"`
Package string `json:"package"`
Position Position `json:"position"`
}
func extractInterfaces(dir string, interfaceName string) ([]InterfaceInfo, error) {
var interfaces []InterfaceInfo
interfaceMap := make(map[string]*InterfaceInfo)
// First pass: collect all interfaces
err := walkGoFiles(dir, func(path string, src []byte, file *ast.File, fset *token.FileSet) error {
ast.Inspect(file, func(n ast.Node) bool {
if genDecl, ok := n.(*ast.GenDecl); ok {
for _, spec := range genDecl.Specs {
if typeSpec, ok := spec.(*ast.TypeSpec); ok {
if iface, ok := typeSpec.Type.(*ast.InterfaceType); ok {
name := typeSpec.Name.Name
if interfaceName == "" || name == interfaceName {
pos := fset.Position(typeSpec.Pos())
info := &InterfaceInfo{
Name: name,
Package: file.Name.Name,
Position: newPosition(pos),
Methods: extractInterfaceMethods(iface, fset),
}
interfaceMap[name] = info
}
}
}
}
}
return true
})
return nil
})
if err != nil {
return nil, err
}
// Second pass: find implementations
if interfaceName != "" {
iface, exists := interfaceMap[interfaceName]
if exists {
err = walkGoFiles(dir, func(path string, src []byte, file *ast.File, fset *token.FileSet) error {
// Collect all types with methods
types := make(map[string][]string)
for _, decl := range file.Decls {
if fn, ok := decl.(*ast.FuncDecl); ok && fn.Recv != nil {
for _, recv := range fn.Recv.List {
typeName := getTypeName(recv.Type)
types[typeName] = append(types[typeName], fn.Name.Name)
}
}
}
// Check if any type implements the interface
for typeName, methods := range types {
if implementsInterface(methods, iface.Methods) {
// Find type declaration
ast.Inspect(file, func(n ast.Node) bool {
if genDecl, ok := n.(*ast.GenDecl); ok {
for _, spec := range genDecl.Specs {
if typeSpec, ok := spec.(*ast.TypeSpec); ok && typeSpec.Name.Name == typeName {
pos := fset.Position(typeSpec.Pos())
iface.Implementations = append(iface.Implementations, ImplementationType{
Type: typeName,
Package: file.Name.Name,
Position: newPosition(pos),
})
}
}
}
return true
})
}
}
return nil
})
}
}
// Convert map to slice
for _, iface := range interfaceMap {
interfaces = append(interfaces, *iface)
}
return interfaces, err
}
func implementsInterface(methods []string, interfaceMethods []MethodInfo) bool {
for _, im := range interfaceMethods {
found := false
for _, m := range methods {
if m == im.Name {
found = true
break
}
}
if !found {
return false
}
}
return true
}