rlp/rlpgen: implement package renaming support

This commit adds support for package renaming in the RLP code generator to handle
import name conflicts. Key changes include:

- Added automatic package alias generation for conflicting imports
- Implemented package loading to get correct package names
- Modified import handling to support aliased imports
- Updated importsList to generate proper import statements with aliases
- Added helper functions for alias management

The changes allow the code generator to handle cases where multiple imported
packages have the same base name by automatically generating unique aliases,
improving the robustness of the generated code.
This commit is contained in:
VolodymyrBg 2025-02-09 21:35:55 +02:00 committed by Felix Lange
parent d4a3bf1b23
commit e1c23fa1f3

View file

@ -22,8 +22,10 @@ import (
"go/format" "go/format"
"go/types" "go/types"
"sort" "sort"
"strings"
"github.com/ethereum/go-ethereum/rlp/internal/rlpstruct" "github.com/ethereum/go-ethereum/rlp/internal/rlpstruct"
"golang.org/x/tools/go/packages"
) )
// buildContext keeps the data needed for make*Op. // buildContext keeps the data needed for make*Op.
@ -96,14 +98,15 @@ func (bctx *buildContext) typeToStructType(typ types.Type) *rlpstruct.Type {
// file and assigns unique names of temporary variables. // file and assigns unique names of temporary variables.
type genContext struct { type genContext struct {
inPackage *types.Package inPackage *types.Package
imports map[string]struct{} imports map[string]string // Changed from map[string]struct{} to map[string]string to store package aliases
tempCounter int tempCounter int
} }
func newGenContext(inPackage *types.Package) *genContext { func newGenContext(inPackage *types.Package) *genContext {
return &genContext{ return &genContext{
inPackage: inPackage, inPackage: inPackage,
imports: make(map[string]struct{}), imports: make(map[string]string),
tempCounter: 0,
} }
} }
@ -117,32 +120,83 @@ func (ctx *genContext) resetTemp() {
ctx.tempCounter = 0 ctx.tempCounter = 0
} }
func (ctx *genContext) addImport(path string) { func (ctx *genContext) addImport(path string) string {
if path == ctx.inPackage.Path() { if path == ctx.inPackage.Path() {
return // avoid importing the package that we're generating in. return "" // avoid importing the package that we're generating in
} }
// TODO: renaming?
ctx.imports[path] = struct{}{} // Check if we already have an alias for this package
if alias, exists := ctx.imports[path]; exists {
return alias
}
// Get the package name and check for conflicts
pkg, err := ctx.loadPackage(path)
if err != nil {
// If we can't load the package, use the last component of the path
parts := strings.Split(path, "/")
pkg = types.NewPackage(path, parts[len(parts)-1])
}
baseName := pkg.Name()
alias := baseName
counter := 1
// If the base name conflicts with any existing import, add a numeric suffix
for ctx.hasAlias(alias) {
alias = fmt.Sprintf("%s%d", baseName, counter)
counter++
}
ctx.imports[path] = alias
return alias
} }
// importsList returns all packages that need to be imported. // hasAlias checks if an alias is already in use
func (ctx *genContext) importsList() []string { func (ctx *genContext) hasAlias(alias string) bool {
imp := make([]string, 0, len(ctx.imports)) for _, existingAlias := range ctx.imports {
for k := range ctx.imports { if existingAlias == alias {
imp = append(imp, k) return true
}
} }
sort.Strings(imp) return false
return imp
} }
// qualify is the types.Qualifier used for printing types. // loadPackage attempts to load package information
func (ctx *genContext) loadPackage(path string) (*types.Package, error) {
cfg := &packages.Config{Mode: packages.NeedName}
pkgs, err := packages.Load(cfg, path)
if err != nil {
return nil, err
}
if len(pkgs) == 0 {
return nil, fmt.Errorf("no package found for path %s", path)
}
return types.NewPackage(path, pkgs[0].Name), nil
}
// qualify is the types.Qualifier used for printing types
func (ctx *genContext) qualify(pkg *types.Package) string { func (ctx *genContext) qualify(pkg *types.Package) string {
if pkg.Path() == ctx.inPackage.Path() { if pkg.Path() == ctx.inPackage.Path() {
return "" return ""
} }
ctx.addImport(pkg.Path()) return ctx.addImport(pkg.Path())
// TODO: renaming? }
return pkg.Name()
// importsList returns all packages that need to be imported
func (ctx *genContext) importsList() []string {
imp := make([]string, 0, len(ctx.imports))
for path, alias := range ctx.imports {
if alias == pkg.Name() {
// If the alias matches the package name, use standard import
imp = append(imp, fmt.Sprintf("%q", path))
} else {
// If we have a custom alias, use aliased import
imp = append(imp, fmt.Sprintf("%s %q", alias, path))
}
}
sort.Strings(imp)
return imp
} }
type op interface { type op interface {