|  | // Copyright 2021 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 symbols | 
|  |  | 
|  | // This file is a subset of golang.org/x/vuln/internal/vulncheck/slicing.go. | 
|  |  | 
|  | import ( | 
|  | "golang.org/x/tools/go/callgraph" | 
|  | "golang.org/x/tools/go/ssa" | 
|  | ) | 
|  |  | 
|  | // forwardSlice computes the transitive closure of functions forward reachable | 
|  | // via calls in cg or referred to in an instruction starting from `sources`. | 
|  | func forwardSlice(sources map[*ssa.Function]bool, cg *callgraph.Graph) map[*ssa.Function]bool { | 
|  | seen := make(map[*ssa.Function]bool) | 
|  | var visit func(f *ssa.Function) | 
|  | visit = func(f *ssa.Function) { | 
|  | if seen[f] { | 
|  | return | 
|  | } | 
|  | seen[f] = true | 
|  |  | 
|  | if n := cg.Nodes[f]; n != nil { | 
|  | for _, e := range n.Out { | 
|  | if e.Site != nil { | 
|  | visit(e.Callee.Func) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | var buf [10]*ssa.Value // avoid alloc in common case | 
|  | for _, b := range f.Blocks { | 
|  | for _, instr := range b.Instrs { | 
|  | for _, op := range instr.Operands(buf[:0]) { | 
|  | if fn, ok := (*op).(*ssa.Function); ok { | 
|  | visit(fn) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | for source := range sources { | 
|  | visit(source) | 
|  | } | 
|  | return seen | 
|  | } | 
|  |  | 
|  | // pruneSet removes functions in `set` that are in `toPrune`. | 
|  | func pruneSet(set, toPrune map[*ssa.Function]bool) { | 
|  | for f := range set { | 
|  | if !toPrune[f] { | 
|  | delete(set, f) | 
|  | } | 
|  | } | 
|  | } |