src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

serialize.go (3099B)


      1 package unused
      2 
      3 import (
      4 	"fmt"
      5 	"go/token"
      6 	"os"
      7 
      8 	"golang.org/x/tools/go/types/objectpath"
      9 )
     10 
     11 type ObjectPath struct {
     12 	PkgPath string
     13 	ObjPath objectpath.Path
     14 }
     15 
     16 // XXX make sure that node 0 always exists and is always the root
     17 
     18 type SerializedGraph struct {
     19 	nodes       []Node
     20 	nodesByPath map[ObjectPath]NodeID
     21 	// XXX deduplicating on position is dubious for `switch x := foo.(type)`, where x will be declared many times for
     22 	// the different types, but all at the same position. On the other hand, merging these nodes is probably fine.
     23 	nodesByPosition map[token.Position]NodeID
     24 }
     25 
     26 func trace(f string, args ...any) {
     27 	fmt.Fprintf(os.Stderr, f, args...)
     28 	fmt.Fprintln(os.Stderr)
     29 }
     30 
     31 func (g *SerializedGraph) Merge(nodes []Node) {
     32 	if g.nodesByPath == nil {
     33 		g.nodesByPath = map[ObjectPath]NodeID{}
     34 	}
     35 	if g.nodesByPosition == nil {
     36 		g.nodesByPosition = map[token.Position]NodeID{}
     37 	}
     38 	if len(g.nodes) == 0 {
     39 		// Seed nodes with a root node
     40 		g.nodes = append(g.nodes, Node{})
     41 	}
     42 	// OPT(dh): reuse storage between calls to Merge
     43 	remapping := make([]NodeID, len(nodes))
     44 
     45 	// First pass: compute remapping of IDs of to-be-merged nodes
     46 	for _, n := range nodes {
     47 		// XXX Column is never 0. it's 1 if there is no column information in the export data. which sucks, because
     48 		// objects can also genuinely be in column 1.
     49 		if n.id != 0 && n.obj.Path == (ObjectPath{}) && n.obj.Position.Column == 0 {
     50 			// If the object has no path, then it couldn't have come from export data, which means it needs to have full
     51 			// position information including a column.
     52 			panic(fmt.Sprintf("object %q has no path but also no column information", n.obj.Name))
     53 		}
     54 
     55 		if orig, ok := g.nodesByPath[n.obj.Path]; ok {
     56 			// We already have a node for this object
     57 			trace("deduplicating %d -> %d based on path %s", n.id, orig, n.obj.Path)
     58 			remapping[n.id] = orig
     59 		} else if orig, ok := g.nodesByPosition[n.obj.Position]; ok && n.obj.Position.Column != 0 {
     60 			// We already have a node for this object
     61 			trace("deduplicating %d -> %d based on position %s", n.id, orig, n.obj.Position)
     62 			remapping[n.id] = orig
     63 		} else {
     64 			// This object is new to us; change ID to avoid collision
     65 			newID := NodeID(len(g.nodes))
     66 			trace("new node, remapping %d -> %d", n.id, newID)
     67 			remapping[n.id] = newID
     68 			g.nodes = append(g.nodes, Node{
     69 				id:   newID,
     70 				obj:  n.obj,
     71 				uses: make([]NodeID, 0, len(n.uses)),
     72 				owns: make([]NodeID, 0, len(n.owns)),
     73 			})
     74 			if n.id == 0 {
     75 				// Our root uses all the roots of the subgraphs
     76 				g.nodes[0].uses = append(g.nodes[0].uses, newID)
     77 			}
     78 			if n.obj.Path != (ObjectPath{}) {
     79 				g.nodesByPath[n.obj.Path] = newID
     80 			}
     81 			if n.obj.Position.Column != 0 {
     82 				g.nodesByPosition[n.obj.Position] = newID
     83 			}
     84 		}
     85 	}
     86 
     87 	// Second step: apply remapping
     88 	for _, n := range nodes {
     89 		n.id = remapping[n.id]
     90 		for i := range n.uses {
     91 			n.uses[i] = remapping[n.uses[i]]
     92 		}
     93 		for i := range n.owns {
     94 			n.owns[i] = remapping[n.owns[i]]
     95 		}
     96 		g.nodes[n.id].uses = append(g.nodes[n.id].uses, n.uses...)
     97 		g.nodes[n.id].owns = append(g.nodes[n.id].owns, n.owns...)
     98 	}
     99 }