Files
llgo/cl/rewrite_internal_test.go
xgopilot 034b05c53c cl: remove Underlying() call to reject string type aliases in rewrites
Type aliases like `type T string` are no longer supported for
-ldflags -X rewrites. Only direct *string types are now allowed.

- Removed Underlying() call from isStringPtrType
- Added TestRewriteIgnoresStringAlias test case

Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: cpunion <8459+cpunion@users.noreply.github.com>
2025-11-14 14:49:30 +00:00

170 lines
4.9 KiB
Go

//go:build !llgo
// +build !llgo
package cl
import (
"go/ast"
"go/parser"
"go/token"
"go/types"
"runtime"
"strings"
"testing"
gpackages "github.com/goplus/gogen/packages"
llssa "github.com/goplus/llgo/ssa"
"github.com/goplus/llgo/ssa/ssatest"
"golang.org/x/tools/go/ssa"
"golang.org/x/tools/go/ssa/ssautil"
)
func init() {
llssa.Initialize(llssa.InitAll | llssa.InitNative)
}
func compileWithRewrites(t *testing.T, src string, rewrites map[string]string) string {
t.Helper()
fset := token.NewFileSet()
file, err := parser.ParseFile(fset, "rewrite.go", src, 0)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
importer := gpackages.NewImporter(fset)
mode := ssa.SanityCheckFunctions | ssa.InstantiateGenerics
pkg, _, err := ssautil.BuildPackage(&types.Config{Importer: importer}, fset,
types.NewPackage(file.Name.Name, file.Name.Name), []*ast.File{file}, mode)
if err != nil {
t.Fatalf("build package failed: %v", err)
}
prog := ssatest.NewProgramEx(t, nil, importer)
prog.TypeSizes(types.SizesFor("gc", runtime.GOARCH))
ret, _, err := NewPackageEx(prog, nil, rewrites, pkg, []*ast.File{file})
if err != nil {
t.Fatalf("NewPackageEx failed: %v", err)
}
return ret.String()
}
func TestRewriteGlobalStrings(t *testing.T) {
const src = `package rewritepkg
var VarInit = "original_value"
var VarPlain string
func Use() string { return VarInit + VarPlain }
`
ir := compileWithRewrites(t, src, map[string]string{
"VarInit": "rewrite_init",
"VarPlain": "rewrite_plain",
})
if strings.Contains(ir, "original_value") {
t.Fatalf("original initializer still present:\n%s", ir)
}
for _, want := range []string{`c"rewrite_init"`, `c"rewrite_plain"`} {
if !strings.Contains(ir, want) {
t.Fatalf("missing %s in IR:\n%s", want, ir)
}
}
}
func TestRewriteSkipsNonConstStores(t *testing.T) {
const src = `package rewritepkg
import "strings"
var VarInit = strings.ToUpper("original_value")
var VarPlain string
func Use() string { return VarInit + VarPlain }
`
ir := compileWithRewrites(t, src, map[string]string{
"VarInit": "rewrite_init",
"VarPlain": "rewrite_plain",
})
if !strings.Contains(ir, `c"rewrite_init"`) {
t.Fatalf("expected rewrite_init constant to remain:\n%s", ir)
}
if !strings.Contains(ir, "strings.ToUpper") {
t.Fatalf("expected call to strings.ToUpper in IR:\n%s", ir)
}
}
func TestRewriteValueNoDot(t *testing.T) {
ctx := &context{rewrites: map[string]string{"VarInit": "rewrite_init"}}
if _, ok := ctx.rewriteValue("VarInit"); ok {
t.Fatalf("rewriteValue should skip names without package prefix")
}
if _, ok := ctx.rewriteValue("pkg."); ok {
t.Fatalf("rewriteValue should skip trailing dot names")
}
}
func TestIsStringPtrTypeDefault(t *testing.T) {
ctx := &context{}
if ctx.isStringPtrType(types.NewPointer(types.Typ[types.Int])) {
t.Fatalf("expected non-string pointer to return false")
}
}
func TestIsStringPtrTypeBranches(t *testing.T) {
ctx := &context{}
if ctx.isStringPtrType(types.NewSlice(types.Typ[types.String])) {
t.Fatalf("slice should trigger default branch and return false")
}
if ctx.isStringPtrType(nil) {
t.Fatalf("nil type should return false")
}
if !ctx.isStringPtrType(types.NewPointer(types.Typ[types.String])) {
t.Fatalf("*string should return true")
}
}
func TestRewriteIgnoredInNonInitStore(t *testing.T) {
const src = `package rewritepkg
var VarInit = "original_value"
func Override() { VarInit = "override_value" }
`
ir := compileWithRewrites(t, src, map[string]string{"VarInit": "rewrite_init"})
if !strings.Contains(ir, `c"override_value"`) {
t.Fatalf("override store should retain original literal:\n%s", ir)
}
if !strings.Contains(ir, `c"rewrite_init"`) {
t.Fatalf("global initializer should still be rewritten:\n%s", ir)
}
}
func TestRewriteMissingEntry(t *testing.T) {
const src = `package rewritepkg
var VarInit = "original_value"
var VarOther = "other_value"
`
ir := compileWithRewrites(t, src, map[string]string{"VarInit": "rewrite_init"})
if !strings.Contains(ir, `c"other_value"`) {
t.Fatalf("VarOther should keep original initializer:\n%s", ir)
}
if !strings.Contains(ir, `c"rewrite_init"`) {
t.Fatalf("VarInit should still be rewritten:\n%s", ir)
}
}
func TestRewriteIgnoresNonStringVar(t *testing.T) {
const src = `package rewritepkg
type wrapper struct{ v int }
var VarStruct = wrapper{v: 1}
`
ir := compileWithRewrites(t, src, map[string]string{"VarStruct": "rewrite_struct"})
if strings.Contains(ir, `c"rewrite_struct"`) {
t.Fatalf("non-string variables must not be rewritten:\n%s", ir)
}
}
func TestRewriteIgnoresStringAlias(t *testing.T) {
const src = `package rewritepkg
type T string
var VarAlias T = "original_value"
`
ir := compileWithRewrites(t, src, map[string]string{"VarAlias": "rewrite_alias"})
if strings.Contains(ir, `c"rewrite_alias"`) {
t.Fatalf("string alias types must not be rewritten:\n%s", ir)
}
if !strings.Contains(ir, `c"original_value"`) {
t.Fatalf("original value should remain for alias type:\n%s", ir)
}
}