Reorganize code into individual tool files
This commit is contained in:
123
tool_extract_interfaces.go
Normal file
123
tool_extract_interfaces.go
Normal file
@@ -0,0 +1,123 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user