Skip to content

Commit

Permalink
cl: types record check selection/index expr is address
Browse files Browse the repository at this point in the history
  • Loading branch information
visualfc committed Mar 4, 2024
1 parent d66dbca commit ae04571
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 8 deletions.
46 changes: 46 additions & 0 deletions cl/compile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4383,3 +4383,49 @@ func main() {
}
`)
}

func TestAddress(t *testing.T) {
gopClTest(t, `
type foo struct{ c int }
func (f foo) ptr() *foo { return &f }
func (f foo) clone() foo { return f }
type nested struct {
f foo
}
func _() {
getNested := func() nested { return nested{} }
_ = getNested().f.c
_ = getNested().f.ptr().c
_ = getNested().f.clone().c
_ = getNested().f.clone().ptr().c
}
`, `package main
type foo struct {
c int
}
type nested struct {
f foo
}
func (f foo) ptr() *foo {
return &f
}
func (f foo) clone() foo {
return f
}
func _() {
getNested := func() nested {
return nested{}
}
_ = getNested().f.c
_ = getNested().f.ptr().c
_ = getNested().f.clone().c
_ = getNested().f.clone().ptr().c
}
`)
}
44 changes: 36 additions & 8 deletions cl/recorder.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,29 @@ import (
)

type goxRecorder struct {
rec Recorder
rec *typesRecorder
}

// Member maps identifiers to the objects they denote.
func (p *goxRecorder) Member(id ast.Node, obj types.Object) {
tv := typesutil.NewTypeAndValueForObject(obj)
switch v := id.(type) {
case *ast.SelectorExpr:
sel := v.Sel
// TODO: record event for a Go ident
if _, ok := fromgo.CheckIdent(sel); !ok {
var tv types.TypeAndValue
// check v.X call result by value
if f, ok := obj.(*types.Var); ok && f.IsField() && p.rec.checkExprByValue(v.X) {
tv = typesutil.NewTypeAndValueForValue(obj.Type(), nil, typesutil.Value)
} else {
tv = typesutil.NewTypeAndValueForObject(obj)
}
p.rec.Use(sel, obj)
p.rec.Type(v, tv)
}
case *ast.Ident: // it's in a classfile and impossible converted from Go
p.rec.Use(v, obj)
p.rec.Type(v, tv)
p.rec.Type(v, typesutil.NewTypeAndValueForObject(obj))
}
}

Expand Down Expand Up @@ -71,6 +77,22 @@ type typesRecorder struct {
types map[ast.Expr]types.TypeAndValue
}

func (rec *typesRecorder) checkExprByValue(v ast.Expr) bool {
if tv, ok := rec.types[v]; ok {
switch v.(type) {
case *ast.CallExpr:
if _, ok := tv.Type.(*types.Pointer); !ok {
return true
}
default:
if tv, ok := rec.types[v]; ok {
return !tv.Addressable()
}
}
}
return false
}

func (rec *typesRecorder) Type(expr ast.Expr, tv types.TypeAndValue) {
rec.types[expr] = tv
rec.Recorder.Type(expr, tv)
Expand Down Expand Up @@ -117,12 +139,16 @@ func (rec *typesRecorder) indexExpr(ctx *blockCtx, expr *ast.IndexExpr) {
return
}
}
switch expr.X.(type) {
op := typesutil.Variable
switch e := expr.X.(type) {
case *ast.CompositeLit:
rec.recordTypeValue(ctx, expr, typesutil.Value)
default:
rec.recordTypeValue(ctx, expr, typesutil.Variable)
op = typesutil.Value
case *ast.SelectorExpr:
if rec.checkExprByValue(e.X) {
op = typesutil.Value
}

Check warning on line 149 in cl/recorder.go

View check run for this annotation

Codecov / codecov/patch

cl/recorder.go#L145-L149

Added lines #L145 - L149 were not covered by tests
}
rec.recordTypeValue(ctx, expr, op)
}

func (rec *typesRecorder) unaryExpr(ctx *blockCtx, expr *ast.UnaryExpr) {
Expand Down Expand Up @@ -168,7 +194,9 @@ func (rec *typesRecorder) recordExpr(ctx *blockCtx, expr ast.Expr, rhs bool) {
rec.recordTypeValue(ctx, v, typesutil.Value)
case *ast.CallExpr:
case *ast.SelectorExpr:
rec.recordTypeValue(ctx, v, typesutil.Variable)
if _, ok := rec.types[v]; !ok {
rec.recordTypeValue(ctx, v, typesutil.Variable)
}
case *ast.BinaryExpr:
rec.recordTypeValue(ctx, v, typesutil.Value)
case *ast.UnaryExpr:
Expand Down
38 changes: 38 additions & 0 deletions x/typesutil/info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1841,3 +1841,41 @@ func TestScopesInfo(t *testing.T) {
}
}
}

func TestAddress(t *testing.T) {
testInfo(t, `package address
type foo struct{ c int; p *int }
func (f foo) ptr() *foo { return &f }
func (f foo) clone() foo { return f }
type nested struct {
f foo
a [2]foo
s []foo
m map[int]foo
}
func _() {
getNested := func() nested { return nested{} }
getNestedPtr := func() *nested { return &nested{} }
_ = getNested().f.c
_ = getNested().a[0].c
_ = getNested().s[0].c
_ = getNested().m[0].c
_ = getNested().f.ptr().c
_ = getNested().f.clone().c
_ = getNested().f.clone().ptr().c
_ = getNestedPtr().f.c
_ = getNestedPtr().a[0].c
_ = getNestedPtr().s[0].c
_ = getNestedPtr().m[0].c
_ = getNestedPtr().f.ptr().c
_ = getNestedPtr().f.clone().c
_ = getNestedPtr().f.clone().ptr().c
}
`)
}

0 comments on commit ae04571

Please sign in to comment.