package fixers import ( "context" "fmt" "go/ast" "go/format" "go/parser" "go/token" "os" "strings" "github.com/yourorg/devour/internal/quality" "github.com/yourorg/devour/internal/quality/plugins" ) type UnusedImportFixer struct{} func NewUnusedImportFixer() *UnusedImportFixer { return &UnusedImportFixer{} } func (f *UnusedImportFixer) Name() string { return "unused_import" } func (f *UnusedImportFixer) Description() string { return "Removes unused import statements" } func (f *UnusedImportFixer) CanFix(finding quality.Finding) bool { return finding.Type == "unused_import" } func (f *UnusedImportFixer) Fix(ctx context.Context, finding quality.Finding, dryRun bool) (*plugins.FixResult, error) { fset := token.NewFileSet() node, err := parser.ParseFile(fset, finding.File, nil, parser.ParseComments) if err != nil { return nil, fmt.Errorf("parse error: %w", err) } importToRemove := finding.Metadata["import_path"] if importToRemove == "" { return nil, fmt.Errorf("no import_path in finding metadata") } var newImports []*ast.ImportSpec for _, imp := range node.Imports { path := strings.Trim(imp.Path.Value, `"`) if path != importToRemove { newImports = append(newImports, imp) } } node.Imports = newImports if dryRun { return &plugins.FixResult{ Success: true, Message: fmt.Sprintf("Would remove import '%s' from %s", importToRemove, finding.File), }, nil } var output strings.Builder if err := format.Node(&output, fset, node); err != nil { return nil, fmt.Errorf("format error: %w", err) } if err := os.WriteFile(finding.File, []byte(output.String()), 0644); err != nil { return nil, fmt.Errorf("write error: %w", err) } return &plugins.FixResult{ Success: true, Message: fmt.Sprintf("Removed unused import '%s' from %s", importToRemove, finding.File), }, nil } type FormattingFixer struct{} func NewFormattingFixer() *FormattingFixer { return &FormattingFixer{} } func (f *FormattingFixer) Name() string { return "format" } func (f *FormattingFixer) Description() string { return "Formats Go source files using gofmt style" } func (f *FormattingFixer) CanFix(finding quality.Finding) bool { return finding.Type == "formatting" || finding.Type == "style" } func (f *FormattingFixer) Fix(ctx context.Context, finding quality.Finding, dryRun bool) (*plugins.FixResult, error) { fset := token.NewFileSet() node, err := parser.ParseFile(fset, finding.File, nil, parser.ParseComments) if err != nil { return nil, fmt.Errorf("parse error: %w", err) } if dryRun { return &plugins.FixResult{ Success: true, Message: fmt.Sprintf("Would format %s", finding.File), }, nil } var output strings.Builder if err := format.Node(&output, fset, node); err != nil { return nil, fmt.Errorf("format error: %w", err) } if err := os.WriteFile(finding.File, []byte(output.String()), 0644); err != nil { return nil, fmt.Errorf("write error: %w", err) } return &plugins.FixResult{ Success: true, Message: fmt.Sprintf("Formatted %s", finding.File), }, nil }