1const std = @import("std"); 2const Ast = std.zig.Ast; 3const DocumentStore = @import("./DocumentStore.zig"); 4const analysis = @import("./analysis.zig"); 5const types = @import("./types.zig"); 6const offsets = @import("./offsets.zig"); 7const log = std.log.scoped(.references); 8const ast = @import("./ast.zig"); 9 10fn tokenReference(handle: *DocumentStore.Handle, tok: Ast.TokenIndex, encoding: offsets.Encoding, context: anytype, comptime handler: anytype) !void { 11 const loc = offsets.tokenRelativeLocation(handle.tree, 0, handle.tree.tokens.items(.start)[tok], encoding) catch return; 12 try handler(context, types.Location{ 13 .uri = handle.uri(), 14 .range = .{ 15 .start = .{ 16 .line = @intCast(i64, loc.line), 17 .character = @intCast(i64, loc.column), 18 }, 19 .end = .{ 20 .line = @intCast(i64, loc.line), 21 .character = @intCast(i64, loc.column + offsets.tokenLength(handle.tree, tok, encoding)), 22 }, 23 }, 24 }); 25} 26 27pub fn labelReferences(arena: *std.heap.ArenaAllocator, decl: analysis.DeclWithHandle, encoding: offsets.Encoding, include_decl: bool, context: anytype, comptime handler: anytype) !void { 28 _ = arena; 29 30 std.debug.assert(decl.decl.* == .label_decl); 31 const handle = decl.handle; 32 const tree = handle.tree; 33 const token_tags = tree.tokens.items(.tag); 34 35 // Find while / for / block from label -> iterate over children nodes, find break and continues, change their labels if they match. 36 // This case can be implemented just by scanning tokens. 37 const first_tok = tree.firstToken(decl.decl.label_decl); 38 const last_tok = tree.firstToken(decl.decl.label_decl); 39 40 if (include_decl) { 41 // The first token is always going to be the label 42 try tokenReference(handle, first_tok, encoding, context, handler); 43 } 44 45 var curr_tok = first_tok + 1; 46 while (curr_tok < last_tok - 2) : (curr_tok += 1) { 47 const curr_id = token_tags[curr_tok]; 48 if ((curr_id == .keyword_break or curr_id == .keyword_continue) and token_tags[curr_tok + 1] == .colon and 49 token_tags[curr_tok + 2] == .identifier) 50 { 51 if (std.mem.eql(u8, tree.tokenSlice(curr_tok + 2), tree.tokenSlice(first_tok))) { 52 try tokenReference(handle, first_tok, encoding, context, handler); 53 } 54 } 55 } 56} 57 58fn symbolReferencesInternal(arena: *std.heap.ArenaAllocator, store: *DocumentStore, node_handle: analysis.NodeWithHandle, decl: analysis.DeclWithHandle, encoding: offsets.Encoding, context: anytype, comptime handler: anytype) error{OutOfMemory}!void { 59 const node = node_handle.node; 60 const handle = node_handle.handle; 61 const tree = handle.tree; 62 if (node > tree.nodes.len) return; 63 const node_tags = tree.nodes.items(.tag); 64 const datas = tree.nodes.items(.data); 65 const main_tokens = tree.nodes.items(.main_token); 66 const starts = tree.tokens.items(.start); 67 68 switch (node_tags[node]) { 69 .block, .block_semicolon, .block_two, .block_two_semicolon => { 70 const statements: []const Ast.Node.Index = switch (node_tags[node]) { 71 .block, .block_semicolon => tree.extra_data[datas[node].lhs..datas[node].rhs], 72 .block_two, .block_two_semicolon => blk: { 73 const statements = &[_]Ast.Node.Index{ datas[node].lhs, datas[node].rhs }; 74 const len: usize = if (datas[node].lhs == 0) 75 @as(usize, 0) 76 else if (datas[node].rhs == 0) 77 @as(usize, 1) 78 else 79 @as(usize, 2); 80 break :blk statements[0..len]; 81 }, 82 else => unreachable, 83 }; 84 for (statements) |stmt| 85 try symbolReferencesInternal(arena, store, .{ .node = stmt, .handle = handle }, decl, encoding, context, handler); 86 }, 87 .container_decl, 88 .container_decl_trailing, 89 .container_decl_arg, 90 .container_decl_arg_trailing, 91 .container_decl_two, 92 .container_decl_two_trailing, 93 .tagged_union, 94 .tagged_union_trailing, 95 .tagged_union_two, 96 .tagged_union_two_trailing, 97 .tagged_union_enum_tag, 98 .tagged_union_enum_tag_trailing, 99 .root, 100 .error_set_decl, 101 => { 102 var buf: [2]Ast.Node.Index = undefined; 103 for (ast.declMembers(tree, node, &buf)) |member| 104 try symbolReferencesInternal(arena, store, .{ .node = member, .handle = handle }, decl, encoding, context, handler); 105 }, 106 .global_var_decl, 107 .local_var_decl, 108 .simple_var_decl, 109 .aligned_var_decl, 110 => { 111 const var_decl = ast.varDecl(tree, node).?; 112 if (var_decl.ast.type_node != 0) { 113 try symbolReferencesInternal(arena, store, .{ .node = var_decl.ast.type_node, .handle = handle }, decl, encoding, context, handler); 114 } 115 if (var_decl.ast.init_node != 0) { 116 try symbolReferencesInternal(arena, store, .{ .node = var_decl.ast.init_node, .handle = handle }, decl, encoding, context, handler); 117 } 118 }, 119 .@"usingnamespace" => { 120 try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler); 121 }, 122 .container_field, 123 .container_field_align, 124 .container_field_init, 125 => { 126 const field = ast.containerField(tree, node).?; 127 if (field.ast.type_expr != 0) { 128 try symbolReferencesInternal(arena, store, .{ .node = field.ast.type_expr, .handle = handle }, decl, encoding, context, handler); 129 } 130 if (field.ast.value_expr != 0) { 131 try symbolReferencesInternal(arena, store, .{ .node = field.ast.value_expr, .handle = handle }, decl, encoding, context, handler); 132 } 133 }, 134 .identifier => { 135 if (try analysis.lookupSymbolGlobal(store, arena, handle, tree.getNodeSource(node), starts[main_tokens[node]])) |child| { 136 if (std.meta.eql(decl, child)) { 137 try tokenReference(handle, main_tokens[node], encoding, context, handler); 138 } 139 } 140 }, 141 .fn_proto, 142 .fn_proto_multi, 143 .fn_proto_one, 144 .fn_proto_simple, 145 .fn_decl, 146 => { 147 var buf: [1]Ast.Node.Index = undefined; 148 const fn_proto = ast.fnProto(tree, node, &buf).?; 149 var it = fn_proto.iterate(tree); 150 while (it.next()) |param| { 151 if (param.type_expr != 0) 152 try symbolReferencesInternal(arena, store, .{ .node = param.type_expr, .handle = handle }, decl, encoding, context, handler); 153 } 154 155 if (fn_proto.ast.return_type != 0) { 156 try symbolReferencesInternal(arena, store, .{ .node = fn_proto.ast.return_type, .handle = handle }, decl, encoding, context, handler); 157 } 158 if (fn_proto.ast.align_expr != 0) { 159 try symbolReferencesInternal(arena, store, .{ .node = fn_proto.ast.align_expr, .handle = handle }, decl, encoding, context, handler); 160 } 161 if (fn_proto.ast.section_expr != 0) { 162 try symbolReferencesInternal(arena, store, .{ .node = fn_proto.ast.section_expr, .handle = handle }, decl, encoding, context, handler); 163 } 164 if (fn_proto.ast.callconv_expr != 0) { 165 try symbolReferencesInternal(arena, store, .{ .node = fn_proto.ast.callconv_expr, .handle = handle }, decl, encoding, context, handler); 166 } 167 if (node_tags[node] == .fn_decl) { 168 try symbolReferencesInternal(arena, store, .{ .node = datas[node].rhs, .handle = handle }, decl, encoding, context, handler); 169 } 170 }, 171 .anyframe_type => { 172 try symbolReferencesInternal(arena, store, .{ .node = datas[node].rhs, .handle = handle }, decl, encoding, context, handler); 173 }, 174 .@"defer" => { 175 try symbolReferencesInternal(arena, store, .{ .node = datas[node].rhs, .handle = handle }, decl, encoding, context, handler); 176 }, 177 .@"comptime" => { 178 try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler); 179 }, 180 .@"nosuspend" => { 181 try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler); 182 }, 183 .@"switch", 184 .switch_comma, 185 => { 186 // TODO When renaming a union(enum) field, also rename switch items that refer to it. 187 try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler); 188 const extra = tree.extraData(datas[node].rhs, Ast.Node.SubRange); 189 const cases = tree.extra_data[extra.start..extra.end]; 190 for (cases) |case| { 191 try symbolReferencesInternal(arena, store, .{ .node = case, .handle = handle }, decl, encoding, context, handler); 192 } 193 }, 194 .switch_case_one => { 195 const case_one = tree.switchCaseOne(node); 196 if (case_one.ast.target_expr != 0) 197 try symbolReferencesInternal(arena, store, .{ .node = case_one.ast.target_expr, .handle = handle }, decl, encoding, context, handler); 198 for (case_one.ast.values) |val| 199 try symbolReferencesInternal(arena, store, .{ .node = val, .handle = handle }, decl, encoding, context, handler); 200 }, 201 .switch_case => { 202 const case = tree.switchCase(node); 203 if (case.ast.target_expr != 0) 204 try symbolReferencesInternal(arena, store, .{ .node = case.ast.target_expr, .handle = handle }, decl, encoding, context, handler); 205 for (case.ast.values) |val| 206 try symbolReferencesInternal(arena, store, .{ .node = val, .handle = handle }, decl, encoding, context, handler); 207 }, 208 .@"while", 209 .while_simple, 210 .while_cont, 211 .for_simple, 212 .@"for", 213 => { 214 const loop = ast.whileAst(tree, node).?; 215 try symbolReferencesInternal(arena, store, .{ .node = loop.ast.cond_expr, .handle = handle }, decl, encoding, context, handler); 216 if (loop.ast.cont_expr != 0) { 217 try symbolReferencesInternal(arena, store, .{ .node = loop.ast.cont_expr, .handle = handle }, decl, encoding, context, handler); 218 } 219 try symbolReferencesInternal(arena, store, .{ .node = loop.ast.then_expr, .handle = handle }, decl, encoding, context, handler); 220 if (loop.ast.else_expr != 0) { 221 try symbolReferencesInternal(arena, store, .{ .node = loop.ast.else_expr, .handle = handle }, decl, encoding, context, handler); 222 } 223 }, 224 .@"if", 225 .if_simple, 226 => { 227 const if_node = ast.ifFull(tree, node); 228 229 try symbolReferencesInternal(arena, store, .{ .node = if_node.ast.cond_expr, .handle = handle }, decl, encoding, context, handler); 230 try symbolReferencesInternal(arena, store, .{ .node = if_node.ast.then_expr, .handle = handle }, decl, encoding, context, handler); 231 if (if_node.ast.else_expr != 0) { 232 try symbolReferencesInternal(arena, store, .{ .node = if_node.ast.else_expr, .handle = handle }, decl, encoding, context, handler); 233 } 234 }, 235 .array_type, 236 .array_type_sentinel, 237 => { 238 try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler); 239 try symbolReferencesInternal(arena, store, .{ .node = datas[node].rhs, .handle = handle }, decl, encoding, context, handler); 240 }, 241 .ptr_type, 242 .ptr_type_aligned, 243 .ptr_type_bit_range, 244 .ptr_type_sentinel, 245 => { 246 const ptr_type = ast.ptrType(tree, node).?; 247 248 if (ptr_type.ast.align_node != 0) { 249 try symbolReferencesInternal(arena, store, .{ .node = ptr_type.ast.align_node, .handle = handle }, decl, encoding, context, handler); 250 if (node_tags[node] == .ptr_type_bit_range) { 251 try symbolReferencesInternal(arena, store, .{ 252 .node = ptr_type.ast.bit_range_start, 253 .handle = handle, 254 }, decl, encoding, context, handler); 255 try symbolReferencesInternal(arena, store, .{ 256 .node = ptr_type.ast.bit_range_end, 257 .handle = handle, 258 }, decl, encoding, context, handler); 259 } 260 } 261 if (ptr_type.ast.sentinel != 0) { 262 try symbolReferencesInternal(arena, store, .{ .node = ptr_type.ast.sentinel, .handle = handle }, decl, encoding, context, handler); 263 } 264 265 try symbolReferencesInternal(arena, store, .{ .node = ptr_type.ast.child_type, .handle = handle }, decl, encoding, context, handler); 266 }, 267 .address_of, .@"await", .bit_not, .bool_not, .optional_type, .negation, .negation_wrap, .@"resume", .@"try" => { 268 try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler); 269 }, 270 .array_init, 271 .array_init_comma, 272 .array_init_dot, 273 .array_init_dot_comma, 274 .array_init_one, 275 .array_init_one_comma, 276 .array_init_dot_two, 277 .array_init_dot_two_comma, 278 => |n| { 279 var buf: [2]Ast.Node.Index = undefined; 280 const array_init = switch (n) { 281 .array_init, .array_init_comma => tree.arrayInit(node), 282 .array_init_dot, .array_init_dot_comma => tree.arrayInitDot(node), 283 .array_init_one, .array_init_one_comma => tree.arrayInitOne(buf[0..1], node), 284 .array_init_dot_two, .array_init_dot_two_comma => tree.arrayInitDotTwo(&buf, node), 285 else => unreachable, 286 }; 287 if (array_init.ast.type_expr != 0) 288 try symbolReferencesInternal(arena, store, .{ .node = array_init.ast.type_expr, .handle = handle }, decl, encoding, context, handler); 289 for (array_init.ast.elements) |e| 290 try symbolReferencesInternal(arena, store, .{ .node = e, .handle = handle }, decl, encoding, context, handler); 291 }, 292 .struct_init, 293 .struct_init_comma, 294 .struct_init_dot, 295 .struct_init_dot_comma, 296 .struct_init_dot_two, 297 .struct_init_dot_two_comma, 298 .struct_init_one, 299 .struct_init_one_comma, 300 => |n| { 301 var buf: [2]Ast.Node.Index = undefined; 302 const struct_init: Ast.full.StructInit = switch (n) { 303 .struct_init, .struct_init_comma => tree.structInit(node), 304 .struct_init_dot, .struct_init_dot_comma => tree.structInitDot(node), 305 .struct_init_one, .struct_init_one_comma => tree.structInitOne(buf[0..1], node), 306 .struct_init_dot_two, .struct_init_dot_two_comma => tree.structInitDotTwo(&buf, node), 307 else => unreachable, 308 }; 309 if (struct_init.ast.type_expr != 0) 310 try symbolReferencesInternal(arena, store, .{ .node = struct_init.ast.type_expr, .handle = handle }, decl, encoding, context, handler); 311 for (struct_init.ast.fields) |field| 312 try symbolReferencesInternal(arena, store, .{ .node = field, .handle = handle }, decl, encoding, context, handler); 313 }, 314 .call, 315 .call_comma, 316 .call_one, 317 .call_one_comma, 318 .async_call, 319 .async_call_comma, 320 .async_call_one, 321 .async_call_one_comma, 322 => |c| { 323 var buf: [1]Ast.Node.Index = undefined; 324 const call: Ast.full.Call = switch (c) { 325 .call, .call_comma, .async_call, .async_call_comma => tree.callFull(node), 326 .call_one, .call_one_comma, .async_call_one, .async_call_one_comma => tree.callOne(&buf, node), 327 else => unreachable, 328 }; 329 if (call.ast.fn_expr != 0) 330 try symbolReferencesInternal(arena, store, .{ .node = call.ast.fn_expr, .handle = handle }, decl, encoding, context, handler); 331 332 for (call.ast.params) |param| { 333 try symbolReferencesInternal(arena, store, .{ .node = param, .handle = handle }, decl, encoding, context, handler); 334 } 335 }, 336 .slice, 337 .slice_sentinel, 338 .slice_open, 339 => |s| { 340 const slice: Ast.full.Slice = switch (s) { 341 .slice => tree.slice(node), 342 .slice_open => tree.sliceOpen(node), 343 .slice_sentinel => tree.sliceSentinel(node), 344 else => unreachable, 345 }; 346 347 try symbolReferencesInternal(arena, store, .{ .node = slice.ast.sliced, .handle = handle }, decl, encoding, context, handler); 348 try symbolReferencesInternal(arena, store, .{ .node = slice.ast.start, .handle = handle }, decl, encoding, context, handler); 349 if (slice.ast.end != 0) 350 try symbolReferencesInternal(arena, store, .{ .node = slice.ast.end, .handle = handle }, decl, encoding, context, handler); 351 if (slice.ast.sentinel != 0) 352 try symbolReferencesInternal(arena, store, .{ .node = slice.ast.sentinel, .handle = handle }, decl, encoding, context, handler); 353 }, 354 .array_access => { 355 try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler); 356 try symbolReferencesInternal(arena, store, .{ .node = datas[node].rhs, .handle = handle }, decl, encoding, context, handler); 357 }, 358 .deref, 359 .unwrap_optional, 360 => { 361 try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler); 362 }, 363 .grouped_expression => { 364 try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler); 365 }, 366 .@"return", 367 .@"break", 368 .@"continue", 369 => { 370 if (datas[node].lhs != 0) { 371 try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler); 372 } 373 }, 374 .@"suspend" => { 375 if (datas[node].lhs != 0) { 376 try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler); 377 } 378 }, 379 .builtin_call, 380 .builtin_call_comma, 381 .builtin_call_two, 382 .builtin_call_two_comma, 383 => |builtin_tag| { 384 const data = datas[node]; 385 const params = switch (builtin_tag) { 386 .builtin_call, .builtin_call_comma => tree.extra_data[data.lhs..data.rhs], 387 .builtin_call_two, .builtin_call_two_comma => if (data.lhs == 0) 388 &[_]Ast.Node.Index{} 389 else if (data.rhs == 0) 390 &[_]Ast.Node.Index{data.lhs} 391 else 392 &[_]Ast.Node.Index{ data.lhs, data.rhs }, 393 else => unreachable, 394 }; 395 396 for (params) |param| 397 try symbolReferencesInternal(arena, store, .{ .node = param, .handle = handle }, decl, encoding, context, handler); 398 }, 399 .@"asm", 400 .asm_simple, 401 => |a| { 402 const _asm: Ast.full.Asm = if (a == .@"asm") tree.asmFull(node) else tree.asmSimple(node); 403 if (_asm.ast.items.len == 0) 404 try symbolReferencesInternal(arena, store, .{ .node = _asm.ast.template, .handle = handle }, decl, encoding, context, handler); 405 406 for (_asm.inputs) |input| 407 try symbolReferencesInternal(arena, store, .{ .node = input, .handle = handle }, decl, encoding, context, handler); 408 409 for (_asm.outputs) |output| 410 try symbolReferencesInternal(arena, store, .{ .node = output, .handle = handle }, decl, encoding, context, handler); 411 }, 412 .test_decl => { 413 try symbolReferencesInternal(arena, store, .{ .node = datas[node].rhs, .handle = handle }, decl, encoding, context, handler); 414 }, 415 .field_access => { 416 try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler); 417 418 const rhs_str = tree.tokenSlice(datas[node].rhs); 419 var bound_type_params = analysis.BoundTypeParams.init(arena.allocator()); 420 const left_type = try analysis.resolveFieldAccessLhsType( 421 store, 422 arena, 423 (try analysis.resolveTypeOfNodeInternal(store, arena, .{ 424 .node = datas[node].lhs, 425 .handle = handle, 426 }, &bound_type_params)) orelse return, 427 &bound_type_params, 428 ); 429 430 const left_type_node = switch (left_type.type.data) { 431 .other => |n| n, 432 else => return, 433 }; 434 435 if (try analysis.lookupSymbolContainer( 436 store, 437 arena, 438 .{ .node = left_type_node, .handle = left_type.handle }, 439 rhs_str, 440 !left_type.type.is_type_val, 441 )) |child| { 442 if (std.meta.eql(child, decl)) { 443 try tokenReference(handle, datas[node].rhs, encoding, context, handler); 444 } 445 } 446 }, 447 .add, 448 .add_wrap, 449 .array_cat, 450 .array_mult, 451 .assign, 452 .assign_bit_and, 453 .assign_bit_or, 454 .assign_shl, 455 .assign_shr, 456 .assign_bit_xor, 457 .assign_div, 458 .assign_sub, 459 .assign_sub_wrap, 460 .assign_mod, 461 .assign_add, 462 .assign_add_wrap, 463 .assign_mul, 464 .assign_mul_wrap, 465 .bang_equal, 466 .bit_and, 467 .bit_or, 468 .shl, 469 .shr, 470 .bit_xor, 471 .bool_or, 472 .div, 473 .equal_equal, 474 .error_union, 475 .greater_or_equal, 476 .greater_than, 477 .less_or_equal, 478 .less_than, 479 .merge_error_sets, 480 .mod, 481 .mul, 482 .mul_wrap, 483 .switch_range, 484 .sub, 485 .sub_wrap, 486 .@"orelse", 487 => { 488 try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler); 489 try symbolReferencesInternal(arena, store, .{ .node = datas[node].rhs, .handle = handle }, decl, encoding, context, handler); 490 }, 491 else => {}, 492 } 493} 494 495pub fn symbolReferences(arena: *std.heap.ArenaAllocator, store: *DocumentStore, decl_handle: analysis.DeclWithHandle, encoding: offsets.Encoding, include_decl: bool, context: anytype, comptime handler: anytype, skip_std_references: bool) !void { 496 std.debug.assert(decl_handle.decl.* != .label_decl); 497 const curr_handle = decl_handle.handle; 498 if (include_decl) { 499 try tokenReference(curr_handle, decl_handle.nameToken(), encoding, context, handler); 500 } 501 502 switch (decl_handle.decl.*) { 503 .ast_node => { 504 try symbolReferencesInternal(arena, store, .{ .node = 0, .handle = curr_handle }, decl_handle, encoding, context, handler); 505 506 var imports = std.ArrayList(*DocumentStore.Handle).init(arena.allocator()); 507 508 var handle_it = store.handles.iterator(); 509 while (handle_it.next()) |entry| { 510 if (skip_std_references and std.mem.indexOf(u8, entry.key_ptr.*, "std") != null) { 511 if (!include_decl or entry.value_ptr.* != curr_handle) 512 continue; 513 } 514 515 // Check entry's transitive imports 516 try imports.append(entry.value_ptr.*); 517 var i: usize = 0; 518 blk: while (i < imports.items.len) : (i += 1) { 519 const import = imports.items[i]; 520 for (import.imports_used.items) |uri| { 521 const h = store.getHandle(uri) orelse break; 522 523 if (h == curr_handle) { 524 // entry does import curr_handle 525 try symbolReferencesInternal(arena, store, .{ .node = 0, .handle = entry.value_ptr.* }, decl_handle, encoding, context, handler); 526 break :blk; 527 } 528 529 select: { 530 for (imports.items) |item| { 531 if (item == h) { 532 // already checked this import 533 break :select; 534 } 535 } 536 try imports.append(h); 537 } 538 } 539 } 540 try imports.resize(0); 541 } 542 }, 543 .param_decl => |param| { 544 // Rename the param tok. 545 const fn_node: Ast.full.FnProto = loop: for (curr_handle.document_scope.scopes) |scope| { 546 switch (scope.data) { 547 .function => |proto| { 548 var buf: [1]Ast.Node.Index = undefined; 549 const fn_proto = ast.fnProto(curr_handle.tree, proto, &buf).?; 550 var it = fn_proto.iterate(curr_handle.tree); 551 while (it.next()) |candidate| { 552 if (std.meta.eql(candidate, param)) { 553 if (curr_handle.tree.nodes.items(.tag)[proto] == .fn_decl) { 554 try symbolReferencesInternal( 555 arena, 556 store, 557 .{ .node = curr_handle.tree.nodes.items(.data)[proto].rhs, .handle = curr_handle }, 558 decl_handle, 559 encoding, 560 context, 561 handler, 562 ); 563 } 564 break :loop fn_proto; 565 } 566 } 567 }, 568 else => {}, 569 } 570 } else { 571 log.warn("Could not find param decl's function", .{}); 572 return; 573 }; 574 _ = fn_node; 575 }, 576 .pointer_payload, .switch_payload, .array_payload, .array_index => { 577 try symbolReferencesInternal(arena, store, .{ .node = 0, .handle = curr_handle }, decl_handle, encoding, context, handler); 578 }, 579 .label_decl => unreachable, 580 } 581} 582