go.tools/pointer: more reflection operators.
(reflect.Value).Bytes (reflect.Value).Elem (reflect.Value).Index (reflect.Value).SetBytes (reflect.Value).Slice reflect.PtrTo reflect.SliceOf + Tests. Also: comment out an 'info-'level print statement in the test; it was distracting. R=crawshaw CC=golang-dev https://golang.org/cl/14454055
This commit is contained in:
parent
271af2c149
commit
aff951c80f
|
@ -37,6 +37,7 @@ var inputs = []string{
|
|||
// Working:
|
||||
"testdata/a_test.go",
|
||||
"testdata/another.go",
|
||||
"testdata/arrayreflect.go",
|
||||
"testdata/arrays.go",
|
||||
"testdata/channels.go",
|
||||
"testdata/chanreflect.go",
|
||||
|
@ -45,9 +46,9 @@ var inputs = []string{
|
|||
"testdata/flow.go",
|
||||
"testdata/fmtexcerpt.go",
|
||||
"testdata/func.go",
|
||||
"testdata/funcreflect.go",
|
||||
"testdata/hello.go",
|
||||
"testdata/interfaces.go",
|
||||
"testdata/funcreflect.go",
|
||||
"testdata/mapreflect.go",
|
||||
"testdata/maps.go",
|
||||
"testdata/panic.go",
|
||||
|
@ -58,7 +59,6 @@ var inputs = []string{
|
|||
// TODO(adonovan): get these tests (of reflection) passing.
|
||||
// (The tests are mostly sound since they were used for a
|
||||
// previous implementation.)
|
||||
// "testdata/arrayreflect.go",
|
||||
// "testdata/finalizer.go",
|
||||
// "testdata/structreflect.go",
|
||||
}
|
||||
|
@ -193,7 +193,7 @@ func doOneInput(input, filename string) bool {
|
|||
if mainpkg.Func("main") == nil {
|
||||
// No main function; assume it's a test.
|
||||
mainpkg.CreateTestMainFunction()
|
||||
fmt.Printf("%s: synthesized testmain package for test.\n", imp.Fset.Position(f.Package))
|
||||
// fmt.Printf("%s: synthesized testmain package for test.\n", imp.Fset.Position(f.Package))
|
||||
}
|
||||
|
||||
ok := true
|
||||
|
|
|
@ -32,16 +32,174 @@ import (
|
|||
// -------------------- (reflect.Value) --------------------
|
||||
|
||||
func ext۰reflect۰Value۰Addr(a *analysis, cgn *cgnode) {}
|
||||
func ext۰reflect۰Value۰Bytes(a *analysis, cgn *cgnode) {}
|
||||
|
||||
// ---------- func (Value).Bytes() Value ----------
|
||||
|
||||
// result = v.Bytes()
|
||||
type rVBytesConstraint struct {
|
||||
v nodeid // (ptr)
|
||||
result nodeid
|
||||
}
|
||||
|
||||
func (c *rVBytesConstraint) String() string {
|
||||
return fmt.Sprintf("n%d = reflect n%d.Bytes()", c.result, c.v)
|
||||
}
|
||||
|
||||
func (c *rVBytesConstraint) ptr() nodeid {
|
||||
return c.v
|
||||
}
|
||||
|
||||
func (c *rVBytesConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||
changed := false
|
||||
for vObj := range delta {
|
||||
tDyn, slice, indirect := a.taggedValue(vObj)
|
||||
if indirect {
|
||||
// TODO(adonovan): we'll need to implement this
|
||||
// when we start creating indirect tagged objects.
|
||||
panic("indirect tagged object")
|
||||
}
|
||||
|
||||
tSlice, ok := tDyn.Underlying().(*types.Slice)
|
||||
if ok && types.IsIdentical(tSlice.Elem(), types.Typ[types.Uint8]) {
|
||||
if a.onlineCopy(c.result, slice) {
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if changed {
|
||||
a.addWork(c.result)
|
||||
}
|
||||
}
|
||||
|
||||
func ext۰reflect۰Value۰Bytes(a *analysis, cgn *cgnode) {
|
||||
a.addConstraint(&rVBytesConstraint{
|
||||
v: a.funcParams(cgn.obj),
|
||||
result: a.funcResults(cgn.obj),
|
||||
})
|
||||
}
|
||||
|
||||
func ext۰reflect۰Value۰Call(a *analysis, cgn *cgnode) {}
|
||||
func ext۰reflect۰Value۰CallSlice(a *analysis, cgn *cgnode) {}
|
||||
func ext۰reflect۰Value۰Convert(a *analysis, cgn *cgnode) {}
|
||||
func ext۰reflect۰Value۰Elem(a *analysis, cgn *cgnode) {}
|
||||
|
||||
// ---------- func (Value).Elem() Value ----------
|
||||
|
||||
// result = v.Elem()
|
||||
type rVElemConstraint struct {
|
||||
cgn *cgnode
|
||||
v nodeid // (ptr)
|
||||
result nodeid
|
||||
}
|
||||
|
||||
func (c *rVElemConstraint) String() string {
|
||||
return fmt.Sprintf("n%d = reflect n%d.Elem()", c.result, c.v)
|
||||
}
|
||||
|
||||
func (c *rVElemConstraint) ptr() nodeid {
|
||||
return c.v
|
||||
}
|
||||
|
||||
func (c *rVElemConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||
changed := false
|
||||
for vObj := range delta {
|
||||
tDyn, payload, indirect := a.taggedValue(vObj)
|
||||
if indirect {
|
||||
// TODO(adonovan): we'll need to implement this
|
||||
// when we start creating indirect tagged objects.
|
||||
panic("indirect tagged object")
|
||||
}
|
||||
|
||||
switch t := tDyn.Underlying().(type) {
|
||||
case *types.Interface:
|
||||
// A direct tagged object can't hold an
|
||||
// interface type. Implement when we support
|
||||
// indirect tagged objects.
|
||||
panic("unreachable")
|
||||
|
||||
case *types.Pointer:
|
||||
obj := a.makeTagged(t.Elem(), c.cgn, nil)
|
||||
a.load(obj+1, payload, 0, a.sizeof(t.Elem()))
|
||||
if a.addLabel(c.result, obj) {
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if changed {
|
||||
a.addWork(c.result)
|
||||
}
|
||||
}
|
||||
|
||||
func ext۰reflect۰Value۰Elem(a *analysis, cgn *cgnode) {
|
||||
a.addConstraint(&rVElemConstraint{
|
||||
cgn: cgn,
|
||||
v: a.funcParams(cgn.obj),
|
||||
result: a.funcResults(cgn.obj),
|
||||
})
|
||||
}
|
||||
|
||||
func ext۰reflect۰Value۰Field(a *analysis, cgn *cgnode) {}
|
||||
func ext۰reflect۰Value۰FieldByIndex(a *analysis, cgn *cgnode) {}
|
||||
func ext۰reflect۰Value۰FieldByName(a *analysis, cgn *cgnode) {}
|
||||
func ext۰reflect۰Value۰FieldByNameFunc(a *analysis, cgn *cgnode) {}
|
||||
func ext۰reflect۰Value۰Index(a *analysis, cgn *cgnode) {}
|
||||
|
||||
// ---------- func (Value).Index() Value ----------
|
||||
|
||||
// result = v.Index()
|
||||
type rVIndexConstraint struct {
|
||||
cgn *cgnode
|
||||
v nodeid // (ptr)
|
||||
result nodeid
|
||||
}
|
||||
|
||||
func (c *rVIndexConstraint) String() string {
|
||||
return fmt.Sprintf("n%d = reflect n%d.Index()", c.result, c.v)
|
||||
}
|
||||
|
||||
func (c *rVIndexConstraint) ptr() nodeid {
|
||||
return c.v
|
||||
}
|
||||
|
||||
func (c *rVIndexConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||
changed := false
|
||||
for vObj := range delta {
|
||||
tDyn, payload, indirect := a.taggedValue(vObj)
|
||||
if indirect {
|
||||
// TODO(adonovan): we'll need to implement this
|
||||
// when we start creating indirect tagged objects.
|
||||
panic("indirect tagged object")
|
||||
}
|
||||
|
||||
var res nodeid
|
||||
switch t := tDyn.Underlying().(type) {
|
||||
case *types.Array:
|
||||
res = a.makeTagged(t.Elem(), c.cgn, nil)
|
||||
a.onlineCopyN(res+1, payload+1, a.sizeof(t.Elem()))
|
||||
|
||||
case *types.Slice:
|
||||
res = a.makeTagged(t.Elem(), c.cgn, nil)
|
||||
a.load(res+1, payload, 1, a.sizeof(t.Elem()))
|
||||
|
||||
case *types.Basic:
|
||||
if t.Kind() == types.String {
|
||||
res = a.makeTagged(types.Typ[types.Rune], c.cgn, nil)
|
||||
}
|
||||
}
|
||||
if res != 0 && a.addLabel(c.result, res) {
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
if changed {
|
||||
a.addWork(c.result)
|
||||
}
|
||||
}
|
||||
|
||||
func ext۰reflect۰Value۰Index(a *analysis, cgn *cgnode) {
|
||||
a.addConstraint(&rVIndexConstraint{
|
||||
cgn: cgn,
|
||||
v: a.funcParams(cgn.obj),
|
||||
result: a.funcResults(cgn.obj),
|
||||
})
|
||||
}
|
||||
|
||||
// ---------- func (Value).Interface() Value ----------
|
||||
|
||||
|
@ -297,7 +455,50 @@ func ext۰reflect۰Value۰Send(a *analysis, cgn *cgnode) {
|
|||
}
|
||||
|
||||
func ext۰reflect۰Value۰Set(a *analysis, cgn *cgnode) {}
|
||||
func ext۰reflect۰Value۰SetBytes(a *analysis, cgn *cgnode) {}
|
||||
|
||||
// ---------- func (Value).SetBytes(x []byte) ----------
|
||||
|
||||
// v.SetBytes(x)
|
||||
type rVSetBytesConstraint struct {
|
||||
cgn *cgnode
|
||||
v nodeid // (ptr)
|
||||
x nodeid
|
||||
}
|
||||
|
||||
func (c *rVSetBytesConstraint) String() string {
|
||||
return fmt.Sprintf("reflect n%d.SetBytes(n%d)", c.v, c.x)
|
||||
}
|
||||
|
||||
func (c *rVSetBytesConstraint) ptr() nodeid {
|
||||
return c.v
|
||||
}
|
||||
|
||||
func (c *rVSetBytesConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||
for vObj := range delta {
|
||||
tDyn, slice, indirect := a.taggedValue(vObj)
|
||||
if indirect {
|
||||
// TODO(adonovan): we'll need to implement this
|
||||
// when we start creating indirect tagged objects.
|
||||
panic("indirect tagged object")
|
||||
}
|
||||
|
||||
tSlice, ok := tDyn.Underlying().(*types.Slice)
|
||||
if ok && types.IsIdentical(tSlice.Elem(), types.Typ[types.Uint8]) {
|
||||
if a.onlineCopy(slice, c.x) {
|
||||
a.addWork(slice)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ext۰reflect۰Value۰SetBytes(a *analysis, cgn *cgnode) {
|
||||
params := a.funcParams(cgn.obj)
|
||||
a.addConstraint(&rVSetBytesConstraint{
|
||||
cgn: cgn,
|
||||
v: params,
|
||||
x: params + 1,
|
||||
})
|
||||
}
|
||||
|
||||
// ---------- func (Value).SetMapIndex(k Value, v Value) ----------
|
||||
|
||||
|
@ -355,7 +556,74 @@ func ext۰reflect۰Value۰SetMapIndex(a *analysis, cgn *cgnode) {
|
|||
}
|
||||
|
||||
func ext۰reflect۰Value۰SetPointer(a *analysis, cgn *cgnode) {}
|
||||
func ext۰reflect۰Value۰Slice(a *analysis, cgn *cgnode) {}
|
||||
|
||||
// ---------- func (Value).Slice(v Value, i, j int) ----------
|
||||
|
||||
// result = v.Slice(_, _)
|
||||
type rVSliceConstraint struct {
|
||||
cgn *cgnode
|
||||
v nodeid // (ptr)
|
||||
result nodeid
|
||||
}
|
||||
|
||||
func (c *rVSliceConstraint) String() string {
|
||||
return fmt.Sprintf("n%d = reflect n%d.Slice(_, _)", c.result, c.v)
|
||||
}
|
||||
|
||||
func (c *rVSliceConstraint) ptr() nodeid {
|
||||
return c.v
|
||||
}
|
||||
|
||||
func (c *rVSliceConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||
changed := false
|
||||
for vObj := range delta {
|
||||
tDyn, payload, indirect := a.taggedValue(vObj)
|
||||
if indirect {
|
||||
// TODO(adonovan): we'll need to implement this
|
||||
// when we start creating indirect tagged objects.
|
||||
panic("indirect tagged object")
|
||||
}
|
||||
|
||||
var res nodeid
|
||||
switch t := tDyn.Underlying().(type) {
|
||||
case *types.Pointer:
|
||||
if tArr, ok := t.Elem().Underlying().(*types.Array); ok {
|
||||
// pointer to array
|
||||
res = a.makeTagged(types.NewSlice(tArr.Elem()), c.cgn, nil)
|
||||
if a.onlineCopy(res+1, payload) {
|
||||
a.addWork(res + 1)
|
||||
}
|
||||
}
|
||||
|
||||
case *types.Array:
|
||||
// TODO(adonovan): implement addressable
|
||||
// arrays when we do indirect tagged objects.
|
||||
|
||||
case *types.Slice:
|
||||
res = vObj
|
||||
|
||||
case *types.Basic:
|
||||
if t == types.Typ[types.String] {
|
||||
res = vObj
|
||||
}
|
||||
}
|
||||
|
||||
if res != 0 && a.addLabel(c.result, res) {
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
if changed {
|
||||
a.addWork(c.result)
|
||||
}
|
||||
}
|
||||
|
||||
func ext۰reflect۰Value۰Slice(a *analysis, cgn *cgnode) {
|
||||
a.addConstraint(&rVSliceConstraint{
|
||||
cgn: cgn,
|
||||
v: a.funcParams(cgn.obj),
|
||||
result: a.funcResults(cgn.obj),
|
||||
})
|
||||
}
|
||||
|
||||
// -------------------- Standalone reflect functions --------------------
|
||||
|
||||
|
@ -648,9 +916,85 @@ func ext۰reflect۰NewAt(a *analysis, cgn *cgnode) {
|
|||
}
|
||||
}
|
||||
|
||||
func ext۰reflect۰PtrTo(a *analysis, cgn *cgnode) {}
|
||||
// ---------- func PtrTo(Type) Type ----------
|
||||
|
||||
// result = PtrTo(t)
|
||||
type reflectPtrToConstraint struct {
|
||||
cgn *cgnode
|
||||
t nodeid // (ptr)
|
||||
result nodeid
|
||||
}
|
||||
|
||||
func (c *reflectPtrToConstraint) String() string {
|
||||
return fmt.Sprintf("n%d = reflect.PtrTo(n%d)", c.result, c.t)
|
||||
}
|
||||
|
||||
func (c *reflectPtrToConstraint) ptr() nodeid {
|
||||
return c.t
|
||||
}
|
||||
|
||||
func (c *reflectPtrToConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||
changed := false
|
||||
for tObj := range delta {
|
||||
T := a.rtypeTaggedValue(tObj)
|
||||
|
||||
if a.addLabel(c.result, a.makeRtype(types.NewPointer(T))) {
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
if changed {
|
||||
a.addWork(c.result)
|
||||
}
|
||||
}
|
||||
|
||||
func ext۰reflect۰PtrTo(a *analysis, cgn *cgnode) {
|
||||
a.addConstraint(&reflectPtrToConstraint{
|
||||
cgn: cgn,
|
||||
t: a.funcParams(cgn.obj),
|
||||
result: a.funcResults(cgn.obj),
|
||||
})
|
||||
}
|
||||
|
||||
func ext۰reflect۰Select(a *analysis, cgn *cgnode) {}
|
||||
func ext۰reflect۰SliceOf(a *analysis, cgn *cgnode) {}
|
||||
|
||||
// ---------- func SliceOf(Type) Type ----------
|
||||
|
||||
// result = SliceOf(t)
|
||||
type reflectSliceOfConstraint struct {
|
||||
cgn *cgnode
|
||||
t nodeid // (ptr)
|
||||
result nodeid
|
||||
}
|
||||
|
||||
func (c *reflectSliceOfConstraint) String() string {
|
||||
return fmt.Sprintf("n%d = reflect.SliceOf(n%d)", c.result, c.t)
|
||||
}
|
||||
|
||||
func (c *reflectSliceOfConstraint) ptr() nodeid {
|
||||
return c.t
|
||||
}
|
||||
|
||||
func (c *reflectSliceOfConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||
changed := false
|
||||
for tObj := range delta {
|
||||
T := a.rtypeTaggedValue(tObj)
|
||||
|
||||
if a.addLabel(c.result, a.makeRtype(types.NewSlice(T))) {
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
if changed {
|
||||
a.addWork(c.result)
|
||||
}
|
||||
}
|
||||
|
||||
func ext۰reflect۰SliceOf(a *analysis, cgn *cgnode) {
|
||||
a.addConstraint(&reflectSliceOfConstraint{
|
||||
cgn: cgn,
|
||||
t: a.funcParams(cgn.obj),
|
||||
result: a.funcResults(cgn.obj),
|
||||
})
|
||||
}
|
||||
|
||||
// ---------- func TypeOf(v Value) Type ----------
|
||||
|
||||
|
|
|
@ -193,6 +193,10 @@ func (a *analysis) onlineCopy(dst, src nodeid) bool {
|
|||
if a.log != nil {
|
||||
fmt.Fprintf(a.log, "\t\t\tdynamic copy n%d <- n%d\n", dst, src)
|
||||
}
|
||||
// TODO(adonovan): most calls to onlineCopy
|
||||
// are followed by addWork, possibly batched
|
||||
// via a 'changed' flag; see if there's a
|
||||
// noticeable penalty to calling addWork here.
|
||||
return a.nodes[dst].pts.addAll(nsrc.pts)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,107 +2,170 @@
|
|||
|
||||
package main
|
||||
|
||||
import "reflect"
|
||||
|
||||
// Test of arrays & slices with reflection.
|
||||
|
||||
var a int
|
||||
import "reflect"
|
||||
|
||||
func arrayreflect1() {
|
||||
sl := make([]*int, 10) // @line ar1make
|
||||
sl[0] = &a
|
||||
var a, b int
|
||||
|
||||
srv := reflect.ValueOf(sl).Slice(0, 0)
|
||||
print(srv.Interface()) // @types []*int
|
||||
print(srv.Interface().([]*int)) // @pointsto makeslice@ar1make:12
|
||||
print(srv.Interface().([]*int)[42]) // @pointsto main.a
|
||||
type S string
|
||||
|
||||
func reflectValueSlice() {
|
||||
// reflect.Value contains a slice.
|
||||
slice := make([]*int, 10) // @line slice
|
||||
slice[0] = &a
|
||||
rvsl := reflect.ValueOf(slice).Slice(0, 0)
|
||||
print(rvsl.Interface()) // @types []*int
|
||||
print(rvsl.Interface().([]*int)) // @pointsto makeslice@slice:15
|
||||
print(rvsl.Interface().([]*int)[42]) // @pointsto main.a
|
||||
|
||||
// reflect.Value contains an arrayay (non-addressable).
|
||||
array := [10]*int{&a} // @line array
|
||||
rvarray := reflect.ValueOf(array).Slice(0, 0)
|
||||
print(rvarray.Interface()) // @types
|
||||
print(rvarray.Interface().([]*int)) // @pointsto
|
||||
print(rvarray.Interface().([]*int)[42]) // @pointsto
|
||||
|
||||
// reflect.Value contains a pointer-to-array
|
||||
rvparray := reflect.ValueOf(&array).Slice(0, 0)
|
||||
print(rvparray.Interface()) // @types []*int
|
||||
print(rvparray.Interface().([]*int)) // @pointsto array@array:2
|
||||
print(rvparray.Interface().([]*int)[42]) // @pointsto main.a
|
||||
|
||||
// reflect.Value contains a string.
|
||||
rvstring := reflect.ValueOf("hi").Slice(0, 0)
|
||||
print(rvstring.Interface()) // @types string
|
||||
|
||||
// reflect.Value contains a (named) string type.
|
||||
rvS := reflect.ValueOf(S("hi")).Slice(0, 0)
|
||||
print(rvS.Interface()) // @types S
|
||||
|
||||
// reflect.Value contains a non-array pointer.
|
||||
rvptr := reflect.ValueOf(new(int)).Slice(0, 0)
|
||||
print(rvptr.Interface()) // @types
|
||||
|
||||
// reflect.Value contains a non-string basic type.
|
||||
rvint := reflect.ValueOf(3).Slice(0, 0)
|
||||
print(rvint.Interface()) // @types
|
||||
}
|
||||
|
||||
func arrayreflect2() {
|
||||
var arr [10]*int
|
||||
sl := arr[:]
|
||||
sl[0] = &a
|
||||
func reflectValueBytes() {
|
||||
sl1 := make([]byte, 0) // @line ar5sl1
|
||||
sl2 := make([]byte, 0) // @line ar5sl2
|
||||
|
||||
srv := reflect.ValueOf(sl).Slice(0, 0)
|
||||
print(srv.Interface()) // @types []*int
|
||||
print(srv.Interface().([]*int)) // pointsto TODO
|
||||
print(srv.Interface().([]*int)[42]) // @pointsto main.a
|
||||
rvsl1 := reflect.ValueOf(sl1)
|
||||
print(rvsl1.Interface()) // @types []byte
|
||||
print(rvsl1.Interface().([]byte)) // @pointsto makeslice@ar5sl1:13
|
||||
print(rvsl1.Bytes()) // @pointsto makeslice@ar5sl1:13
|
||||
|
||||
rvsl2 := reflect.ValueOf(123)
|
||||
rvsl2.SetBytes(sl2)
|
||||
print(rvsl2.Interface()) // @types int
|
||||
print(rvsl2.Interface().([]byte)) // @pointsto
|
||||
print(rvsl2.Bytes()) // @pointsto
|
||||
|
||||
rvsl3 := reflect.ValueOf([]byte(nil))
|
||||
rvsl3.SetBytes(sl2)
|
||||
print(rvsl3.Interface()) // @types []byte
|
||||
print(rvsl3.Interface().([]byte)) // @pointsto makeslice@ar5sl2:13
|
||||
print(rvsl3.Bytes()) // @pointsto makeslice@ar5sl2:13
|
||||
}
|
||||
|
||||
func arrayreflect3() {
|
||||
srv := reflect.ValueOf("hi").Slice(0, 0)
|
||||
print(srv.Interface()) // @types string
|
||||
func reflectValueIndex() {
|
||||
slice := []*int{&a} // @line ar6slice
|
||||
rv1 := reflect.ValueOf(slice)
|
||||
print(rv1.Index(42).Interface()) // @types *int
|
||||
print(rv1.Index(42).Interface().(*int)) // @pointsto main.a
|
||||
|
||||
type S string
|
||||
srv2 := reflect.ValueOf(S("hi")).Slice(0, 0)
|
||||
print(srv2.Interface()) // @types main.S
|
||||
array := [10]*int{&a}
|
||||
rv2 := reflect.ValueOf(array)
|
||||
print(rv2.Index(42).Interface()) // @types *int
|
||||
print(rv2.Index(42).Interface().(*int)) // @pointsto main.a
|
||||
|
||||
rv3 := reflect.ValueOf("string")
|
||||
print(rv3.Index(42).Interface()) // @types rune
|
||||
|
||||
rv4 := reflect.ValueOf(&array)
|
||||
print(rv4.Index(42).Interface()) // @types
|
||||
|
||||
rv5 := reflect.ValueOf(3)
|
||||
print(rv5.Index(42).Interface()) // @types
|
||||
}
|
||||
|
||||
func arrayreflect4() {
|
||||
rv1 := reflect.ValueOf("hi")
|
||||
rv2 := rv1 // backflow!
|
||||
if unknown {
|
||||
rv2 = reflect.ValueOf(123)
|
||||
}
|
||||
// We see backflow through the assignment above causing an
|
||||
// imprecise result for rv1. This is because the SSA builder
|
||||
// doesn't yet lift structs (like reflect.Value) into
|
||||
// registers so these are all loads/stores to the stack.
|
||||
// Under Das's algorithm, the extra indirection results in
|
||||
// (undirected) unification not (directed) flow edges.
|
||||
// TODO(adonovan): precision: lift aggregates.
|
||||
print(rv1.Interface()) // @types string | int
|
||||
print(rv2.Interface()) // @types string | int
|
||||
func reflectValueElem() {
|
||||
// TODO(adonovan): tests 'interface'. Needs indirect tagged objects.
|
||||
// rv1 := reflect.ValueOf(...)
|
||||
// print(rv1.Elem().Interface()) // #@types *int
|
||||
// print(rv1.Elem().Interface().(*int)) // #@pointsto main.a
|
||||
|
||||
// Pointer.
|
||||
ptr := &a
|
||||
rv2 := reflect.ValueOf(&ptr)
|
||||
print(rv2.Elem().Interface()) // @types *int
|
||||
print(rv2.Elem().Interface().(*int)) // @pointsto main.a
|
||||
|
||||
// No other type works with (rV).Elem, not even those that
|
||||
// work with (rT).Elem: slice, array, map, chan.
|
||||
|
||||
rv3 := reflect.ValueOf([]*int{&a})
|
||||
print(rv3.Elem().Interface()) // @types
|
||||
|
||||
rv4 := reflect.ValueOf([10]*int{&a})
|
||||
print(rv4.Elem().Interface()) // @types
|
||||
|
||||
rv5 := reflect.ValueOf(map[*int]*int{&a: &b})
|
||||
print(rv5.Elem().Interface()) // @types
|
||||
|
||||
ch := make(chan *int)
|
||||
ch <- &a
|
||||
rv6 := reflect.ValueOf(ch)
|
||||
print(rv6.Elem().Interface()) // @types
|
||||
|
||||
rv7 := reflect.ValueOf(3)
|
||||
print(rv7.Elem().Interface()) // @types
|
||||
}
|
||||
|
||||
func arrayreflect5() {
|
||||
sl1 := make([]byte, 0)
|
||||
sl2 := make([]byte, 0)
|
||||
func reflectTypeElem() {
|
||||
rt1 := reflect.TypeOf(make([]*int, 0))
|
||||
print(reflect.Zero(rt1.Elem())) // @types *int
|
||||
|
||||
srv := reflect.ValueOf(sl1)
|
||||
rt2 := reflect.TypeOf([10]*int{})
|
||||
print(reflect.Zero(rt2.Elem())) // @types *int
|
||||
|
||||
print(srv.Interface()) // @types []byte
|
||||
print(srv.Interface().([]byte)) // @pointsto makeslice@testdata/arrayreflect.go:62:13
|
||||
print(srv.Bytes()) // @pointsto makeslice@testdata/arrayreflect.go:62:13
|
||||
rt3 := reflect.TypeOf(map[*int]*int{})
|
||||
print(reflect.Zero(rt3.Elem())) // @types *int
|
||||
|
||||
srv2 := reflect.ValueOf(123)
|
||||
srv2.SetBytes(sl2)
|
||||
print(srv2.Interface()) // @types []byte | int
|
||||
print(srv2.Interface().([]byte)) // @pointsto makeslice@testdata/arrayreflect.go:63:13
|
||||
print(srv2.Bytes()) // @pointsto makeslice@testdata/arrayreflect.go:63:13
|
||||
rt4 := reflect.TypeOf(make(chan *int))
|
||||
print(reflect.Zero(rt4.Elem())) // @types *int
|
||||
|
||||
ptr := &a
|
||||
rt5 := reflect.TypeOf(&ptr)
|
||||
print(reflect.Zero(rt5.Elem())) // @types *int
|
||||
|
||||
rt6 := reflect.TypeOf(3)
|
||||
print(reflect.Zero(rt6.Elem())) // @types
|
||||
}
|
||||
|
||||
func arrayreflect6() {
|
||||
sl1 := []*bool{new(bool)}
|
||||
sl2 := []*int{&a}
|
||||
func reflectPtrTo() {
|
||||
tInt := reflect.TypeOf(3)
|
||||
tPtrInt := reflect.PtrTo(tInt)
|
||||
print(reflect.Zero(tPtrInt)) // @types *int
|
||||
tPtrPtrInt := reflect.PtrTo(tPtrInt)
|
||||
print(reflect.Zero(tPtrPtrInt)) // @types **int
|
||||
}
|
||||
|
||||
srv1 := reflect.ValueOf(sl1)
|
||||
print(srv1.Index(42).Interface()) // @types *bool
|
||||
print(srv1.Index(42).Interface().(*bool)) // @pointsto alloc@testdata/arrayreflect.go:79:20
|
||||
|
||||
srv2 := reflect.ValueOf(sl2)
|
||||
print(srv2.Index(42).Interface()) // @types *int
|
||||
print(srv2.Index(42).Interface().(*int)) // @pointsto main.a
|
||||
|
||||
p1 := &sl1[0]
|
||||
p2 := &sl2[0]
|
||||
|
||||
prv1 := reflect.ValueOf(p1)
|
||||
print(prv1.Elem().Interface()) // @types *bool
|
||||
print(prv1.Elem().Interface().(*bool)) // @pointsto alloc@testdata/arrayreflect.go:79:20
|
||||
|
||||
prv2 := reflect.ValueOf(p2)
|
||||
print(prv2.Elem().Interface()) // @types *int
|
||||
print(prv2.Elem().Interface().(*int)) // @pointsto main.a
|
||||
func reflectSliceOf() {
|
||||
tInt := reflect.TypeOf(3)
|
||||
tSliceInt := reflect.SliceOf(tInt)
|
||||
print(reflect.Zero(tSliceInt)) // @types []int
|
||||
}
|
||||
|
||||
func main() {
|
||||
arrayreflect1()
|
||||
arrayreflect2()
|
||||
arrayreflect3()
|
||||
arrayreflect4()
|
||||
arrayreflect5()
|
||||
arrayreflect6()
|
||||
reflectValueSlice()
|
||||
reflectValueBytes()
|
||||
reflectValueIndex()
|
||||
reflectValueElem()
|
||||
reflectTypeElem()
|
||||
reflectPtrTo()
|
||||
reflectSliceOf()
|
||||
}
|
||||
|
||||
var unknown bool
|
||||
|
|
Loading…
Reference in New Issue