1 Star 0 Fork 0

lonely/gometalinter

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
reflect.go 54.47 KB
一键复制 编辑 原始数据 按行查看 历史
Thomas Heller 提交于 2017-03-04 12:44 . add safesql (#251)
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package pointer
// This file implements the generation and resolution rules for
// constraints arising from the use of reflection in the target
// program. See doc.go for explanation of the representation.
//
// For consistency, the names of all parameters match those of the
// actual functions in the "reflect" package.
//
// To avoid proliferation of equivalent labels, intrinsics should
// memoize as much as possible, like TypeOf and Zero do for their
// tagged objects.
//
// TODO(adonovan): this file is rather subtle. Explain how we derive
// the implementation of each reflect operator from its spec,
// including the subtleties of reflect.flag{Addr,RO,Indir}.
// [Hint: our implementation is as if reflect.flagIndir was always
// true, i.e. reflect.Values are pointers to tagged objects, there is
// no inline allocation optimization; and indirect tagged objects (not
// yet implemented) correspond to reflect.Values with
// reflect.flagAddr.]
// A picture would help too.
//
// TODO(adonovan): try factoring up the common parts of the majority of
// these constraints that are single input, single output.
import (
"fmt"
exact "go/constant"
"go/types"
"reflect"
"golang.org/x/tools/go/ssa"
)
func init() {
for name, fn := range map[string]intrinsic{
// reflect.Value methods.
"(reflect.Value).Addr": ext۰reflect۰Value۰Addr,
"(reflect.Value).Bool": ext۰NoEffect,
"(reflect.Value).Bytes": ext۰reflect۰Value۰Bytes,
"(reflect.Value).Call": ext۰reflect۰Value۰Call,
"(reflect.Value).CallSlice": ext۰reflect۰Value۰CallSlice,
"(reflect.Value).CanAddr": ext۰NoEffect,
"(reflect.Value).CanInterface": ext۰NoEffect,
"(reflect.Value).CanSet": ext۰NoEffect,
"(reflect.Value).Cap": ext۰NoEffect,
"(reflect.Value).Close": ext۰NoEffect,
"(reflect.Value).Complex": ext۰NoEffect,
"(reflect.Value).Convert": ext۰reflect۰Value۰Convert,
"(reflect.Value).Elem": ext۰reflect۰Value۰Elem,
"(reflect.Value).Field": ext۰reflect۰Value۰Field,
"(reflect.Value).FieldByIndex": ext۰reflect۰Value۰FieldByIndex,
"(reflect.Value).FieldByName": ext۰reflect۰Value۰FieldByName,
"(reflect.Value).FieldByNameFunc": ext۰reflect۰Value۰FieldByNameFunc,
"(reflect.Value).Float": ext۰NoEffect,
"(reflect.Value).Index": ext۰reflect۰Value۰Index,
"(reflect.Value).Int": ext۰NoEffect,
"(reflect.Value).Interface": ext۰reflect۰Value۰Interface,
"(reflect.Value).InterfaceData": ext۰NoEffect,
"(reflect.Value).IsNil": ext۰NoEffect,
"(reflect.Value).IsValid": ext۰NoEffect,
"(reflect.Value).Kind": ext۰NoEffect,
"(reflect.Value).Len": ext۰NoEffect,
"(reflect.Value).MapIndex": ext۰reflect۰Value۰MapIndex,
"(reflect.Value).MapKeys": ext۰reflect۰Value۰MapKeys,
"(reflect.Value).Method": ext۰reflect۰Value۰Method,
"(reflect.Value).MethodByName": ext۰reflect۰Value۰MethodByName,
"(reflect.Value).NumField": ext۰NoEffect,
"(reflect.Value).NumMethod": ext۰NoEffect,
"(reflect.Value).OverflowComplex": ext۰NoEffect,
"(reflect.Value).OverflowFloat": ext۰NoEffect,
"(reflect.Value).OverflowInt": ext۰NoEffect,
"(reflect.Value).OverflowUint": ext۰NoEffect,
"(reflect.Value).Pointer": ext۰NoEffect,
"(reflect.Value).Recv": ext۰reflect۰Value۰Recv,
"(reflect.Value).Send": ext۰reflect۰Value۰Send,
"(reflect.Value).Set": ext۰reflect۰Value۰Set,
"(reflect.Value).SetBool": ext۰NoEffect,
"(reflect.Value).SetBytes": ext۰reflect۰Value۰SetBytes,
"(reflect.Value).SetComplex": ext۰NoEffect,
"(reflect.Value).SetFloat": ext۰NoEffect,
"(reflect.Value).SetInt": ext۰NoEffect,
"(reflect.Value).SetLen": ext۰NoEffect,
"(reflect.Value).SetMapIndex": ext۰reflect۰Value۰SetMapIndex,
"(reflect.Value).SetPointer": ext۰reflect۰Value۰SetPointer,
"(reflect.Value).SetString": ext۰NoEffect,
"(reflect.Value).SetUint": ext۰NoEffect,
"(reflect.Value).Slice": ext۰reflect۰Value۰Slice,
"(reflect.Value).String": ext۰NoEffect,
"(reflect.Value).TryRecv": ext۰reflect۰Value۰Recv,
"(reflect.Value).TrySend": ext۰reflect۰Value۰Send,
"(reflect.Value).Type": ext۰NoEffect,
"(reflect.Value).Uint": ext۰NoEffect,
"(reflect.Value).UnsafeAddr": ext۰NoEffect,
// Standalone reflect.* functions.
"reflect.Append": ext۰reflect۰Append,
"reflect.AppendSlice": ext۰reflect۰AppendSlice,
"reflect.Copy": ext۰reflect۰Copy,
"reflect.ChanOf": ext۰reflect۰ChanOf,
"reflect.DeepEqual": ext۰NoEffect,
"reflect.Indirect": ext۰reflect۰Indirect,
"reflect.MakeChan": ext۰reflect۰MakeChan,
"reflect.MakeFunc": ext۰reflect۰MakeFunc,
"reflect.MakeMap": ext۰reflect۰MakeMap,
"reflect.MakeSlice": ext۰reflect۰MakeSlice,
"reflect.MapOf": ext۰reflect۰MapOf,
"reflect.New": ext۰reflect۰New,
"reflect.NewAt": ext۰reflect۰NewAt,
"reflect.PtrTo": ext۰reflect۰PtrTo,
"reflect.Select": ext۰reflect۰Select,
"reflect.SliceOf": ext۰reflect۰SliceOf,
"reflect.TypeOf": ext۰reflect۰TypeOf,
"reflect.ValueOf": ext۰reflect۰ValueOf,
"reflect.Zero": ext۰reflect۰Zero,
"reflect.init": ext۰NoEffect,
// *reflect.rtype methods
"(*reflect.rtype).Align": ext۰NoEffect,
"(*reflect.rtype).AssignableTo": ext۰NoEffect,
"(*reflect.rtype).Bits": ext۰NoEffect,
"(*reflect.rtype).ChanDir": ext۰NoEffect,
"(*reflect.rtype).ConvertibleTo": ext۰NoEffect,
"(*reflect.rtype).Elem": ext۰reflect۰rtype۰Elem,
"(*reflect.rtype).Field": ext۰reflect۰rtype۰Field,
"(*reflect.rtype).FieldAlign": ext۰NoEffect,
"(*reflect.rtype).FieldByIndex": ext۰reflect۰rtype۰FieldByIndex,
"(*reflect.rtype).FieldByName": ext۰reflect۰rtype۰FieldByName,
"(*reflect.rtype).FieldByNameFunc": ext۰reflect۰rtype۰FieldByNameFunc,
"(*reflect.rtype).Implements": ext۰NoEffect,
"(*reflect.rtype).In": ext۰reflect۰rtype۰In,
"(*reflect.rtype).IsVariadic": ext۰NoEffect,
"(*reflect.rtype).Key": ext۰reflect۰rtype۰Key,
"(*reflect.rtype).Kind": ext۰NoEffect,
"(*reflect.rtype).Len": ext۰NoEffect,
"(*reflect.rtype).Method": ext۰reflect۰rtype۰Method,
"(*reflect.rtype).MethodByName": ext۰reflect۰rtype۰MethodByName,
"(*reflect.rtype).Name": ext۰NoEffect,
"(*reflect.rtype).NumField": ext۰NoEffect,
"(*reflect.rtype).NumIn": ext۰NoEffect,
"(*reflect.rtype).NumMethod": ext۰NoEffect,
"(*reflect.rtype).NumOut": ext۰NoEffect,
"(*reflect.rtype).Out": ext۰reflect۰rtype۰Out,
"(*reflect.rtype).PkgPath": ext۰NoEffect,
"(*reflect.rtype).Size": ext۰NoEffect,
"(*reflect.rtype).String": ext۰NoEffect,
} {
intrinsicsByName[name] = fn
}
}
// -------------------- (reflect.Value) --------------------
func ext۰reflect۰Value۰Addr(a *analysis, cgn *cgnode) {} // TODO(adonovan)
// ---------- func (Value).Bytes() Value ----------
// result = v.Bytes()
type rVBytesConstraint struct {
v nodeid // (ptr)
result nodeid // (indirect)
}
func (c *rVBytesConstraint) ptr() nodeid { return c.v }
func (c *rVBytesConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result), "rVBytes.result")
}
func (c *rVBytesConstraint) renumber(mapping []nodeid) {
c.v = mapping[c.v]
c.result = mapping[c.result]
}
func (c *rVBytesConstraint) String() string {
return fmt.Sprintf("n%d = reflect n%d.Bytes()", c.result, c.v)
}
func (c *rVBytesConstraint) solve(a *analysis, delta *nodeset) {
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
vObj := nodeid(x)
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.Identical(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 (Value).Call(in []Value) []Value ----------
// result = v.Call(in)
type rVCallConstraint struct {
cgn *cgnode
targets nodeid // (indirect)
v nodeid // (ptr)
arg nodeid // = in[*]
result nodeid // (indirect)
dotdotdot bool // interpret last arg as a "..." slice
}
func (c *rVCallConstraint) ptr() nodeid { return c.v }
func (c *rVCallConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.targets), "rVCall.targets")
h.markIndirect(onodeid(c.result), "rVCall.result")
}
func (c *rVCallConstraint) renumber(mapping []nodeid) {
c.targets = mapping[c.targets]
c.v = mapping[c.v]
c.arg = mapping[c.arg]
c.result = mapping[c.result]
}
func (c *rVCallConstraint) String() string {
return fmt.Sprintf("n%d = reflect n%d.Call(n%d)", c.result, c.v, c.arg)
}
func (c *rVCallConstraint) solve(a *analysis, delta *nodeset) {
if c.targets == 0 {
panic("no targets")
}
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
vObj := nodeid(x)
tDyn, fn, 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")
}
tSig, ok := tDyn.Underlying().(*types.Signature)
if !ok {
continue // not a function
}
if tSig.Recv() != nil {
panic(tSig) // TODO(adonovan): rethink when we implement Method()
}
// Add dynamic call target.
if a.onlineCopy(c.targets, fn) {
a.addWork(c.targets)
// TODO(adonovan): is 'else continue' a sound optimisation here?
}
// Allocate a P/R block.
tParams := tSig.Params()
tResults := tSig.Results()
params := a.addNodes(tParams, "rVCall.params")
results := a.addNodes(tResults, "rVCall.results")
// Make a dynamic call to 'fn'.
a.store(fn, params, 1, a.sizeof(tParams))
a.load(results, fn, 1+a.sizeof(tParams), a.sizeof(tResults))
// Populate P by type-asserting each actual arg (all merged in c.arg).
for i, n := 0, tParams.Len(); i < n; i++ {
T := tParams.At(i).Type()
a.typeAssert(T, params, c.arg, false)
params += nodeid(a.sizeof(T))
}
// Use R by tagging and copying each actual result to c.result.
for i, n := 0, tResults.Len(); i < n; i++ {
T := tResults.At(i).Type()
// Convert from an arbitrary type to a reflect.Value
// (like MakeInterface followed by reflect.ValueOf).
if isInterface(T) {
// (don't tag)
if a.onlineCopy(c.result, results) {
changed = true
}
} else {
obj := a.makeTagged(T, c.cgn, nil)
a.onlineCopyN(obj+1, results, a.sizeof(T))
if a.addLabel(c.result, obj) { // (true)
changed = true
}
}
results += nodeid(a.sizeof(T))
}
}
if changed {
a.addWork(c.result)
}
}
// Common code for direct (inlined) and indirect calls to (reflect.Value).Call.
func reflectCallImpl(a *analysis, cgn *cgnode, site *callsite, recv, arg nodeid, dotdotdot bool) nodeid {
// Allocate []reflect.Value array for the result.
ret := a.nextNode()
a.addNodes(types.NewArray(a.reflectValueObj.Type(), 1), "rVCall.ret")
a.endObject(ret, cgn, nil)
// pts(targets) will be the set of possible call targets.
site.targets = a.addOneNode(tInvalid, "rvCall.targets", nil)
// All arguments are merged since they arrive in a slice.
argelts := a.addOneNode(a.reflectValueObj.Type(), "rVCall.args", nil)
a.load(argelts, arg, 1, 1) // slice elements
a.addConstraint(&rVCallConstraint{
cgn: cgn,
targets: site.targets,
v: recv,
arg: argelts,
result: ret + 1, // results go into elements of ret
dotdotdot: dotdotdot,
})
return ret
}
func reflectCall(a *analysis, cgn *cgnode, dotdotdot bool) {
// This is the shared contour implementation of (reflect.Value).Call
// and CallSlice, as used by indirect calls (rare).
// Direct calls are inlined in gen.go, eliding the
// intermediate cgnode for Call.
site := new(callsite)
cgn.sites = append(cgn.sites, site)
recv := a.funcParams(cgn.obj)
arg := recv + 1
ret := reflectCallImpl(a, cgn, site, recv, arg, dotdotdot)
a.addressOf(cgn.fn.Signature.Results().At(0).Type(), a.funcResults(cgn.obj), ret)
}
func ext۰reflect۰Value۰Call(a *analysis, cgn *cgnode) {
reflectCall(a, cgn, false)
}
func ext۰reflect۰Value۰CallSlice(a *analysis, cgn *cgnode) {
// TODO(adonovan): implement. Also, inline direct calls in gen.go too.
if false {
reflectCall(a, cgn, true)
}
}
func ext۰reflect۰Value۰Convert(a *analysis, cgn *cgnode) {} // TODO(adonovan)
// ---------- func (Value).Elem() Value ----------
// result = v.Elem()
type rVElemConstraint struct {
cgn *cgnode
v nodeid // (ptr)
result nodeid // (indirect)
}
func (c *rVElemConstraint) ptr() nodeid { return c.v }
func (c *rVElemConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result), "rVElem.result")
}
func (c *rVElemConstraint) renumber(mapping []nodeid) {
c.v = mapping[c.v]
c.result = mapping[c.result]
}
func (c *rVElemConstraint) String() string {
return fmt.Sprintf("n%d = reflect n%d.Elem()", c.result, c.v)
}
func (c *rVElemConstraint) solve(a *analysis, delta *nodeset) {
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
vObj := nodeid(x)
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:
if a.onlineCopy(c.result, payload) {
changed = true
}
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) {} // TODO(adonovan)
func ext۰reflect۰Value۰FieldByIndex(a *analysis, cgn *cgnode) {} // TODO(adonovan)
func ext۰reflect۰Value۰FieldByName(a *analysis, cgn *cgnode) {} // TODO(adonovan)
func ext۰reflect۰Value۰FieldByNameFunc(a *analysis, cgn *cgnode) {} // TODO(adonovan)
// ---------- func (Value).Index() Value ----------
// result = v.Index()
type rVIndexConstraint struct {
cgn *cgnode
v nodeid // (ptr)
result nodeid // (indirect)
}
func (c *rVIndexConstraint) ptr() nodeid { return c.v }
func (c *rVIndexConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result), "rVIndex.result")
}
func (c *rVIndexConstraint) renumber(mapping []nodeid) {
c.v = mapping[c.v]
c.result = mapping[c.result]
}
func (c *rVIndexConstraint) String() string {
return fmt.Sprintf("n%d = reflect n%d.Index()", c.result, c.v)
}
func (c *rVIndexConstraint) solve(a *analysis, delta *nodeset) {
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
vObj := nodeid(x)
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 ----------
// result = v.Interface()
type rVInterfaceConstraint struct {
v nodeid // (ptr)
result nodeid // (indirect)
}
func (c *rVInterfaceConstraint) ptr() nodeid { return c.v }
func (c *rVInterfaceConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result), "rVInterface.result")
}
func (c *rVInterfaceConstraint) renumber(mapping []nodeid) {
c.v = mapping[c.v]
c.result = mapping[c.result]
}
func (c *rVInterfaceConstraint) String() string {
return fmt.Sprintf("n%d = reflect n%d.Interface()", c.result, c.v)
}
func (c *rVInterfaceConstraint) solve(a *analysis, delta *nodeset) {
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
vObj := nodeid(x)
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")
}
if isInterface(tDyn) {
if a.onlineCopy(c.result, payload) {
a.addWork(c.result)
}
} else {
if a.addLabel(c.result, vObj) {
changed = true
}
}
}
if changed {
a.addWork(c.result)
}
}
func ext۰reflect۰Value۰Interface(a *analysis, cgn *cgnode) {
a.addConstraint(&rVInterfaceConstraint{
v: a.funcParams(cgn.obj),
result: a.funcResults(cgn.obj),
})
}
// ---------- func (Value).MapIndex(Value) Value ----------
// result = v.MapIndex(_)
type rVMapIndexConstraint struct {
cgn *cgnode
v nodeid // (ptr)
result nodeid // (indirect)
}
func (c *rVMapIndexConstraint) ptr() nodeid { return c.v }
func (c *rVMapIndexConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result), "rVMapIndex.result")
}
func (c *rVMapIndexConstraint) renumber(mapping []nodeid) {
c.v = mapping[c.v]
c.result = mapping[c.result]
}
func (c *rVMapIndexConstraint) String() string {
return fmt.Sprintf("n%d = reflect n%d.MapIndex(_)", c.result, c.v)
}
func (c *rVMapIndexConstraint) solve(a *analysis, delta *nodeset) {
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
vObj := nodeid(x)
tDyn, m, indirect := a.taggedValue(vObj)
tMap, _ := tDyn.Underlying().(*types.Map)
if tMap == nil {
continue // not a map
}
if indirect {
// TODO(adonovan): we'll need to implement this
// when we start creating indirect tagged objects.
panic("indirect tagged object")
}
obj := a.makeTagged(tMap.Elem(), c.cgn, nil)
a.load(obj+1, m, a.sizeof(tMap.Key()), a.sizeof(tMap.Elem()))
if a.addLabel(c.result, obj) {
changed = true
}
}
if changed {
a.addWork(c.result)
}
}
func ext۰reflect۰Value۰MapIndex(a *analysis, cgn *cgnode) {
a.addConstraint(&rVMapIndexConstraint{
cgn: cgn,
v: a.funcParams(cgn.obj),
result: a.funcResults(cgn.obj),
})
}
// ---------- func (Value).MapKeys() []Value ----------
// result = v.MapKeys()
type rVMapKeysConstraint struct {
cgn *cgnode
v nodeid // (ptr)
result nodeid // (indirect)
}
func (c *rVMapKeysConstraint) ptr() nodeid { return c.v }
func (c *rVMapKeysConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result), "rVMapKeys.result")
}
func (c *rVMapKeysConstraint) renumber(mapping []nodeid) {
c.v = mapping[c.v]
c.result = mapping[c.result]
}
func (c *rVMapKeysConstraint) String() string {
return fmt.Sprintf("n%d = reflect n%d.MapKeys()", c.result, c.v)
}
func (c *rVMapKeysConstraint) solve(a *analysis, delta *nodeset) {
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
vObj := nodeid(x)
tDyn, m, indirect := a.taggedValue(vObj)
tMap, _ := tDyn.Underlying().(*types.Map)
if tMap == nil {
continue // not a map
}
if indirect {
// TODO(adonovan): we'll need to implement this
// when we start creating indirect tagged objects.
panic("indirect tagged object")
}
kObj := a.makeTagged(tMap.Key(), c.cgn, nil)
a.load(kObj+1, m, 0, a.sizeof(tMap.Key()))
if a.addLabel(c.result, kObj) {
changed = true
}
}
if changed {
a.addWork(c.result)
}
}
func ext۰reflect۰Value۰MapKeys(a *analysis, cgn *cgnode) {
// Allocate an array for the result.
obj := a.nextNode()
T := types.NewSlice(a.reflectValueObj.Type())
a.addNodes(sliceToArray(T), "reflect.MapKeys result")
a.endObject(obj, cgn, nil)
a.addressOf(T, a.funcResults(cgn.obj), obj)
a.addConstraint(&rVMapKeysConstraint{
cgn: cgn,
v: a.funcParams(cgn.obj),
result: obj + 1, // result is stored in array elems
})
}
func ext۰reflect۰Value۰Method(a *analysis, cgn *cgnode) {} // TODO(adonovan)
func ext۰reflect۰Value۰MethodByName(a *analysis, cgn *cgnode) {} // TODO(adonovan)
// ---------- func (Value).Recv(Value) Value ----------
// result, _ = v.Recv()
type rVRecvConstraint struct {
cgn *cgnode
v nodeid // (ptr)
result nodeid // (indirect)
}
func (c *rVRecvConstraint) ptr() nodeid { return c.v }
func (c *rVRecvConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result), "rVRecv.result")
}
func (c *rVRecvConstraint) renumber(mapping []nodeid) {
c.v = mapping[c.v]
c.result = mapping[c.result]
}
func (c *rVRecvConstraint) String() string {
return fmt.Sprintf("n%d = reflect n%d.Recv()", c.result, c.v)
}
func (c *rVRecvConstraint) solve(a *analysis, delta *nodeset) {
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
vObj := nodeid(x)
tDyn, ch, indirect := a.taggedValue(vObj)
tChan, _ := tDyn.Underlying().(*types.Chan)
if tChan == nil {
continue // not a channel
}
if indirect {
// TODO(adonovan): we'll need to implement this
// when we start creating indirect tagged objects.
panic("indirect tagged object")
}
tElem := tChan.Elem()
elemObj := a.makeTagged(tElem, c.cgn, nil)
a.load(elemObj+1, ch, 0, a.sizeof(tElem))
if a.addLabel(c.result, elemObj) {
changed = true
}
}
if changed {
a.addWork(c.result)
}
}
func ext۰reflect۰Value۰Recv(a *analysis, cgn *cgnode) {
a.addConstraint(&rVRecvConstraint{
cgn: cgn,
v: a.funcParams(cgn.obj),
result: a.funcResults(cgn.obj),
})
}
// ---------- func (Value).Send(Value) ----------
// v.Send(x)
type rVSendConstraint struct {
cgn *cgnode
v nodeid // (ptr)
x nodeid
}
func (c *rVSendConstraint) ptr() nodeid { return c.v }
func (c *rVSendConstraint) presolve(*hvn) {}
func (c *rVSendConstraint) renumber(mapping []nodeid) {
c.v = mapping[c.v]
c.x = mapping[c.x]
}
func (c *rVSendConstraint) String() string {
return fmt.Sprintf("reflect n%d.Send(n%d)", c.v, c.x)
}
func (c *rVSendConstraint) solve(a *analysis, delta *nodeset) {
for _, x := range delta.AppendTo(a.deltaSpace) {
vObj := nodeid(x)
tDyn, ch, indirect := a.taggedValue(vObj)
tChan, _ := tDyn.Underlying().(*types.Chan)
if tChan == nil {
continue // not a channel
}
if indirect {
// TODO(adonovan): we'll need to implement this
// when we start creating indirect tagged objects.
panic("indirect tagged object")
}
// Extract x's payload to xtmp, then store to channel.
tElem := tChan.Elem()
xtmp := a.addNodes(tElem, "Send.xtmp")
a.typeAssert(tElem, xtmp, c.x, false)
a.store(ch, xtmp, 0, a.sizeof(tElem))
}
}
func ext۰reflect۰Value۰Send(a *analysis, cgn *cgnode) {
params := a.funcParams(cgn.obj)
a.addConstraint(&rVSendConstraint{
cgn: cgn,
v: params,
x: params + 1,
})
}
func ext۰reflect۰Value۰Set(a *analysis, cgn *cgnode) {} // TODO(adonovan)
// ---------- func (Value).SetBytes(x []byte) ----------
// v.SetBytes(x)
type rVSetBytesConstraint struct {
cgn *cgnode
v nodeid // (ptr)
x nodeid
}
func (c *rVSetBytesConstraint) ptr() nodeid { return c.v }
func (c *rVSetBytesConstraint) presolve(*hvn) {}
func (c *rVSetBytesConstraint) renumber(mapping []nodeid) {
c.v = mapping[c.v]
c.x = mapping[c.x]
}
func (c *rVSetBytesConstraint) String() string {
return fmt.Sprintf("reflect n%d.SetBytes(n%d)", c.v, c.x)
}
func (c *rVSetBytesConstraint) solve(a *analysis, delta *nodeset) {
for _, x := range delta.AppendTo(a.deltaSpace) {
vObj := nodeid(x)
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.Identical(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) ----------
// v.SetMapIndex(key, val)
type rVSetMapIndexConstraint struct {
cgn *cgnode
v nodeid // (ptr)
key nodeid
val nodeid
}
func (c *rVSetMapIndexConstraint) ptr() nodeid { return c.v }
func (c *rVSetMapIndexConstraint) presolve(*hvn) {}
func (c *rVSetMapIndexConstraint) renumber(mapping []nodeid) {
c.v = mapping[c.v]
c.key = mapping[c.key]
c.val = mapping[c.val]
}
func (c *rVSetMapIndexConstraint) String() string {
return fmt.Sprintf("reflect n%d.SetMapIndex(n%d, n%d)", c.v, c.key, c.val)
}
func (c *rVSetMapIndexConstraint) solve(a *analysis, delta *nodeset) {
for _, x := range delta.AppendTo(a.deltaSpace) {
vObj := nodeid(x)
tDyn, m, indirect := a.taggedValue(vObj)
tMap, _ := tDyn.Underlying().(*types.Map)
if tMap == nil {
continue // not a map
}
if indirect {
// TODO(adonovan): we'll need to implement this
// when we start creating indirect tagged objects.
panic("indirect tagged object")
}
keysize := a.sizeof(tMap.Key())
// Extract key's payload to keytmp, then store to map key.
keytmp := a.addNodes(tMap.Key(), "SetMapIndex.keytmp")
a.typeAssert(tMap.Key(), keytmp, c.key, false)
a.store(m, keytmp, 0, keysize)
// Extract val's payload to vtmp, then store to map value.
valtmp := a.addNodes(tMap.Elem(), "SetMapIndex.valtmp")
a.typeAssert(tMap.Elem(), valtmp, c.val, false)
a.store(m, valtmp, keysize, a.sizeof(tMap.Elem()))
}
}
func ext۰reflect۰Value۰SetMapIndex(a *analysis, cgn *cgnode) {
params := a.funcParams(cgn.obj)
a.addConstraint(&rVSetMapIndexConstraint{
cgn: cgn,
v: params,
key: params + 1,
val: params + 2,
})
}
func ext۰reflect۰Value۰SetPointer(a *analysis, cgn *cgnode) {} // TODO(adonovan)
// ---------- func (Value).Slice(v Value, i, j int) Value ----------
// result = v.Slice(_, _)
type rVSliceConstraint struct {
cgn *cgnode
v nodeid // (ptr)
result nodeid // (indirect)
}
func (c *rVSliceConstraint) ptr() nodeid { return c.v }
func (c *rVSliceConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result), "rVSlice.result")
}
func (c *rVSliceConstraint) renumber(mapping []nodeid) {
c.v = mapping[c.v]
c.result = mapping[c.result]
}
func (c *rVSliceConstraint) String() string {
return fmt.Sprintf("n%d = reflect n%d.Slice(_, _)", c.result, c.v)
}
func (c *rVSliceConstraint) solve(a *analysis, delta *nodeset) {
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
vObj := nodeid(x)
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 --------------------
func ext۰reflect۰Append(a *analysis, cgn *cgnode) {} // TODO(adonovan)
func ext۰reflect۰AppendSlice(a *analysis, cgn *cgnode) {} // TODO(adonovan)
func ext۰reflect۰Copy(a *analysis, cgn *cgnode) {} // TODO(adonovan)
// ---------- func ChanOf(ChanDir, Type) Type ----------
// result = ChanOf(dir, t)
type reflectChanOfConstraint struct {
cgn *cgnode
t nodeid // (ptr)
result nodeid // (indirect)
dirs []types.ChanDir
}
func (c *reflectChanOfConstraint) ptr() nodeid { return c.t }
func (c *reflectChanOfConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result), "reflectChanOf.result")
}
func (c *reflectChanOfConstraint) renumber(mapping []nodeid) {
c.t = mapping[c.t]
c.result = mapping[c.result]
}
func (c *reflectChanOfConstraint) String() string {
return fmt.Sprintf("n%d = reflect.ChanOf(n%d)", c.result, c.t)
}
func (c *reflectChanOfConstraint) solve(a *analysis, delta *nodeset) {
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
tObj := nodeid(x)
T := a.rtypeTaggedValue(tObj)
if typeTooHigh(T) {
continue
}
for _, dir := range c.dirs {
if a.addLabel(c.result, a.makeRtype(types.NewChan(dir, T))) {
changed = true
}
}
}
if changed {
a.addWork(c.result)
}
}
// dirMap maps reflect.ChanDir to the set of channel types generated by ChanOf.
var dirMap = [...][]types.ChanDir{
0: {types.SendOnly, types.RecvOnly, types.SendRecv}, // unknown
reflect.RecvDir: {types.RecvOnly},
reflect.SendDir: {types.SendOnly},
reflect.BothDir: {types.SendRecv},
}
func ext۰reflect۰ChanOf(a *analysis, cgn *cgnode) {
// If we have access to the callsite,
// and the channel argument is a constant (as is usual),
// only generate the requested direction.
var dir reflect.ChanDir // unknown
if site := cgn.callersite; site != nil {
if c, ok := site.instr.Common().Args[0].(*ssa.Const); ok {
v, _ := exact.Int64Val(c.Value)
if 0 <= v && v <= int64(reflect.BothDir) {
dir = reflect.ChanDir(v)
}
}
}
params := a.funcParams(cgn.obj)
a.addConstraint(&reflectChanOfConstraint{
cgn: cgn,
t: params + 1,
result: a.funcResults(cgn.obj),
dirs: dirMap[dir],
})
}
// ---------- func Indirect(v Value) Value ----------
// result = Indirect(v)
type reflectIndirectConstraint struct {
cgn *cgnode
v nodeid // (ptr)
result nodeid // (indirect)
}
func (c *reflectIndirectConstraint) ptr() nodeid { return c.v }
func (c *reflectIndirectConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result), "reflectIndirect.result")
}
func (c *reflectIndirectConstraint) renumber(mapping []nodeid) {
c.v = mapping[c.v]
c.result = mapping[c.result]
}
func (c *reflectIndirectConstraint) String() string {
return fmt.Sprintf("n%d = reflect.Indirect(n%d)", c.result, c.v)
}
func (c *reflectIndirectConstraint) solve(a *analysis, delta *nodeset) {
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
vObj := nodeid(x)
tDyn, _, _ := a.taggedValue(vObj)
var res nodeid
if tPtr, ok := tDyn.Underlying().(*types.Pointer); ok {
// load the payload of the pointer's tagged object
// into a new tagged object
res = a.makeTagged(tPtr.Elem(), c.cgn, nil)
a.load(res+1, vObj+1, 0, a.sizeof(tPtr.Elem()))
} else {
res = vObj
}
if a.addLabel(c.result, res) {
changed = true
}
}
if changed {
a.addWork(c.result)
}
}
func ext۰reflect۰Indirect(a *analysis, cgn *cgnode) {
a.addConstraint(&reflectIndirectConstraint{
cgn: cgn,
v: a.funcParams(cgn.obj),
result: a.funcResults(cgn.obj),
})
}
// ---------- func MakeChan(Type) Value ----------
// result = MakeChan(typ)
type reflectMakeChanConstraint struct {
cgn *cgnode
typ nodeid // (ptr)
result nodeid // (indirect)
}
func (c *reflectMakeChanConstraint) ptr() nodeid { return c.typ }
func (c *reflectMakeChanConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result), "reflectMakeChan.result")
}
func (c *reflectMakeChanConstraint) renumber(mapping []nodeid) {
c.typ = mapping[c.typ]
c.result = mapping[c.result]
}
func (c *reflectMakeChanConstraint) String() string {
return fmt.Sprintf("n%d = reflect.MakeChan(n%d)", c.result, c.typ)
}
func (c *reflectMakeChanConstraint) solve(a *analysis, delta *nodeset) {
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
typObj := nodeid(x)
T := a.rtypeTaggedValue(typObj)
tChan, ok := T.Underlying().(*types.Chan)
if !ok || tChan.Dir() != types.SendRecv {
continue // not a bidirectional channel type
}
obj := a.nextNode()
a.addNodes(tChan.Elem(), "reflect.MakeChan.value")
a.endObject(obj, c.cgn, nil)
// put its address in a new T-tagged object
id := a.makeTagged(T, c.cgn, nil)
a.addLabel(id+1, obj)
// flow the T-tagged object to the result
if a.addLabel(c.result, id) {
changed = true
}
}
if changed {
a.addWork(c.result)
}
}
func ext۰reflect۰MakeChan(a *analysis, cgn *cgnode) {
a.addConstraint(&reflectMakeChanConstraint{
cgn: cgn,
typ: a.funcParams(cgn.obj),
result: a.funcResults(cgn.obj),
})
}
func ext۰reflect۰MakeFunc(a *analysis, cgn *cgnode) {} // TODO(adonovan)
// ---------- func MakeMap(Type) Value ----------
// result = MakeMap(typ)
type reflectMakeMapConstraint struct {
cgn *cgnode
typ nodeid // (ptr)
result nodeid // (indirect)
}
func (c *reflectMakeMapConstraint) ptr() nodeid { return c.typ }
func (c *reflectMakeMapConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result), "reflectMakeMap.result")
}
func (c *reflectMakeMapConstraint) renumber(mapping []nodeid) {
c.typ = mapping[c.typ]
c.result = mapping[c.result]
}
func (c *reflectMakeMapConstraint) String() string {
return fmt.Sprintf("n%d = reflect.MakeMap(n%d)", c.result, c.typ)
}
func (c *reflectMakeMapConstraint) solve(a *analysis, delta *nodeset) {
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
typObj := nodeid(x)
T := a.rtypeTaggedValue(typObj)
tMap, ok := T.Underlying().(*types.Map)
if !ok {
continue // not a map type
}
mapObj := a.nextNode()
a.addNodes(tMap.Key(), "reflect.MakeMap.key")
a.addNodes(tMap.Elem(), "reflect.MakeMap.value")
a.endObject(mapObj, c.cgn, nil)
// put its address in a new T-tagged object
id := a.makeTagged(T, c.cgn, nil)
a.addLabel(id+1, mapObj)
// flow the T-tagged object to the result
if a.addLabel(c.result, id) {
changed = true
}
}
if changed {
a.addWork(c.result)
}
}
func ext۰reflect۰MakeMap(a *analysis, cgn *cgnode) {
a.addConstraint(&reflectMakeMapConstraint{
cgn: cgn,
typ: a.funcParams(cgn.obj),
result: a.funcResults(cgn.obj),
})
}
// ---------- func MakeSlice(Type) Value ----------
// result = MakeSlice(typ)
type reflectMakeSliceConstraint struct {
cgn *cgnode
typ nodeid // (ptr)
result nodeid // (indirect)
}
func (c *reflectMakeSliceConstraint) ptr() nodeid { return c.typ }
func (c *reflectMakeSliceConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result), "reflectMakeSlice.result")
}
func (c *reflectMakeSliceConstraint) renumber(mapping []nodeid) {
c.typ = mapping[c.typ]
c.result = mapping[c.result]
}
func (c *reflectMakeSliceConstraint) String() string {
return fmt.Sprintf("n%d = reflect.MakeSlice(n%d)", c.result, c.typ)
}
func (c *reflectMakeSliceConstraint) solve(a *analysis, delta *nodeset) {
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
typObj := nodeid(x)
T := a.rtypeTaggedValue(typObj)
if _, ok := T.Underlying().(*types.Slice); !ok {
continue // not a slice type
}
obj := a.nextNode()
a.addNodes(sliceToArray(T), "reflect.MakeSlice")
a.endObject(obj, c.cgn, nil)
// put its address in a new T-tagged object
id := a.makeTagged(T, c.cgn, nil)
a.addLabel(id+1, obj)
// flow the T-tagged object to the result
if a.addLabel(c.result, id) {
changed = true
}
}
if changed {
a.addWork(c.result)
}
}
func ext۰reflect۰MakeSlice(a *analysis, cgn *cgnode) {
a.addConstraint(&reflectMakeSliceConstraint{
cgn: cgn,
typ: a.funcParams(cgn.obj),
result: a.funcResults(cgn.obj),
})
}
func ext۰reflect۰MapOf(a *analysis, cgn *cgnode) {} // TODO(adonovan)
// ---------- func New(Type) Value ----------
// result = New(typ)
type reflectNewConstraint struct {
cgn *cgnode
typ nodeid // (ptr)
result nodeid // (indirect)
}
func (c *reflectNewConstraint) ptr() nodeid { return c.typ }
func (c *reflectNewConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result), "reflectNew.result")
}
func (c *reflectNewConstraint) renumber(mapping []nodeid) {
c.typ = mapping[c.typ]
c.result = mapping[c.result]
}
func (c *reflectNewConstraint) String() string {
return fmt.Sprintf("n%d = reflect.New(n%d)", c.result, c.typ)
}
func (c *reflectNewConstraint) solve(a *analysis, delta *nodeset) {
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
typObj := nodeid(x)
T := a.rtypeTaggedValue(typObj)
// allocate new T object
newObj := a.nextNode()
a.addNodes(T, "reflect.New")
a.endObject(newObj, c.cgn, nil)
// put its address in a new *T-tagged object
id := a.makeTagged(types.NewPointer(T), c.cgn, nil)
a.addLabel(id+1, newObj)
// flow the pointer to the result
if a.addLabel(c.result, id) {
changed = true
}
}
if changed {
a.addWork(c.result)
}
}
func ext۰reflect۰New(a *analysis, cgn *cgnode) {
a.addConstraint(&reflectNewConstraint{
cgn: cgn,
typ: a.funcParams(cgn.obj),
result: a.funcResults(cgn.obj),
})
}
func ext۰reflect۰NewAt(a *analysis, cgn *cgnode) {
ext۰reflect۰New(a, cgn)
// TODO(adonovan): also report dynamic calls to unsound intrinsics.
if site := cgn.callersite; site != nil {
a.warnf(site.pos(), "unsound: %s contains a reflect.NewAt() call", site.instr.Parent())
}
}
// ---------- func PtrTo(Type) Type ----------
// result = PtrTo(t)
type reflectPtrToConstraint struct {
cgn *cgnode
t nodeid // (ptr)
result nodeid // (indirect)
}
func (c *reflectPtrToConstraint) ptr() nodeid { return c.t }
func (c *reflectPtrToConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result), "reflectPtrTo.result")
}
func (c *reflectPtrToConstraint) renumber(mapping []nodeid) {
c.t = mapping[c.t]
c.result = mapping[c.result]
}
func (c *reflectPtrToConstraint) String() string {
return fmt.Sprintf("n%d = reflect.PtrTo(n%d)", c.result, c.t)
}
func (c *reflectPtrToConstraint) solve(a *analysis, delta *nodeset) {
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
tObj := nodeid(x)
T := a.rtypeTaggedValue(tObj)
if typeTooHigh(T) {
continue
}
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) {} // TODO(adonovan)
// ---------- func SliceOf(Type) Type ----------
// result = SliceOf(t)
type reflectSliceOfConstraint struct {
cgn *cgnode
t nodeid // (ptr)
result nodeid // (indirect)
}
func (c *reflectSliceOfConstraint) ptr() nodeid { return c.t }
func (c *reflectSliceOfConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result), "reflectSliceOf.result")
}
func (c *reflectSliceOfConstraint) renumber(mapping []nodeid) {
c.t = mapping[c.t]
c.result = mapping[c.result]
}
func (c *reflectSliceOfConstraint) String() string {
return fmt.Sprintf("n%d = reflect.SliceOf(n%d)", c.result, c.t)
}
func (c *reflectSliceOfConstraint) solve(a *analysis, delta *nodeset) {
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
tObj := nodeid(x)
T := a.rtypeTaggedValue(tObj)
if typeTooHigh(T) {
continue
}
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 ----------
// result = TypeOf(i)
type reflectTypeOfConstraint struct {
cgn *cgnode
i nodeid // (ptr)
result nodeid // (indirect)
}
func (c *reflectTypeOfConstraint) ptr() nodeid { return c.i }
func (c *reflectTypeOfConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result), "reflectTypeOf.result")
}
func (c *reflectTypeOfConstraint) renumber(mapping []nodeid) {
c.i = mapping[c.i]
c.result = mapping[c.result]
}
func (c *reflectTypeOfConstraint) String() string {
return fmt.Sprintf("n%d = reflect.TypeOf(n%d)", c.result, c.i)
}
func (c *reflectTypeOfConstraint) solve(a *analysis, delta *nodeset) {
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
iObj := nodeid(x)
tDyn, _, _ := a.taggedValue(iObj)
if a.addLabel(c.result, a.makeRtype(tDyn)) {
changed = true
}
}
if changed {
a.addWork(c.result)
}
}
func ext۰reflect۰TypeOf(a *analysis, cgn *cgnode) {
a.addConstraint(&reflectTypeOfConstraint{
cgn: cgn,
i: a.funcParams(cgn.obj),
result: a.funcResults(cgn.obj),
})
}
// ---------- func ValueOf(interface{}) Value ----------
func ext۰reflect۰ValueOf(a *analysis, cgn *cgnode) {
// TODO(adonovan): when we start creating indirect tagged
// objects, we'll need to handle them specially here since
// they must never appear in the PTS of an interface{}.
a.copy(a.funcResults(cgn.obj), a.funcParams(cgn.obj), 1)
}
// ---------- func Zero(Type) Value ----------
// result = Zero(typ)
type reflectZeroConstraint struct {
cgn *cgnode
typ nodeid // (ptr)
result nodeid // (indirect)
}
func (c *reflectZeroConstraint) ptr() nodeid { return c.typ }
func (c *reflectZeroConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result), "reflectZero.result")
}
func (c *reflectZeroConstraint) renumber(mapping []nodeid) {
c.typ = mapping[c.typ]
c.result = mapping[c.result]
}
func (c *reflectZeroConstraint) String() string {
return fmt.Sprintf("n%d = reflect.Zero(n%d)", c.result, c.typ)
}
func (c *reflectZeroConstraint) solve(a *analysis, delta *nodeset) {
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
typObj := nodeid(x)
T := a.rtypeTaggedValue(typObj)
// TODO(adonovan): if T is an interface type, we need
// to create an indirect tagged object containing
// new(T). To avoid updates of such shared values,
// we'll need another flag on indirect tagged objects
// that marks whether they are addressable or
// readonly, just like the reflect package does.
// memoize using a.reflectZeros[T]
var id nodeid
if z := a.reflectZeros.At(T); false && z != nil {
id = z.(nodeid)
} else {
id = a.makeTagged(T, c.cgn, nil)
a.reflectZeros.Set(T, id)
}
if a.addLabel(c.result, id) {
changed = true
}
}
if changed {
a.addWork(c.result)
}
}
func ext۰reflect۰Zero(a *analysis, cgn *cgnode) {
a.addConstraint(&reflectZeroConstraint{
cgn: cgn,
typ: a.funcParams(cgn.obj),
result: a.funcResults(cgn.obj),
})
}
// -------------------- (*reflect.rtype) methods --------------------
// ---------- func (*rtype) Elem() Type ----------
// result = Elem(t)
type rtypeElemConstraint struct {
cgn *cgnode
t nodeid // (ptr)
result nodeid // (indirect)
}
func (c *rtypeElemConstraint) ptr() nodeid { return c.t }
func (c *rtypeElemConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result), "rtypeElem.result")
}
func (c *rtypeElemConstraint) renumber(mapping []nodeid) {
c.t = mapping[c.t]
c.result = mapping[c.result]
}
func (c *rtypeElemConstraint) String() string {
return fmt.Sprintf("n%d = (*reflect.rtype).Elem(n%d)", c.result, c.t)
}
func (c *rtypeElemConstraint) solve(a *analysis, delta *nodeset) {
// Implemented by *types.{Map,Chan,Array,Slice,Pointer}.
type hasElem interface {
Elem() types.Type
}
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
tObj := nodeid(x)
T := a.nodes[tObj].obj.data.(types.Type)
if tHasElem, ok := T.Underlying().(hasElem); ok {
if a.addLabel(c.result, a.makeRtype(tHasElem.Elem())) {
changed = true
}
}
}
if changed {
a.addWork(c.result)
}
}
func ext۰reflect۰rtype۰Elem(a *analysis, cgn *cgnode) {
a.addConstraint(&rtypeElemConstraint{
cgn: cgn,
t: a.funcParams(cgn.obj),
result: a.funcResults(cgn.obj),
})
}
// ---------- func (*rtype) Field(int) StructField ----------
// ---------- func (*rtype) FieldByName(string) (StructField, bool) ----------
// result = FieldByName(t, name)
// result = Field(t, _)
type rtypeFieldByNameConstraint struct {
cgn *cgnode
name string // name of field; "" for unknown
t nodeid // (ptr)
result nodeid // (indirect)
}
func (c *rtypeFieldByNameConstraint) ptr() nodeid { return c.t }
func (c *rtypeFieldByNameConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result+3), "rtypeFieldByName.result.Type")
}
func (c *rtypeFieldByNameConstraint) renumber(mapping []nodeid) {
c.t = mapping[c.t]
c.result = mapping[c.result]
}
func (c *rtypeFieldByNameConstraint) String() string {
return fmt.Sprintf("n%d = (*reflect.rtype).FieldByName(n%d, %q)", c.result, c.t, c.name)
}
func (c *rtypeFieldByNameConstraint) solve(a *analysis, delta *nodeset) {
// type StructField struct {
// 0 __identity__
// 1 Name string
// 2 PkgPath string
// 3 Type Type
// 4 Tag StructTag
// 5 Offset uintptr
// 6 Index []int
// 7 Anonymous bool
// }
for _, x := range delta.AppendTo(a.deltaSpace) {
tObj := nodeid(x)
T := a.nodes[tObj].obj.data.(types.Type)
tStruct, ok := T.Underlying().(*types.Struct)
if !ok {
continue // not a struct type
}
n := tStruct.NumFields()
for i := 0; i < n; i++ {
f := tStruct.Field(i)
if c.name == "" || c.name == f.Name() {
// a.offsetOf(Type) is 3.
if id := c.result + 3; a.addLabel(id, a.makeRtype(f.Type())) {
a.addWork(id)
}
// TODO(adonovan): StructField.Index should be non-nil.
}
}
}
}
func ext۰reflect۰rtype۰FieldByName(a *analysis, cgn *cgnode) {
// If we have access to the callsite,
// and the argument is a string constant,
// return only that field.
var name string
if site := cgn.callersite; site != nil {
if c, ok := site.instr.Common().Args[0].(*ssa.Const); ok {
name = exact.StringVal(c.Value)
}
}
a.addConstraint(&rtypeFieldByNameConstraint{
cgn: cgn,
name: name,
t: a.funcParams(cgn.obj),
result: a.funcResults(cgn.obj),
})
}
func ext۰reflect۰rtype۰Field(a *analysis, cgn *cgnode) {
// No-one ever calls Field with a constant argument,
// so we don't specialize that case.
a.addConstraint(&rtypeFieldByNameConstraint{
cgn: cgn,
t: a.funcParams(cgn.obj),
result: a.funcResults(cgn.obj),
})
}
func ext۰reflect۰rtype۰FieldByIndex(a *analysis, cgn *cgnode) {} // TODO(adonovan)
func ext۰reflect۰rtype۰FieldByNameFunc(a *analysis, cgn *cgnode) {} // TODO(adonovan)
// ---------- func (*rtype) In/Out(i int) Type ----------
// result = In/Out(t, i)
type rtypeInOutConstraint struct {
cgn *cgnode
t nodeid // (ptr)
result nodeid // (indirect)
out bool
i int // -ve if not a constant
}
func (c *rtypeInOutConstraint) ptr() nodeid { return c.t }
func (c *rtypeInOutConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result), "rtypeInOut.result")
}
func (c *rtypeInOutConstraint) renumber(mapping []nodeid) {
c.t = mapping[c.t]
c.result = mapping[c.result]
}
func (c *rtypeInOutConstraint) String() string {
return fmt.Sprintf("n%d = (*reflect.rtype).InOut(n%d, %d)", c.result, c.t, c.i)
}
func (c *rtypeInOutConstraint) solve(a *analysis, delta *nodeset) {
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
tObj := nodeid(x)
T := a.nodes[tObj].obj.data.(types.Type)
sig, ok := T.Underlying().(*types.Signature)
if !ok {
continue // not a func type
}
tuple := sig.Params()
if c.out {
tuple = sig.Results()
}
for i, n := 0, tuple.Len(); i < n; i++ {
if c.i < 0 || c.i == i {
if a.addLabel(c.result, a.makeRtype(tuple.At(i).Type())) {
changed = true
}
}
}
}
if changed {
a.addWork(c.result)
}
}
func ext۰reflect۰rtype۰InOut(a *analysis, cgn *cgnode, out bool) {
// If we have access to the callsite,
// and the argument is an int constant,
// return only that parameter.
index := -1
if site := cgn.callersite; site != nil {
if c, ok := site.instr.Common().Args[0].(*ssa.Const); ok {
v, _ := exact.Int64Val(c.Value)
index = int(v)
}
}
a.addConstraint(&rtypeInOutConstraint{
cgn: cgn,
t: a.funcParams(cgn.obj),
result: a.funcResults(cgn.obj),
out: out,
i: index,
})
}
func ext۰reflect۰rtype۰In(a *analysis, cgn *cgnode) {
ext۰reflect۰rtype۰InOut(a, cgn, false)
}
func ext۰reflect۰rtype۰Out(a *analysis, cgn *cgnode) {
ext۰reflect۰rtype۰InOut(a, cgn, true)
}
// ---------- func (*rtype) Key() Type ----------
// result = Key(t)
type rtypeKeyConstraint struct {
cgn *cgnode
t nodeid // (ptr)
result nodeid // (indirect)
}
func (c *rtypeKeyConstraint) ptr() nodeid { return c.t }
func (c *rtypeKeyConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result), "rtypeKey.result")
}
func (c *rtypeKeyConstraint) renumber(mapping []nodeid) {
c.t = mapping[c.t]
c.result = mapping[c.result]
}
func (c *rtypeKeyConstraint) String() string {
return fmt.Sprintf("n%d = (*reflect.rtype).Key(n%d)", c.result, c.t)
}
func (c *rtypeKeyConstraint) solve(a *analysis, delta *nodeset) {
changed := false
for _, x := range delta.AppendTo(a.deltaSpace) {
tObj := nodeid(x)
T := a.nodes[tObj].obj.data.(types.Type)
if tMap, ok := T.Underlying().(*types.Map); ok {
if a.addLabel(c.result, a.makeRtype(tMap.Key())) {
changed = true
}
}
}
if changed {
a.addWork(c.result)
}
}
func ext۰reflect۰rtype۰Key(a *analysis, cgn *cgnode) {
a.addConstraint(&rtypeKeyConstraint{
cgn: cgn,
t: a.funcParams(cgn.obj),
result: a.funcResults(cgn.obj),
})
}
// ---------- func (*rtype) Method(int) (Method, bool) ----------
// ---------- func (*rtype) MethodByName(string) (Method, bool) ----------
// result = MethodByName(t, name)
// result = Method(t, _)
type rtypeMethodByNameConstraint struct {
cgn *cgnode
name string // name of method; "" for unknown
t nodeid // (ptr)
result nodeid // (indirect)
}
func (c *rtypeMethodByNameConstraint) ptr() nodeid { return c.t }
func (c *rtypeMethodByNameConstraint) presolve(h *hvn) {
h.markIndirect(onodeid(c.result+3), "rtypeMethodByName.result.Type")
h.markIndirect(onodeid(c.result+4), "rtypeMethodByName.result.Func")
}
func (c *rtypeMethodByNameConstraint) renumber(mapping []nodeid) {
c.t = mapping[c.t]
c.result = mapping[c.result]
}
func (c *rtypeMethodByNameConstraint) String() string {
return fmt.Sprintf("n%d = (*reflect.rtype).MethodByName(n%d, %q)", c.result, c.t, c.name)
}
// changeRecv returns sig with Recv prepended to Params().
func changeRecv(sig *types.Signature) *types.Signature {
params := sig.Params()
n := params.Len()
p2 := make([]*types.Var, n+1)
p2[0] = sig.Recv()
for i := 0; i < n; i++ {
p2[i+1] = params.At(i)
}
return types.NewSignature(nil, types.NewTuple(p2...), sig.Results(), sig.Variadic())
}
func (c *rtypeMethodByNameConstraint) solve(a *analysis, delta *nodeset) {
for _, x := range delta.AppendTo(a.deltaSpace) {
tObj := nodeid(x)
T := a.nodes[tObj].obj.data.(types.Type)
isIface := isInterface(T)
// We don't use Lookup(c.name) when c.name != "" to avoid
// ambiguity: >1 unexported methods could match.
mset := a.prog.MethodSets.MethodSet(T)
for i, n := 0, mset.Len(); i < n; i++ {
sel := mset.At(i)
if c.name == "" || c.name == sel.Obj().Name() {
// type Method struct {
// 0 __identity__
// 1 Name string
// 2 PkgPath string
// 3 Type Type
// 4 Func Value
// 5 Index int
// }
var sig *types.Signature
var fn *ssa.Function
if isIface {
sig = sel.Type().(*types.Signature)
} else {
fn = a.prog.MethodValue(sel)
// move receiver to params[0]
sig = changeRecv(fn.Signature)
}
// a.offsetOf(Type) is 3.
if id := c.result + 3; a.addLabel(id, a.makeRtype(sig)) {
a.addWork(id)
}
if fn != nil {
// a.offsetOf(Func) is 4.
if id := c.result + 4; a.addLabel(id, a.objectNode(nil, fn)) {
a.addWork(id)
}
}
}
}
}
}
func ext۰reflect۰rtype۰MethodByName(a *analysis, cgn *cgnode) {
// If we have access to the callsite,
// and the argument is a string constant,
// return only that method.
var name string
if site := cgn.callersite; site != nil {
if c, ok := site.instr.Common().Args[0].(*ssa.Const); ok {
name = exact.StringVal(c.Value)
}
}
a.addConstraint(&rtypeMethodByNameConstraint{
cgn: cgn,
name: name,
t: a.funcParams(cgn.obj),
result: a.funcResults(cgn.obj),
})
}
func ext۰reflect۰rtype۰Method(a *analysis, cgn *cgnode) {
// No-one ever calls Method with a constant argument,
// so we don't specialize that case.
a.addConstraint(&rtypeMethodByNameConstraint{
cgn: cgn,
t: a.funcParams(cgn.obj),
result: a.funcResults(cgn.obj),
})
}
// typeHeight returns the "height" of the type, which is roughly
// speaking the number of chan, map, pointer and slice type constructors
// at the root of T; these are the four type kinds that can be created
// via reflection. Chan and map constructors are counted as double the
// height of slice and pointer constructors since they are less often
// deeply nested.
//
// The solver rules for type constructors must somehow bound the set of
// types they create to ensure termination of the algorithm in cases
// where the output of a type constructor flows to its input, e.g.
//
// func f(t reflect.Type) {
// f(reflect.PtrTo(t))
// }
//
// It does this by limiting the type height to k, but this still leaves
// a potentially exponential (4^k) number of of types that may be
// enumerated in pathological cases.
//
func typeHeight(T types.Type) int {
switch T := T.(type) {
case *types.Chan:
return 2 + typeHeight(T.Elem())
case *types.Map:
k := typeHeight(T.Key())
v := typeHeight(T.Elem())
if v > k {
k = v // max(k, v)
}
return 2 + k
case *types.Slice:
return 1 + typeHeight(T.Elem())
case *types.Pointer:
return 1 + typeHeight(T.Elem())
}
return 0
}
func typeTooHigh(T types.Type) bool {
return typeHeight(T) > 3
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/lonely0422/gometalinter.git
git@gitee.com:lonely0422/gometalinter.git
lonely0422
gometalinter
gometalinter
v2.0.9

搜索帮助