Files
gocp/tool_find_inefficiencies.go

93 lines
2.6 KiB
Go
Raw Normal View History

package main
import (
"fmt"
"go/ast"
"go/token"
)
// Performance inefficiency types
type InefficiencyInfo struct {
File string `json:"file"`
StringConcat []InefficiencyItem `json:"string_concat,omitempty"`
Conversions []InefficiencyItem `json:"unnecessary_conversions,omitempty"`
Allocations []InefficiencyItem `json:"potential_allocations,omitempty"`
}
type InefficiencyItem struct {
Type string `json:"type"`
Description string `json:"description"`
Suggestion string `json:"suggestion"`
Position Position `json:"position"`
}
func findInefficiencies(dir string) ([]InefficiencyInfo, error) {
var inefficiencies []InefficiencyInfo
err := walkGoFiles(dir, func(path string, src []byte, file *ast.File, fset *token.FileSet) error {
info := InefficiencyInfo{
File: path,
}
ast.Inspect(file, func(n ast.Node) bool {
// Find string concatenation in loops
if forStmt, ok := n.(*ast.ForStmt); ok {
ast.Inspect(forStmt.Body, func(inner ast.Node) bool {
if binExpr, ok := inner.(*ast.BinaryExpr); ok && binExpr.Op == token.ADD {
if ineffIsStringType(binExpr.X) || ineffIsStringType(binExpr.Y) {
pos := fset.Position(binExpr.Pos())
info.StringConcat = append(info.StringConcat, InefficiencyItem{
Type: "string_concatenation_in_loop",
Description: "String concatenation in loop can be inefficient",
Suggestion: "Consider using strings.Builder",
Position: newPosition(pos),
})
}
}
return true
})
}
// Find unnecessary type conversions
if callExpr, ok := n.(*ast.CallExpr); ok {
if len(callExpr.Args) == 1 {
if ident, ok := callExpr.Fun.(*ast.Ident); ok {
argType := getExprType(callExpr.Args[0])
if ident.Name == argType {
pos := fset.Position(callExpr.Pos())
info.Conversions = append(info.Conversions, InefficiencyItem{
Type: "unnecessary_conversion",
Description: fmt.Sprintf("Unnecessary conversion to %s", ident.Name),
Suggestion: "Remove unnecessary type conversion",
Position: newPosition(pos),
})
}
}
}
}
return true
})
if len(info.StringConcat) > 0 || len(info.Conversions) > 0 || len(info.Allocations) > 0 {
inefficiencies = append(inefficiencies, info)
}
return nil
})
return inefficiencies, err
}
func ineffIsStringType(expr ast.Expr) bool {
if ident, ok := expr.(*ast.Ident); ok {
return ident.Name == "string"
}
return false
}
func getExprType(expr ast.Expr) string {
if ident, ok := expr.(*ast.Ident); ok {
return ident.Name
}
return "unknown"
}