| // 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) |
| } |
| } |
| } |