kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/go/services/cli/commands_xrefs.go (about) 1 /* 2 * Copyright 2017 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 cli 18 19 import ( 20 "context" 21 "flag" 22 "fmt" 23 "strings" 24 25 "kythe.io/kythe/go/util/flagutil" 26 "kythe.io/kythe/go/util/kytheuri" 27 "kythe.io/kythe/go/util/log" 28 "kythe.io/kythe/go/util/markedsource" 29 "kythe.io/kythe/go/util/schema/edges" 30 "kythe.io/kythe/go/util/schema/facts" 31 32 cpb "kythe.io/kythe/proto/common_go_proto" 33 xpb "kythe.io/kythe/proto/xref_go_proto" 34 ) 35 36 type xrefsCommand struct { 37 baseKytheCommand 38 nodeFilters flagutil.StringList 39 buildConfigs flagutil.StringSet 40 41 workspaceURI string 42 43 pageToken string 44 pageSize int 45 46 defKind string 47 declKind string 48 refKind string 49 callerKind string 50 51 semanticScopes bool 52 relatedNodes bool 53 nodeDefinitions bool 54 anchorText bool 55 56 resolvedPathFilters flagutil.StringList 57 58 excludeGenerated bool 59 60 totalsOnly bool 61 } 62 63 func (xrefsCommand) Name() string { return "xrefs" } 64 func (xrefsCommand) Synopsis() string { return "retrieve cross-references for the given node" } 65 func (xrefsCommand) Usage() string { return "" } 66 func (c *xrefsCommand) SetFlags(flag *flag.FlagSet) { 67 flag.StringVar(&c.defKind, "definitions", "binding", "Kind of definitions to return (kinds: all, binding, full, or none)") 68 flag.StringVar(&c.declKind, "declarations", "all", "Kind of declarations to return (kinds: all or none)") 69 flag.StringVar(&c.refKind, "references", "noncall", "Kind of references to return (kinds: all, noncall, call, or none)") 70 flag.StringVar(&c.callerKind, "callers", "direct", "Kind of callers to return (kinds: direct, overrides, or none)") 71 flag.StringVar(&c.workspaceURI, "workspace_uri", "", "Workspace URI to patch cross-references") 72 flag.BoolVar(&c.relatedNodes, "related_nodes", true, "Whether to request related nodes") 73 flag.Var(&c.nodeFilters, "filters", "CSV list of additional fact filters to use when requesting related nodes") 74 flag.Var(&c.resolvedPathFilters, "resolved_path_filters", "CSV list of additional resolved path filters to use") 75 flag.Var(&c.buildConfigs, "build_config", "CSV set of build configs with which to filter file decorations") 76 flag.BoolVar(&c.nodeDefinitions, "node_definitions", false, "Whether to request definition locations for related nodes") 77 flag.BoolVar(&c.anchorText, "anchor_text", false, "Whether to request text for anchors") 78 flag.BoolVar(&c.semanticScopes, "semantic_scopes", false, "Whether to include semantic scopes") 79 flag.BoolVar(&c.excludeGenerated, "exclude_generated", false, "Whether to exclude anchors with non-empty roots") 80 81 flag.BoolVar(&c.totalsOnly, "totals_only", false, "Only output total count of xrefs") 82 83 flag.StringVar(&c.pageToken, "page_token", "", "CrossReferences page token") 84 flag.IntVar(&c.pageSize, "page_size", 0, "Maximum number of cross-references returned (0 lets the service use a sensible default)") 85 } 86 func (c xrefsCommand) Run(ctx context.Context, flag *flag.FlagSet, api API) error { 87 req := &xpb.CrossReferencesRequest{ 88 Ticket: flag.Args(), 89 PageToken: c.pageToken, 90 PageSize: int32(c.pageSize), 91 Snippets: xpb.SnippetsKind_DEFAULT, 92 TotalsQuality: xpb.CrossReferencesRequest_APPROXIMATE_TOTALS, 93 94 SemanticScopes: c.semanticScopes, 95 AnchorText: c.anchorText, 96 NodeDefinitions: c.nodeDefinitions, 97 98 CorpusPathFilters: &xpb.CorpusPathFilters{}, 99 } 100 if c.workspaceURI != "" { 101 req.Workspace = &xpb.Workspace{Uri: c.workspaceURI} 102 req.PatchAgainstWorkspace = true 103 } 104 if c.excludeGenerated { 105 req.CorpusPathFilters.Filter = append(req.CorpusPathFilters.Filter, &xpb.CorpusPathFilter{ 106 Type: xpb.CorpusPathFilter_EXCLUDE, 107 Root: ".+", 108 }) 109 } 110 for _, f := range c.resolvedPathFilters { 111 req.CorpusPathFilters.Filter = append(req.CorpusPathFilters.Filter, &xpb.CorpusPathFilter{ 112 Type: xpb.CorpusPathFilter_INCLUDE_ONLY, 113 ResolvedPath: f, 114 }) 115 } 116 if c.relatedNodes { 117 req.Filter = []string{facts.NodeKind, facts.Subkind} 118 if len(c.nodeFilters) > 0 && (len(c.nodeFilters) != 1 || c.nodeFilters[0] != "") { 119 req.Filter = append(req.Filter, c.nodeFilters...) 120 } 121 } 122 req.BuildConfig = c.buildConfigs.Elements() 123 switch c.defKind { 124 case "all": 125 req.DefinitionKind = xpb.CrossReferencesRequest_ALL_DEFINITIONS 126 case "none": 127 req.DefinitionKind = xpb.CrossReferencesRequest_NO_DEFINITIONS 128 case "binding": 129 req.DefinitionKind = xpb.CrossReferencesRequest_BINDING_DEFINITIONS 130 case "full": 131 req.DefinitionKind = xpb.CrossReferencesRequest_FULL_DEFINITIONS 132 default: 133 return fmt.Errorf("unknown definition kind: %q", c.defKind) 134 } 135 switch c.declKind { 136 case "all": 137 req.DeclarationKind = xpb.CrossReferencesRequest_ALL_DECLARATIONS 138 case "none": 139 req.DeclarationKind = xpb.CrossReferencesRequest_NO_DECLARATIONS 140 default: 141 return fmt.Errorf("unknown declaration kind: %q", c.declKind) 142 } 143 switch c.refKind { 144 case "all": 145 req.ReferenceKind = xpb.CrossReferencesRequest_ALL_REFERENCES 146 case "noncall": 147 req.ReferenceKind = xpb.CrossReferencesRequest_NON_CALL_REFERENCES 148 case "call": 149 req.ReferenceKind = xpb.CrossReferencesRequest_CALL_REFERENCES 150 case "none": 151 req.ReferenceKind = xpb.CrossReferencesRequest_NO_REFERENCES 152 default: 153 return fmt.Errorf("unknown reference kind: %q", c.refKind) 154 } 155 switch c.callerKind { 156 case "direct": 157 req.CallerKind = xpb.CrossReferencesRequest_DIRECT_CALLERS 158 case "overrides": 159 req.CallerKind = xpb.CrossReferencesRequest_OVERRIDE_CALLERS 160 case "none": 161 req.CallerKind = xpb.CrossReferencesRequest_NO_CALLERS 162 default: 163 return fmt.Errorf("unknown caller kind: %q", c.callerKind) 164 } 165 LogRequest(req) 166 reply, err := api.XRefService.CrossReferences(ctx, req) 167 if err != nil { 168 return err 169 } 170 if reply.NextPageToken != "" { 171 defer log.InfoContextf(ctx, "Next page token: %s", reply.NextPageToken) 172 } 173 return c.displayXRefs(reply) 174 } 175 176 func (c xrefsCommand) displayXRefs(reply *xpb.CrossReferencesReply) error { 177 if DisplayJSON { 178 return PrintJSONMessage(reply) 179 } 180 181 fmt.Fprintf(out, "Totals:\n%s\n\n", reply.GetTotal()) 182 183 if c.totalsOnly { 184 return nil 185 } 186 187 for _, xr := range reply.CrossReferences { 188 var sig string 189 if xr.MarkedSource != nil { 190 sig = showSignature(xr.MarkedSource) + " " 191 } 192 if _, err := fmt.Fprintf(out, "Cross-References for %s%s\n", sig, xr.Ticket); err != nil { 193 return err 194 } 195 if err := displayRelatedAnchors("Definitions", xr.Definition); err != nil { 196 return err 197 } 198 if err := displayRelatedAnchors("Declarations", xr.Declaration); err != nil { 199 return err 200 } 201 if err := displayRelatedAnchors("References", xr.Reference); err != nil { 202 return err 203 } 204 if err := displayRelatedAnchors("Callers", xr.Caller); err != nil { 205 return err 206 } 207 if len(xr.RelatedNode) > 0 { 208 if _, err := fmt.Fprintln(out, " Related Nodes:"); err != nil { 209 return err 210 } 211 for _, n := range xr.RelatedNode { 212 var nodeKind, subkind string 213 if node, ok := reply.Nodes[n.Ticket]; ok { 214 for name, value := range node.Facts { 215 switch name { 216 case facts.NodeKind: 217 nodeKind = string(value) 218 case facts.Subkind: 219 subkind = string(value) 220 } 221 } 222 } 223 if nodeKind == "" { 224 nodeKind = "UNKNOWN" 225 } else if subkind != "" { 226 nodeKind += "/" + subkind 227 } 228 var ordinal string 229 if edges.OrdinalKind(n.RelationKind) || n.Ordinal != 0 { 230 ordinal = fmt.Sprintf(".%d", n.Ordinal) 231 } 232 if _, err := fmt.Fprintf(out, " %s %s%s [%s]\n", n.Ticket, n.RelationKind, ordinal, nodeKind); err != nil { 233 return err 234 } 235 } 236 } 237 } 238 239 return nil 240 } 241 242 func displayRelatedAnchors(kind string, anchors []*xpb.CrossReferencesReply_RelatedAnchor) error { 243 if len(anchors) == 0 { 244 return nil 245 } 246 247 if _, err := fmt.Fprintf(out, " %s:\n", kind); err != nil { 248 return err 249 } 250 251 for _, a := range anchors { 252 pURI, err := kytheuri.Parse(a.Anchor.Parent) 253 if err != nil { 254 return err 255 } 256 if _, err := fmt.Fprintf(out, " %s\t", pURI.Path); err != nil { 257 return err 258 } 259 if a.MarkedSource != nil { 260 if _, err := fmt.Fprintf(out, "%s\t", showSignature(a.MarkedSource)); err != nil { 261 return err 262 } 263 } 264 if _, err := fmt.Fprintf(out, " [%d:%d-%d:%d %s)\n %q\n", 265 a.GetAnchor().GetSpan().GetStart().GetLineNumber(), a.GetAnchor().GetSpan().GetStart().GetColumnOffset(), 266 a.GetAnchor().GetSpan().GetEnd().GetLineNumber(), a.GetAnchor().GetSpan().GetEnd().GetColumnOffset(), 267 a.GetAnchor().GetKind(), string(a.GetAnchor().GetSnippet())); err != nil { 268 return err 269 } 270 for _, site := range a.Site { 271 if _, err := fmt.Fprintf(out, " [%d:%d-%d-%d %s)\n %q\n", 272 site.GetSpan().GetStart().GetLineNumber(), site.GetSpan().GetStart().GetColumnOffset(), 273 site.GetSpan().GetEnd().GetLineNumber(), site.GetSpan().GetEnd().GetColumnOffset(), 274 site.GetKind(), string(site.GetSnippet())); err != nil { 275 return err 276 } 277 } 278 } 279 280 return nil 281 } 282 283 func showSignature(signature *cpb.MarkedSource) string { 284 if signature == nil { 285 return "(nil)" 286 } 287 ident := markedsource.RenderSimpleIdentifier(signature, markedsource.PlaintextContent, nil) 288 params := markedsource.RenderSimpleParams(signature, markedsource.PlaintextContent, nil) 289 if len(params) == 0 { 290 return ident 291 } 292 return fmt.Sprintf("%s(%s)", ident, strings.Join(params, ",")) 293 }