serialize.go raw

   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 ...interface{}) {
  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  }
 100