blob: 4d7dbaef7cad034d67a4f19646532fd63b647f6d [file] [log] [blame]
Zack Williamse940c7a2019-08-21 14:25:39 -07001package internal
2
3import (
4 dpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
5)
6
7// SourceInfoMap is a map of paths in a descriptor to the corresponding source
8// code info.
9type SourceInfoMap map[string]*dpb.SourceCodeInfo_Location
10
11// Get returns the source code info for the given path.
12func (m SourceInfoMap) Get(path []int32) *dpb.SourceCodeInfo_Location {
13 return m[asMapKey(path)]
14}
15
16// Put stores the given source code info for the given path.
17func (m SourceInfoMap) Put(path []int32, loc *dpb.SourceCodeInfo_Location) {
18 m[asMapKey(path)] = loc
19}
20
21// PutIfAbsent stores the given source code info for the given path only if the
22// given path does not exist in the map. This method returns true when the value
23// is stored, false if the path already exists.
24func (m SourceInfoMap) PutIfAbsent(path []int32, loc *dpb.SourceCodeInfo_Location) bool {
25 k := asMapKey(path)
26 if _, ok := m[k]; ok {
27 return false
28 }
29 m[k] = loc
30 return true
31}
32
33func asMapKey(slice []int32) string {
34 // NB: arrays should be usable as map keys, but this does not
35 // work due to a bug: https://github.com/golang/go/issues/22605
36 //rv := reflect.ValueOf(slice)
37 //arrayType := reflect.ArrayOf(rv.Len(), rv.Type().Elem())
38 //array := reflect.New(arrayType).Elem()
39 //reflect.Copy(array, rv)
40 //return array.Interface()
41
42 b := make([]byte, len(slice)*4)
43 for i, s := range slice {
44 j := i * 4
45 b[j] = byte(s)
46 b[j+1] = byte(s >> 8)
47 b[j+2] = byte(s >> 16)
48 b[j+3] = byte(s >> 24)
49 }
50 return string(b)
51}
52
53// CreateSourceInfoMap constructs a new SourceInfoMap and populates it with the
54// source code info in the given file descriptor proto.
55func CreateSourceInfoMap(fd *dpb.FileDescriptorProto) SourceInfoMap {
56 res := SourceInfoMap{}
57 PopulateSourceInfoMap(fd, res)
58 return res
59}
60
61// PopulateSourceInfoMap populates the given SourceInfoMap with information from
62// the given file descriptor.
63func PopulateSourceInfoMap(fd *dpb.FileDescriptorProto, m SourceInfoMap) {
64 for _, l := range fd.GetSourceCodeInfo().GetLocation() {
65 m.Put(l.Path, l)
66 }
67}
68
69// NB: This wonkiness allows desc.Descriptor impl to implement an interface that
70// is only usable from this package, by embedding a SourceInfoComputeFunc that
71// implements the actual logic (which must live in desc package to avoid a
72// dependency cycle).
73
74// SourceInfoComputer is a single method which will be invoked to recompute
75// source info. This is needed for the protoparse package, which needs to link
76// descriptors without source info in order to interpret options, but then needs
77// to re-compute source info after that interpretation so that final linked
78// descriptors expose the right info.
79type SourceInfoComputer interface {
80 recomputeSourceInfo()
81}
82
83// SourceInfoComputeFunc is the type that a desc.Descriptor will embed. It will
84// be aliased in the desc package to an unexported name so it is not marked as
85// an exported field in reflection and not present in Go docs.
86type SourceInfoComputeFunc func()
87
88func (f SourceInfoComputeFunc) recomputeSourceInfo() {
89 f()
90}
91
92// RecomputeSourceInfo is used to initiate recomputation of source info. This is
93// is used by the protoparse package, after it interprets options.
94func RecomputeSourceInfo(c SourceInfoComputer) {
95 c.recomputeSourceInfo()
96}