kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/go/util/markedsource/resolve.go (about) 1 /* 2 * Copyright 2023 The Kythe Authors. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package markedsource 18 19 import ( 20 "fmt" 21 22 "kythe.io/kythe/go/util/kytheuri" 23 "kythe.io/kythe/go/util/schema/edges" 24 "kythe.io/kythe/go/util/schema/facts" 25 26 "google.golang.org/protobuf/encoding/protojson" 27 "google.golang.org/protobuf/proto" 28 29 cpb "kythe.io/kythe/proto/common_go_proto" 30 spb "kythe.io/kythe/proto/storage_go_proto" 31 ) 32 33 // Resolver produces fully resolved MarkedSources from a set of entries. 34 type Resolver struct { 35 nodes map[string]*cpb.MarkedSource 36 37 params map[string][]string 38 tparams map[string][]string 39 typed map[string]string 40 } 41 42 // NewResolver constructs a MarkedSource resolver from the given entries. 43 func NewResolver(entries []*spb.Entry) (*Resolver, error) { 44 r := &Resolver{ 45 nodes: make(map[string]*cpb.MarkedSource), 46 params: make(map[string][]string), 47 tparams: make(map[string][]string), 48 typed: make(map[string]string), 49 } 50 for _, e := range entries { 51 if e.GetFactName() == facts.Code { 52 ticket := kytheuri.ToString(e.GetSource()) 53 var ms cpb.MarkedSource 54 if err := proto.Unmarshal(e.GetFactValue(), &ms); err != nil { 55 return nil, fmt.Errorf("error unmarshalling code for %s: %v", ticket, err) 56 } 57 r.nodes[ticket] = &ms 58 } else if e.GetFactName() == facts.Code+"/json" { 59 ticket := kytheuri.ToString(e.GetSource()) 60 var ms cpb.MarkedSource 61 if err := protojson.Unmarshal(e.GetFactValue(), &ms); err != nil { 62 return nil, fmt.Errorf("error unmarshalling code/json for %s: %v", ticket, err) 63 } 64 r.nodes[ticket] = &ms 65 } else if e.GetEdgeKind() != "" { 66 ticket := kytheuri.ToString(e.GetSource()) 67 kind, ord, _ := edges.ParseOrdinal(e.GetEdgeKind()) 68 if ord < 0 { 69 return nil, fmt.Errorf("invalid ordinal: %d", ord) 70 } 71 switch kind { 72 case edges.Typed: 73 r.typed[ticket] = kytheuri.ToString(e.GetTarget()) 74 case edges.Param: 75 params := r.params[ticket] 76 if len(params)-1 < ord { 77 n := make([]string, ord+1) 78 copy(n, params) 79 params = n 80 r.params[ticket] = params 81 } 82 params[ord] = kytheuri.ToString(e.GetTarget()) 83 case edges.TParam: 84 tparams := r.tparams[ticket] 85 if len(tparams)-1 < ord { 86 n := make([]string, ord+1) 87 copy(n, tparams) 88 tparams = n 89 r.tparams[ticket] = tparams 90 } 91 tparams[ord] = kytheuri.ToString(e.GetTarget()) 92 } 93 } 94 } 95 return r, nil 96 } 97 98 // Resolve returns the fully resolved MarkedSource for the given source VName. 99 // May return nil if no MarkedSource is found. 100 func (r *Resolver) Resolve(src *spb.VName) *cpb.MarkedSource { 101 return r.ResolveTicket(kytheuri.ToString(src)) 102 } 103 104 // ResolveTicket returns the fully resolved MarkedSource for the given source ticket. 105 // May return nil if no MarkedSource is found. 106 func (r *Resolver) ResolveTicket(ticket string) *cpb.MarkedSource { 107 if ticket == "" { 108 return nil 109 } 110 return r.resolve(ticket, r.nodes[ticket]) 111 } 112 113 func ensureKind(ms *cpb.MarkedSource, k cpb.MarkedSource_Kind) *cpb.MarkedSource { 114 if ms.GetKind() == k { 115 return ms 116 } 117 if ms != nil && ms.GetKind() == cpb.MarkedSource_BOX { 118 ret := proto.Clone(ms).(*cpb.MarkedSource) 119 ret.Kind = k 120 return ret 121 } 122 return &cpb.MarkedSource{ 123 Kind: k, 124 Child: []*cpb.MarkedSource{ms}, 125 } 126 } 127 128 func removeExcluded(kind cpb.MarkedSource_Kind, ms *cpb.MarkedSource) *cpb.MarkedSource { 129 for _, k := range ms.GetExcludeOnInclude() { 130 if k == kind { 131 return nil 132 } 133 } 134 if len(ms.GetChild()) == 0 { 135 return ms 136 } 137 138 children := make([]*cpb.MarkedSource, 0, len(ms.GetChild())) 139 for _, c := range ms.GetChild() { 140 if e := removeExcluded(kind, c); e != nil { 141 children = append(children, e) 142 } 143 } 144 res := proto.Clone(ms).(*cpb.MarkedSource) 145 res.Child = children 146 return res 147 } 148 149 var invalidLookupReplacement = &cpb.MarkedSource{PreText: "???"} 150 151 func (r *Resolver) resolve(ticket string, ms *cpb.MarkedSource) *cpb.MarkedSource { 152 if ms == nil { 153 return ms 154 } 155 switch ms.GetKind() { 156 case cpb.MarkedSource_LOOKUP_BY_PARAM: 157 params := r.params[ticket] 158 if int(ms.GetLookupIndex()) >= len(params) { 159 return ensureKind(invalidLookupReplacement, cpb.MarkedSource_PARAMETER) 160 } 161 if p := params[ms.GetLookupIndex()]; p != "" { 162 return removeExcluded(ms.GetKind(), ensureKind(r.ResolveTicket(p), cpb.MarkedSource_PARAMETER)) 163 } 164 case cpb.MarkedSource_LOOKUP_BY_TPARAM: 165 tparams := r.tparams[ticket] 166 if int(ms.GetLookupIndex()) >= len(tparams) { 167 return ensureKind(invalidLookupReplacement, cpb.MarkedSource_PARAMETER) 168 } 169 if p := tparams[ms.GetLookupIndex()]; p != "" { 170 return removeExcluded(ms.GetKind(), ensureKind(r.ResolveTicket(p), cpb.MarkedSource_PARAMETER)) 171 } 172 case cpb.MarkedSource_LOOKUP_BY_TYPED: 173 return removeExcluded(ms.GetKind(), ensureKind(r.ResolveTicket(r.typed[ticket]), cpb.MarkedSource_TYPE)) 174 case cpb.MarkedSource_PARAMETER_LOOKUP_BY_PARAM_WITH_DEFAULTS, cpb.MarkedSource_PARAMETER_LOOKUP_BY_PARAM: 175 // TODO: handle param/default 176 params := r.params[ticket] 177 if int(ms.GetLookupIndex()) > len(params) { 178 return ensureKind(invalidLookupReplacement, cpb.MarkedSource_PARAMETER) 179 } 180 return r.resolveParameters(ms, params[ms.GetLookupIndex():]) 181 case cpb.MarkedSource_PARAMETER_LOOKUP_BY_TPARAM: 182 tparams := r.tparams[ticket] 183 if int(ms.GetLookupIndex()) > len(tparams) { 184 return ensureKind(invalidLookupReplacement, cpb.MarkedSource_PARAMETER) 185 } 186 return r.resolveParameters(ms, tparams[ms.GetLookupIndex():]) 187 } 188 return r.resolveChildren(ticket, ms) 189 } 190 191 func (r *Resolver) resolveParameters(base *cpb.MarkedSource, params []string) *cpb.MarkedSource { 192 n := proto.Clone(base).(*cpb.MarkedSource) 193 n.LookupIndex = 0 194 n.Kind = cpb.MarkedSource_PARAMETER 195 n.Child = make([]*cpb.MarkedSource, 0, len(params)) 196 for _, p := range params { 197 if c := removeExcluded(base.GetKind(), r.ResolveTicket(p)); c != nil { 198 n.Child = append(n.Child, c) 199 } 200 } 201 return n 202 } 203 204 func (r *Resolver) resolveChildren(ticket string, ms *cpb.MarkedSource) *cpb.MarkedSource { 205 n := proto.Clone(ms).(*cpb.MarkedSource) 206 children := make([]*cpb.MarkedSource, 0, len(n.GetChild())) 207 for _, ms := range n.GetChild() { 208 if c := r.resolve(ticket, ms); c != nil { 209 children = append(children, c) 210 } 211 } 212 n.Child = children 213 return n 214 }