Files
gocp/tool_find_struct_usage.go
2025-06-27 21:22:36 -07:00

110 lines
2.6 KiB
Go

package main
import (
"go/ast"
"go/token"
"strings"
)
// Struct usage types
type StructUsage struct {
File string `json:"file"`
Literals []StructLiteral `json:"literals,omitempty"`
FieldAccess []FieldAccess `json:"field_access,omitempty"`
TypeUsage []TypeUsage `json:"type_usage,omitempty"`
}
type StructLiteral struct {
Fields []string `json:"fields_initialized"`
IsComposite bool `json:"is_composite"`
Position Position `json:"position"`
}
type FieldAccess struct {
Field string `json:"field"`
Context string `json:"context"`
Position Position `json:"position"`
}
type TypeUsage struct {
Usage string `json:"usage"`
Position Position `json:"position"`
}
func findStructUsage(dir string, structName string) ([]StructUsage, error) {
var usages []StructUsage
err := walkGoFiles(dir, func(path string, src []byte, file *ast.File, fset *token.FileSet) error {
usage := StructUsage{
File: path,
}
ast.Inspect(file, func(n ast.Node) bool {
switch x := n.(type) {
// Find struct literals
case *ast.CompositeLit:
if typeName := getTypeName(x.Type); typeName == structName {
pos := fset.Position(x.Pos())
lit := StructLiteral{
IsComposite: len(x.Elts) > 0,
Position: newPosition(pos),
}
// Extract initialized fields
for _, elt := range x.Elts {
if kv, ok := elt.(*ast.KeyValueExpr); ok {
if ident, ok := kv.Key.(*ast.Ident); ok {
lit.Fields = append(lit.Fields, ident.Name)
}
}
}
usage.Literals = append(usage.Literals, lit)
}
// Find field access
case *ast.SelectorExpr:
if typeName := getTypeName(x.X); strings.Contains(typeName, structName) {
pos := fset.Position(x.Sel.Pos())
context := extractContext(src, pos)
usage.FieldAccess = append(usage.FieldAccess, FieldAccess{
Field: x.Sel.Name,
Context: context,
Position: newPosition(pos),
})
}
// Find type usage in declarations
case *ast.Field:
if typeName := getTypeName(x.Type); typeName == structName {
pos := fset.Position(x.Pos())
usage.TypeUsage = append(usage.TypeUsage, TypeUsage{
Usage: "field",
Position: newPosition(pos),
})
}
}
return true
})
if len(usage.Literals) > 0 || len(usage.FieldAccess) > 0 || len(usage.TypeUsage) > 0 {
usages = append(usages, usage)
}
return nil
})
return usages, err
}
func getTypeName(expr ast.Expr) string {
switch x := expr.(type) {
case *ast.Ident:
return x.Name
case *ast.StarExpr:
return getTypeName(x.X)
case *ast.SelectorExpr:
return exprToString(x)
}
return ""
}