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

98 lines
2.5 KiB
Go

package main
import (
"go/ast"
"go/token"
"path/filepath"
"strings"
)
// Import analysis types
type ImportInfo struct {
Package string `json:"package"`
File string `json:"file"`
Imports []ImportDetail `json:"imports"`
UnusedImports []string `json:"unused_imports,omitempty"`
}
type ImportDetail struct {
Path string `json:"path"`
Alias string `json:"alias,omitempty"`
Used []string `json:"used_symbols,omitempty"`
Position Position `json:"position"`
}
func findImports(dir string) ([]ImportInfo, error) {
var imports []ImportInfo
err := walkGoFiles(dir, func(path string, src []byte, file *ast.File, fset *token.FileSet) error {
info := ImportInfo{
Package: file.Name.Name,
File: path,
Imports: []ImportDetail{},
}
// Collect all imports
importMap := make(map[string]*ImportDetail)
for _, imp := range file.Imports {
importPath := strings.Trim(imp.Path.Value, `"`)
pos := fset.Position(imp.Pos())
detail := &ImportDetail{
Path: importPath,
Position: newPosition(pos),
}
if imp.Name != nil {
detail.Alias = imp.Name.Name
}
importMap[importPath] = detail
info.Imports = append(info.Imports, *detail)
}
// Track which imports are used
usedImports := make(map[string]map[string]bool)
ast.Inspect(file, func(n ast.Node) bool {
switch x := n.(type) {
case *ast.SelectorExpr:
if ident, ok := x.X.(*ast.Ident); ok {
pkgName := ident.Name
symbol := x.Sel.Name
// Find matching import
for importPath, detail := range importMap {
importName := filepath.Base(importPath)
if detail.Alias != "" && detail.Alias == pkgName {
if usedImports[importPath] == nil {
usedImports[importPath] = make(map[string]bool)
}
usedImports[importPath][symbol] = true
} else if importName == pkgName {
if usedImports[importPath] == nil {
usedImports[importPath] = make(map[string]bool)
}
usedImports[importPath][symbol] = true
}
}
}
}
return true
})
// Update import details with used symbols
for i, imp := range info.Imports {
if used, ok := usedImports[imp.Path]; ok {
for symbol := range used {
info.Imports[i].Used = append(info.Imports[i].Used, symbol)
}
} else if !strings.HasSuffix(imp.Path, "_test") && imp.Alias != "_" {
info.UnusedImports = append(info.UnusedImports, imp.Path)
}
}
if len(info.Imports) > 0 {
imports = append(imports, info)
}
return nil
})
return imports, err
}