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