github.com/Big-big-orange/protoreflect@v0.0.0-20240408141420-285cedfdf6a4/desc/internal/source_info.go (about) 1 package internal 2 3 import ( 4 "google.golang.org/protobuf/types/descriptorpb" 5 ) 6 7 // SourceInfoMap is a map of paths in a descriptor to the corresponding source 8 // code info. 9 type SourceInfoMap map[string][]*descriptorpb.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. 13 func (m SourceInfoMap) Get(path []int32) *descriptorpb.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. 22 func (m SourceInfoMap) GetAll(path []int32) []*descriptorpb.SourceCodeInfo_Location { 23 return m[asMapKey(path)] 24 } 25 26 // Add stores the given source code info for the given path. 27 func (m SourceInfoMap) Add(path []int32, loc *descriptorpb.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. 34 func (m SourceInfoMap) PutIfAbsent(path []int32, loc *descriptorpb.SourceCodeInfo_Location) bool { 35 k := asMapKey(path) 36 if _, ok := m[k]; ok { 37 return false 38 } 39 m[k] = []*descriptorpb.SourceCodeInfo_Location{loc} 40 return true 41 } 42 43 func 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. 66 func CreateSourceInfoMap(fd *descriptorpb.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. 74 func PopulateSourceInfoMap(fd *descriptorpb.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. 90 type 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. 97 type SourceInfoComputeFunc func() 98 99 func (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. 105 func RecomputeSourceInfo(c SourceInfoComputer) { 106 c.recomputeSourceInfo() 107 }