Added our own ifFull implementation, fixes some crashes
This commit is contained in:
		
							parent
							
								
									9eece0985b
								
							
						
					
					
						commit
						3e300e4d74
					
				@ -4,7 +4,7 @@ const ast = std.zig.ast;
 | 
			
		||||
const types = @import("types.zig");
 | 
			
		||||
const offsets = @import("offsets.zig");
 | 
			
		||||
const log = std.log.scoped(.analysis);
 | 
			
		||||
const lastToken = offsets.lastToken;
 | 
			
		||||
usingnamespace @import("ast.zig");
 | 
			
		||||
 | 
			
		||||
/// Get a declaration's doc comment token index
 | 
			
		||||
pub fn getDocCommentTokenIndex(tree: ast.Tree, node: ast.Node.Index) ?ast.TokenIndex {
 | 
			
		||||
@ -2819,7 +2819,7 @@ fn makeScopeInternal(
 | 
			
		||||
        .if_simple,
 | 
			
		||||
        => {
 | 
			
		||||
            const if_node: ast.full.If = if (node_tag == .@"if")
 | 
			
		||||
                tree.ifFull(node_idx)
 | 
			
		||||
                ifFull(tree, node_idx)
 | 
			
		||||
            else
 | 
			
		||||
                tree.ifSimple(node_idx);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										560
									
								
								src/ast.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										560
									
								
								src/ast.zig
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,560 @@
 | 
			
		||||
//! Collection of functions from std.zig.ast that we need
 | 
			
		||||
//! and may hit undefined in the standard library implementation
 | 
			
		||||
//! when there are parser errors.
 | 
			
		||||
 | 
			
		||||
const std = @import("std");
 | 
			
		||||
const ast = std.zig.ast;
 | 
			
		||||
const Tree = ast.Tree;
 | 
			
		||||
const Node = ast.Node;
 | 
			
		||||
const full = ast.full;
 | 
			
		||||
const assert = std.debug.assert;
 | 
			
		||||
 | 
			
		||||
fn fullIf(tree: Tree, info: full.If.Ast) full.If {
 | 
			
		||||
    const token_tags = tree.tokens.items(.tag);
 | 
			
		||||
    var result: full.If = .{
 | 
			
		||||
        .ast = info,
 | 
			
		||||
        .payload_token = null,
 | 
			
		||||
        .error_token = null,
 | 
			
		||||
        .else_token = undefined,
 | 
			
		||||
    };
 | 
			
		||||
    // if (cond_expr) |x|
 | 
			
		||||
    //              ^ ^
 | 
			
		||||
    const payload_pipe = lastToken(tree, info.cond_expr) + 2;
 | 
			
		||||
    if (token_tags[payload_pipe] == .pipe) {
 | 
			
		||||
        result.payload_token = payload_pipe + 1;
 | 
			
		||||
    }
 | 
			
		||||
    if (info.else_expr != 0) {
 | 
			
		||||
        // then_expr else |x|
 | 
			
		||||
        //           ^    ^
 | 
			
		||||
        result.else_token = lastToken(tree, info.then_expr) + 1;
 | 
			
		||||
        if (token_tags[result.else_token + 1] == .pipe) {
 | 
			
		||||
            result.error_token = result.else_token + 2;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn ifFull(tree: Tree, node: Node.Index) full.If {
 | 
			
		||||
    assert(tree.nodes.items(.tag)[node] == .@"if");
 | 
			
		||||
    const data = tree.nodes.items(.data)[node];
 | 
			
		||||
    const extra = tree.extraData(data.rhs, Node.If);
 | 
			
		||||
    return fullIf(tree, .{
 | 
			
		||||
        .cond_expr = data.lhs,
 | 
			
		||||
        .then_expr = extra.then_expr,
 | 
			
		||||
        .else_expr = extra.else_expr,
 | 
			
		||||
        .if_token = tree.nodes.items(.main_token)[node],
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn lastToken(tree: ast.Tree, node: ast.Node.Index) ast.TokenIndex {
 | 
			
		||||
    const TokenIndex = ast.TokenIndex;
 | 
			
		||||
    const tags = tree.nodes.items(.tag);
 | 
			
		||||
    const datas = tree.nodes.items(.data);
 | 
			
		||||
    const main_tokens = tree.nodes.items(.main_token);
 | 
			
		||||
    const token_starts = tree.tokens.items(.start);
 | 
			
		||||
    const token_tags = tree.tokens.items(.tag);
 | 
			
		||||
    var n = node;
 | 
			
		||||
    var end_offset: TokenIndex = 0;
 | 
			
		||||
    while (true) switch (tags[n]) {
 | 
			
		||||
        .root => return @intCast(TokenIndex, tree.tokens.len - 1),
 | 
			
		||||
 | 
			
		||||
        .@"usingnamespace",
 | 
			
		||||
        .bool_not,
 | 
			
		||||
        .negation,
 | 
			
		||||
        .bit_not,
 | 
			
		||||
        .negation_wrap,
 | 
			
		||||
        .address_of,
 | 
			
		||||
        .@"try",
 | 
			
		||||
        .@"await",
 | 
			
		||||
        .optional_type,
 | 
			
		||||
        .@"resume",
 | 
			
		||||
        .@"nosuspend",
 | 
			
		||||
        .@"comptime",
 | 
			
		||||
        => n = datas[n].lhs,
 | 
			
		||||
 | 
			
		||||
        .test_decl,
 | 
			
		||||
        .@"errdefer",
 | 
			
		||||
        .@"defer",
 | 
			
		||||
        .@"catch",
 | 
			
		||||
        .equal_equal,
 | 
			
		||||
        .bang_equal,
 | 
			
		||||
        .less_than,
 | 
			
		||||
        .greater_than,
 | 
			
		||||
        .less_or_equal,
 | 
			
		||||
        .greater_or_equal,
 | 
			
		||||
        .assign_mul,
 | 
			
		||||
        .assign_div,
 | 
			
		||||
        .assign_mod,
 | 
			
		||||
        .assign_add,
 | 
			
		||||
        .assign_sub,
 | 
			
		||||
        .assign_bit_shift_left,
 | 
			
		||||
        .assign_bit_shift_right,
 | 
			
		||||
        .assign_bit_and,
 | 
			
		||||
        .assign_bit_xor,
 | 
			
		||||
        .assign_bit_or,
 | 
			
		||||
        .assign_mul_wrap,
 | 
			
		||||
        .assign_add_wrap,
 | 
			
		||||
        .assign_sub_wrap,
 | 
			
		||||
        .assign,
 | 
			
		||||
        .merge_error_sets,
 | 
			
		||||
        .mul,
 | 
			
		||||
        .div,
 | 
			
		||||
        .mod,
 | 
			
		||||
        .array_mult,
 | 
			
		||||
        .mul_wrap,
 | 
			
		||||
        .add,
 | 
			
		||||
        .sub,
 | 
			
		||||
        .array_cat,
 | 
			
		||||
        .add_wrap,
 | 
			
		||||
        .sub_wrap,
 | 
			
		||||
        .bit_shift_left,
 | 
			
		||||
        .bit_shift_right,
 | 
			
		||||
        .bit_and,
 | 
			
		||||
        .bit_xor,
 | 
			
		||||
        .bit_or,
 | 
			
		||||
        .@"orelse",
 | 
			
		||||
        .bool_and,
 | 
			
		||||
        .bool_or,
 | 
			
		||||
        .anyframe_type,
 | 
			
		||||
        .error_union,
 | 
			
		||||
        .if_simple,
 | 
			
		||||
        .while_simple,
 | 
			
		||||
        .for_simple,
 | 
			
		||||
        .fn_proto_simple,
 | 
			
		||||
        .fn_proto_multi,
 | 
			
		||||
        .ptr_type_aligned,
 | 
			
		||||
        .ptr_type_sentinel,
 | 
			
		||||
        .ptr_type,
 | 
			
		||||
        .ptr_type_bit_range,
 | 
			
		||||
        .array_type,
 | 
			
		||||
        .switch_case_one,
 | 
			
		||||
        .switch_case,
 | 
			
		||||
        .switch_range,
 | 
			
		||||
        => n = datas[n].rhs,
 | 
			
		||||
 | 
			
		||||
        .field_access,
 | 
			
		||||
        .unwrap_optional,
 | 
			
		||||
        .grouped_expression,
 | 
			
		||||
        .multiline_string_literal,
 | 
			
		||||
        .error_set_decl,
 | 
			
		||||
        .asm_simple,
 | 
			
		||||
        .asm_output,
 | 
			
		||||
        .asm_input,
 | 
			
		||||
        .error_value,
 | 
			
		||||
        => return datas[n].rhs + end_offset,
 | 
			
		||||
 | 
			
		||||
        .@"anytype",
 | 
			
		||||
        .anyframe_literal,
 | 
			
		||||
        .char_literal,
 | 
			
		||||
        .integer_literal,
 | 
			
		||||
        .float_literal,
 | 
			
		||||
        .false_literal,
 | 
			
		||||
        .true_literal,
 | 
			
		||||
        .null_literal,
 | 
			
		||||
        .undefined_literal,
 | 
			
		||||
        .unreachable_literal,
 | 
			
		||||
        .identifier,
 | 
			
		||||
        .deref,
 | 
			
		||||
        .enum_literal,
 | 
			
		||||
        .string_literal,
 | 
			
		||||
        => return main_tokens[n] + end_offset,
 | 
			
		||||
 | 
			
		||||
        .@"return" => if (datas[n].lhs != 0) {
 | 
			
		||||
            n = datas[n].lhs;
 | 
			
		||||
        } else {
 | 
			
		||||
            return main_tokens[n] + end_offset;
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        .call, .async_call => {
 | 
			
		||||
            end_offset += 1; // for the rparen
 | 
			
		||||
            const params = tree.extraData(datas[n].rhs, Node.SubRange);
 | 
			
		||||
            if (params.end - params.start == 0) {
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
            n = tree.extra_data[params.end - 1]; // last parameter
 | 
			
		||||
        },
 | 
			
		||||
        .tagged_union_enum_tag => {
 | 
			
		||||
            const members = tree.extraData(datas[n].rhs, Node.SubRange);
 | 
			
		||||
            if (members.end - members.start == 0) {
 | 
			
		||||
                end_offset += 4; // for the rparen + rparen + lbrace + rbrace
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                end_offset += 1; // for the rbrace
 | 
			
		||||
                n = tree.extra_data[members.end - 1]; // last parameter
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .call_comma,
 | 
			
		||||
        .async_call_comma,
 | 
			
		||||
        .tagged_union_enum_tag_trailing,
 | 
			
		||||
        => {
 | 
			
		||||
            end_offset += 2; // for the comma/semicolon + rparen/rbrace
 | 
			
		||||
            const params = tree.extraData(datas[n].rhs, Node.SubRange);
 | 
			
		||||
            std.debug.assert(params.end > params.start);
 | 
			
		||||
            n = tree.extra_data[params.end - 1]; // last parameter
 | 
			
		||||
        },
 | 
			
		||||
        .@"switch" => {
 | 
			
		||||
            const cases = tree.extraData(datas[n].rhs, Node.SubRange);
 | 
			
		||||
            if (cases.end - cases.start == 0) {
 | 
			
		||||
                end_offset += 3; // rparen, lbrace, rbrace
 | 
			
		||||
                n = datas[n].lhs; // condition expression
 | 
			
		||||
            } else {
 | 
			
		||||
                end_offset += 1; // for the rbrace
 | 
			
		||||
                n = tree.extra_data[cases.end - 1]; // last case
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .container_decl_arg => {
 | 
			
		||||
            const members = tree.extraData(datas[n].rhs, Node.SubRange);
 | 
			
		||||
            if (members.end - members.start == 0) {
 | 
			
		||||
                end_offset += 3; // for the rparen + lbrace + rbrace
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                end_offset += 1; // for the rbrace
 | 
			
		||||
                n = tree.extra_data[members.end - 1]; // last parameter
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .@"asm" => {
 | 
			
		||||
            const extra = tree.extraData(datas[n].rhs, Node.Asm);
 | 
			
		||||
            return extra.rparen + end_offset;
 | 
			
		||||
        },
 | 
			
		||||
        .array_init,
 | 
			
		||||
        .struct_init,
 | 
			
		||||
        => {
 | 
			
		||||
            const elements = tree.extraData(datas[n].rhs, Node.SubRange);
 | 
			
		||||
            std.debug.assert(elements.end - elements.start > 0);
 | 
			
		||||
            end_offset += 1; // for the rbrace
 | 
			
		||||
            n = tree.extra_data[elements.end - 1]; // last element
 | 
			
		||||
        },
 | 
			
		||||
        .array_init_comma,
 | 
			
		||||
        .struct_init_comma,
 | 
			
		||||
        .container_decl_arg_trailing,
 | 
			
		||||
        .switch_comma,
 | 
			
		||||
        => {
 | 
			
		||||
            const members = tree.extraData(datas[n].rhs, Node.SubRange);
 | 
			
		||||
            std.debug.assert(members.end - members.start > 0);
 | 
			
		||||
            end_offset += 2; // for the comma + rbrace
 | 
			
		||||
            n = tree.extra_data[members.end - 1]; // last parameter
 | 
			
		||||
        },
 | 
			
		||||
        .array_init_dot,
 | 
			
		||||
        .struct_init_dot,
 | 
			
		||||
        .block,
 | 
			
		||||
        .container_decl,
 | 
			
		||||
        .tagged_union,
 | 
			
		||||
        .builtin_call,
 | 
			
		||||
        => {
 | 
			
		||||
            std.debug.assert(datas[n].rhs - datas[n].lhs > 0);
 | 
			
		||||
            end_offset += 1; // for the rbrace
 | 
			
		||||
            n = tree.extra_data[datas[n].rhs - 1]; // last statement
 | 
			
		||||
        },
 | 
			
		||||
        .array_init_dot_comma,
 | 
			
		||||
        .struct_init_dot_comma,
 | 
			
		||||
        .block_semicolon,
 | 
			
		||||
        .container_decl_trailing,
 | 
			
		||||
        .tagged_union_trailing,
 | 
			
		||||
        .builtin_call_comma,
 | 
			
		||||
        => {
 | 
			
		||||
            std.debug.assert(datas[n].rhs - datas[n].lhs > 0);
 | 
			
		||||
            end_offset += 2; // for the comma/semicolon + rbrace/rparen
 | 
			
		||||
            n = tree.extra_data[datas[n].rhs - 1]; // last member
 | 
			
		||||
        },
 | 
			
		||||
        .call_one,
 | 
			
		||||
        .async_call_one,
 | 
			
		||||
        .array_access,
 | 
			
		||||
        => {
 | 
			
		||||
            end_offset += 1; // for the rparen/rbracket
 | 
			
		||||
            if (datas[n].rhs == 0) {
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
            n = datas[n].rhs;
 | 
			
		||||
        },
 | 
			
		||||
        .array_init_dot_two,
 | 
			
		||||
        .block_two,
 | 
			
		||||
        .builtin_call_two,
 | 
			
		||||
        .struct_init_dot_two,
 | 
			
		||||
        .container_decl_two,
 | 
			
		||||
        .tagged_union_two,
 | 
			
		||||
        => {
 | 
			
		||||
            if (datas[n].rhs != 0) {
 | 
			
		||||
                end_offset += 1; // for the rparen/rbrace
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            } else if (datas[n].lhs != 0) {
 | 
			
		||||
                end_offset += 1; // for the rparen/rbrace
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                switch (tags[n]) {
 | 
			
		||||
                    .array_init_dot_two,
 | 
			
		||||
                    .block_two,
 | 
			
		||||
                    .struct_init_dot_two,
 | 
			
		||||
                    => end_offset += 1, // rbrace
 | 
			
		||||
                    .builtin_call_two => end_offset += 2, // lparen/lbrace + rparen/rbrace
 | 
			
		||||
                    .container_decl_two => {
 | 
			
		||||
                        var i: u32 = 2; // lbrace + rbrace
 | 
			
		||||
                        while (token_tags[main_tokens[n] + i] == .container_doc_comment) i += 1;
 | 
			
		||||
                        end_offset += i;
 | 
			
		||||
                    },
 | 
			
		||||
                    .tagged_union_two => {
 | 
			
		||||
                        var i: u32 = 5; // (enum) {}
 | 
			
		||||
                        while (token_tags[main_tokens[n] + i] == .container_doc_comment) i += 1;
 | 
			
		||||
                        end_offset += i;
 | 
			
		||||
                    },
 | 
			
		||||
                    else => unreachable,
 | 
			
		||||
                }
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .array_init_dot_two_comma,
 | 
			
		||||
        .builtin_call_two_comma,
 | 
			
		||||
        .block_two_semicolon,
 | 
			
		||||
        .struct_init_dot_two_comma,
 | 
			
		||||
        .container_decl_two_trailing,
 | 
			
		||||
        .tagged_union_two_trailing,
 | 
			
		||||
        => {
 | 
			
		||||
            end_offset += 2; // for the comma/semicolon + rbrace/rparen
 | 
			
		||||
            if (datas[n].rhs != 0) {
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            } else if (datas[n].lhs != 0) {
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                return main_tokens[n] + end_offset; // returns { }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .simple_var_decl => {
 | 
			
		||||
            if (datas[n].rhs != 0) {
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            } else if (datas[n].lhs != 0) {
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                end_offset += 1; // from mut token to name
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .aligned_var_decl => {
 | 
			
		||||
            if (datas[n].rhs != 0) {
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            } else if (datas[n].lhs != 0) {
 | 
			
		||||
                end_offset += 1; // for the rparen
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                end_offset += 1; // from mut token to name
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .global_var_decl => {
 | 
			
		||||
            if (datas[n].rhs != 0) {
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                const extra = tree.extraData(datas[n].lhs, Node.GlobalVarDecl);
 | 
			
		||||
                if (extra.section_node != 0) {
 | 
			
		||||
                    end_offset += 1; // for the rparen
 | 
			
		||||
                    n = extra.section_node;
 | 
			
		||||
                } else if (extra.align_node != 0) {
 | 
			
		||||
                    end_offset += 1; // for the rparen
 | 
			
		||||
                    n = extra.align_node;
 | 
			
		||||
                } else if (extra.type_node != 0) {
 | 
			
		||||
                    n = extra.type_node;
 | 
			
		||||
                } else {
 | 
			
		||||
                    end_offset += 1; // from mut token to name
 | 
			
		||||
                    return main_tokens[n] + end_offset;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .local_var_decl => {
 | 
			
		||||
            if (datas[n].rhs != 0) {
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                const extra = tree.extraData(datas[n].lhs, Node.LocalVarDecl);
 | 
			
		||||
                if (extra.align_node != 0) {
 | 
			
		||||
                    end_offset += 1; // for the rparen
 | 
			
		||||
                    n = extra.align_node;
 | 
			
		||||
                } else if (extra.type_node != 0) {
 | 
			
		||||
                    n = extra.type_node;
 | 
			
		||||
                } else {
 | 
			
		||||
                    end_offset += 1; // from mut token to name
 | 
			
		||||
                    return main_tokens[n] + end_offset;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .container_field_init => {
 | 
			
		||||
            if (datas[n].rhs != 0) {
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            } else if (datas[n].lhs != 0) {
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .container_field_align => {
 | 
			
		||||
            if (datas[n].rhs != 0) {
 | 
			
		||||
                end_offset += 1; // for the rparen
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            } else if (datas[n].lhs != 0) {
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .container_field => {
 | 
			
		||||
            const extra = tree.extraData(datas[n].rhs, Node.ContainerField);
 | 
			
		||||
            if (extra.value_expr != 0) {
 | 
			
		||||
                n = extra.value_expr;
 | 
			
		||||
            } else if (extra.align_expr != 0) {
 | 
			
		||||
                end_offset += 1; // for the rparen
 | 
			
		||||
                n = extra.align_expr;
 | 
			
		||||
            } else if (datas[n].lhs != 0) {
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        .array_init_one,
 | 
			
		||||
        .struct_init_one,
 | 
			
		||||
        => {
 | 
			
		||||
            end_offset += 1; // rbrace
 | 
			
		||||
            if (datas[n].rhs == 0) {
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            } else {
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .slice_open,
 | 
			
		||||
        .call_one_comma,
 | 
			
		||||
        .async_call_one_comma,
 | 
			
		||||
        .array_init_one_comma,
 | 
			
		||||
        .struct_init_one_comma,
 | 
			
		||||
        => {
 | 
			
		||||
            end_offset += 2; // ellipsis2 + rbracket, or comma + rparen
 | 
			
		||||
            n = datas[n].rhs;
 | 
			
		||||
            std.debug.assert(n != 0);
 | 
			
		||||
        },
 | 
			
		||||
        .slice => {
 | 
			
		||||
            const extra = tree.extraData(datas[n].rhs, Node.Slice);
 | 
			
		||||
            std.debug.assert(extra.end != 0); // should have used slice_open
 | 
			
		||||
            end_offset += 1; // rbracket
 | 
			
		||||
            n = extra.end;
 | 
			
		||||
        },
 | 
			
		||||
        .slice_sentinel => {
 | 
			
		||||
            const extra = tree.extraData(datas[n].rhs, Node.SliceSentinel);
 | 
			
		||||
            std.debug.assert(extra.sentinel != 0); // should have used slice
 | 
			
		||||
            end_offset += 1; // rbracket
 | 
			
		||||
            n = extra.sentinel;
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        .@"continue" => {
 | 
			
		||||
            if (datas[n].lhs != 0) {
 | 
			
		||||
                return datas[n].lhs + end_offset;
 | 
			
		||||
            } else {
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .@"break" => {
 | 
			
		||||
            if (datas[n].rhs != 0) {
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            } else if (datas[n].lhs != 0) {
 | 
			
		||||
                return datas[n].lhs + end_offset;
 | 
			
		||||
            } else {
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .fn_decl => {
 | 
			
		||||
            if (datas[n].rhs != 0) {
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .fn_proto_one => {
 | 
			
		||||
            const extra = tree.extraData(datas[n].lhs, Node.FnProtoOne);
 | 
			
		||||
            // linksection, callconv, align can appear in any order, so we
 | 
			
		||||
            // find the last one here.
 | 
			
		||||
            var max_node: Node.Index = datas[n].rhs;
 | 
			
		||||
            var max_start = token_starts[main_tokens[max_node]];
 | 
			
		||||
            var max_offset: TokenIndex = 0;
 | 
			
		||||
            if (extra.align_expr != 0) {
 | 
			
		||||
                const start = token_starts[main_tokens[extra.align_expr]];
 | 
			
		||||
                if (start > max_start) {
 | 
			
		||||
                    max_node = extra.align_expr;
 | 
			
		||||
                    max_start = start;
 | 
			
		||||
                    max_offset = 1; // for the rparen
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (extra.section_expr != 0) {
 | 
			
		||||
                const start = token_starts[main_tokens[extra.section_expr]];
 | 
			
		||||
                if (start > max_start) {
 | 
			
		||||
                    max_node = extra.section_expr;
 | 
			
		||||
                    max_start = start;
 | 
			
		||||
                    max_offset = 1; // for the rparen
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (extra.callconv_expr != 0) {
 | 
			
		||||
                const start = token_starts[main_tokens[extra.callconv_expr]];
 | 
			
		||||
                if (start > max_start) {
 | 
			
		||||
                    max_node = extra.callconv_expr;
 | 
			
		||||
                    max_start = start;
 | 
			
		||||
                    max_offset = 1; // for the rparen
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            n = max_node;
 | 
			
		||||
            end_offset += max_offset;
 | 
			
		||||
        },
 | 
			
		||||
        .fn_proto => {
 | 
			
		||||
            const extra = tree.extraData(datas[n].lhs, Node.FnProto);
 | 
			
		||||
            // linksection, callconv, align can appear in any order, so we
 | 
			
		||||
            // find the last one here.
 | 
			
		||||
            var max_node: Node.Index = datas[n].rhs;
 | 
			
		||||
            var max_start = token_starts[main_tokens[max_node]];
 | 
			
		||||
            var max_offset: TokenIndex = 0;
 | 
			
		||||
            if (extra.align_expr != 0) {
 | 
			
		||||
                const start = token_starts[main_tokens[extra.align_expr]];
 | 
			
		||||
                if (start > max_start) {
 | 
			
		||||
                    max_node = extra.align_expr;
 | 
			
		||||
                    max_start = start;
 | 
			
		||||
                    max_offset = 1; // for the rparen
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (extra.section_expr != 0) {
 | 
			
		||||
                const start = token_starts[main_tokens[extra.section_expr]];
 | 
			
		||||
                if (start > max_start) {
 | 
			
		||||
                    max_node = extra.section_expr;
 | 
			
		||||
                    max_start = start;
 | 
			
		||||
                    max_offset = 1; // for the rparen
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (extra.callconv_expr != 0) {
 | 
			
		||||
                const start = token_starts[main_tokens[extra.callconv_expr]];
 | 
			
		||||
                if (start > max_start) {
 | 
			
		||||
                    max_node = extra.callconv_expr;
 | 
			
		||||
                    max_start = start;
 | 
			
		||||
                    max_offset = 1; // for the rparen
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            n = max_node;
 | 
			
		||||
            end_offset += max_offset;
 | 
			
		||||
        },
 | 
			
		||||
        .while_cont => {
 | 
			
		||||
            const extra = tree.extraData(datas[n].rhs, Node.WhileCont);
 | 
			
		||||
            std.debug.assert(extra.then_expr != 0);
 | 
			
		||||
            n = extra.then_expr;
 | 
			
		||||
        },
 | 
			
		||||
        .@"while" => {
 | 
			
		||||
            const extra = tree.extraData(datas[n].rhs, Node.While);
 | 
			
		||||
            std.debug.assert(extra.else_expr != 0);
 | 
			
		||||
            n = extra.else_expr;
 | 
			
		||||
        },
 | 
			
		||||
        .@"if", .@"for" => {
 | 
			
		||||
            const extra = tree.extraData(datas[n].rhs, Node.If);
 | 
			
		||||
            std.debug.assert(extra.else_expr != 0);
 | 
			
		||||
            n = extra.else_expr;
 | 
			
		||||
        },
 | 
			
		||||
        .@"suspend" => {
 | 
			
		||||
            if (datas[n].lhs != 0) {
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .array_type_sentinel => {
 | 
			
		||||
            const extra = tree.extraData(datas[n].rhs, Node.ArrayTypeSentinel);
 | 
			
		||||
            n = extra.elem_type;
 | 
			
		||||
        },
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										517
									
								
								src/offsets.zig
									
									
									
									
									
								
							
							
						
						
									
										517
									
								
								src/offsets.zig
									
									
									
									
									
								
							@ -218,520 +218,3 @@ pub fn documentRange(doc: types.TextDocument, encoding: Encoding) !types.Range {
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Updated version from std that allows for failures
 | 
			
		||||
// by removing the unreachables and returning up to that point
 | 
			
		||||
// so that we can always provide information while the user is still typing
 | 
			
		||||
pub fn lastToken(tree: ast.Tree, node: ast.Node.Index) ast.TokenIndex {
 | 
			
		||||
    const Node = ast.Node;
 | 
			
		||||
    const TokenIndex = ast.TokenIndex;
 | 
			
		||||
    const tags = tree.nodes.items(.tag);
 | 
			
		||||
    const datas = tree.nodes.items(.data);
 | 
			
		||||
    const main_tokens = tree.nodes.items(.main_token);
 | 
			
		||||
    const token_starts = tree.tokens.items(.start);
 | 
			
		||||
    const token_tags = tree.tokens.items(.tag);
 | 
			
		||||
    var n = node;
 | 
			
		||||
    var end_offset: TokenIndex = 0;
 | 
			
		||||
    while (true) switch (tags[n]) {
 | 
			
		||||
        .root => return @intCast(TokenIndex, tree.tokens.len - 1),
 | 
			
		||||
 | 
			
		||||
        .@"usingnamespace",
 | 
			
		||||
        .bool_not,
 | 
			
		||||
        .negation,
 | 
			
		||||
        .bit_not,
 | 
			
		||||
        .negation_wrap,
 | 
			
		||||
        .address_of,
 | 
			
		||||
        .@"try",
 | 
			
		||||
        .@"await",
 | 
			
		||||
        .optional_type,
 | 
			
		||||
        .@"resume",
 | 
			
		||||
        .@"nosuspend",
 | 
			
		||||
        .@"comptime",
 | 
			
		||||
        => n = datas[n].lhs,
 | 
			
		||||
 | 
			
		||||
        .test_decl,
 | 
			
		||||
        .@"errdefer",
 | 
			
		||||
        .@"defer",
 | 
			
		||||
        .@"catch",
 | 
			
		||||
        .equal_equal,
 | 
			
		||||
        .bang_equal,
 | 
			
		||||
        .less_than,
 | 
			
		||||
        .greater_than,
 | 
			
		||||
        .less_or_equal,
 | 
			
		||||
        .greater_or_equal,
 | 
			
		||||
        .assign_mul,
 | 
			
		||||
        .assign_div,
 | 
			
		||||
        .assign_mod,
 | 
			
		||||
        .assign_add,
 | 
			
		||||
        .assign_sub,
 | 
			
		||||
        .assign_bit_shift_left,
 | 
			
		||||
        .assign_bit_shift_right,
 | 
			
		||||
        .assign_bit_and,
 | 
			
		||||
        .assign_bit_xor,
 | 
			
		||||
        .assign_bit_or,
 | 
			
		||||
        .assign_mul_wrap,
 | 
			
		||||
        .assign_add_wrap,
 | 
			
		||||
        .assign_sub_wrap,
 | 
			
		||||
        .assign,
 | 
			
		||||
        .merge_error_sets,
 | 
			
		||||
        .mul,
 | 
			
		||||
        .div,
 | 
			
		||||
        .mod,
 | 
			
		||||
        .array_mult,
 | 
			
		||||
        .mul_wrap,
 | 
			
		||||
        .add,
 | 
			
		||||
        .sub,
 | 
			
		||||
        .array_cat,
 | 
			
		||||
        .add_wrap,
 | 
			
		||||
        .sub_wrap,
 | 
			
		||||
        .bit_shift_left,
 | 
			
		||||
        .bit_shift_right,
 | 
			
		||||
        .bit_and,
 | 
			
		||||
        .bit_xor,
 | 
			
		||||
        .bit_or,
 | 
			
		||||
        .@"orelse",
 | 
			
		||||
        .bool_and,
 | 
			
		||||
        .bool_or,
 | 
			
		||||
        .anyframe_type,
 | 
			
		||||
        .error_union,
 | 
			
		||||
        .if_simple,
 | 
			
		||||
        .while_simple,
 | 
			
		||||
        .for_simple,
 | 
			
		||||
        .fn_proto_simple,
 | 
			
		||||
        .fn_proto_multi,
 | 
			
		||||
        .ptr_type_aligned,
 | 
			
		||||
        .ptr_type_sentinel,
 | 
			
		||||
        .ptr_type,
 | 
			
		||||
        .ptr_type_bit_range,
 | 
			
		||||
        .array_type,
 | 
			
		||||
        .switch_case_one,
 | 
			
		||||
        .switch_case,
 | 
			
		||||
        .switch_range,
 | 
			
		||||
        => n = datas[n].rhs,
 | 
			
		||||
 | 
			
		||||
        .field_access,
 | 
			
		||||
        .unwrap_optional,
 | 
			
		||||
        .grouped_expression,
 | 
			
		||||
        .multiline_string_literal,
 | 
			
		||||
        .error_set_decl,
 | 
			
		||||
        .asm_simple,
 | 
			
		||||
        .asm_output,
 | 
			
		||||
        .asm_input,
 | 
			
		||||
        .error_value,
 | 
			
		||||
        => return datas[n].rhs + end_offset,
 | 
			
		||||
 | 
			
		||||
        .@"anytype",
 | 
			
		||||
        .anyframe_literal,
 | 
			
		||||
        .char_literal,
 | 
			
		||||
        .integer_literal,
 | 
			
		||||
        .float_literal,
 | 
			
		||||
        .false_literal,
 | 
			
		||||
        .true_literal,
 | 
			
		||||
        .null_literal,
 | 
			
		||||
        .undefined_literal,
 | 
			
		||||
        .unreachable_literal,
 | 
			
		||||
        .identifier,
 | 
			
		||||
        .deref,
 | 
			
		||||
        .enum_literal,
 | 
			
		||||
        .string_literal,
 | 
			
		||||
        => return main_tokens[n] + end_offset,
 | 
			
		||||
 | 
			
		||||
        .@"return" => if (datas[n].lhs != 0) {
 | 
			
		||||
            n = datas[n].lhs;
 | 
			
		||||
        } else {
 | 
			
		||||
            return main_tokens[n] + end_offset;
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        .call, .async_call => {
 | 
			
		||||
            end_offset += 1; // for the rparen
 | 
			
		||||
            const params = tree.extraData(datas[n].rhs, Node.SubRange);
 | 
			
		||||
            if (params.end - params.start == 0) {
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
            n = tree.extra_data[params.end - 1]; // last parameter
 | 
			
		||||
        },
 | 
			
		||||
        .tagged_union_enum_tag => {
 | 
			
		||||
            const members = tree.extraData(datas[n].rhs, Node.SubRange);
 | 
			
		||||
            if (members.end - members.start == 0) {
 | 
			
		||||
                end_offset += 4; // for the rparen + rparen + lbrace + rbrace
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                end_offset += 1; // for the rbrace
 | 
			
		||||
                n = tree.extra_data[members.end - 1]; // last parameter
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .call_comma,
 | 
			
		||||
        .async_call_comma,
 | 
			
		||||
        .tagged_union_enum_tag_trailing,
 | 
			
		||||
        => {
 | 
			
		||||
            end_offset += 2; // for the comma/semicolon + rparen/rbrace
 | 
			
		||||
            const params = tree.extraData(datas[n].rhs, Node.SubRange);
 | 
			
		||||
            std.debug.assert(params.end > params.start);
 | 
			
		||||
            n = tree.extra_data[params.end - 1]; // last parameter
 | 
			
		||||
        },
 | 
			
		||||
        .@"switch" => {
 | 
			
		||||
            const cases = tree.extraData(datas[n].rhs, Node.SubRange);
 | 
			
		||||
            if (cases.end - cases.start == 0) {
 | 
			
		||||
                end_offset += 3; // rparen, lbrace, rbrace
 | 
			
		||||
                n = datas[n].lhs; // condition expression
 | 
			
		||||
            } else {
 | 
			
		||||
                end_offset += 1; // for the rbrace
 | 
			
		||||
                n = tree.extra_data[cases.end - 1]; // last case
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .container_decl_arg => {
 | 
			
		||||
            const members = tree.extraData(datas[n].rhs, Node.SubRange);
 | 
			
		||||
            if (members.end - members.start == 0) {
 | 
			
		||||
                end_offset += 3; // for the rparen + lbrace + rbrace
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                end_offset += 1; // for the rbrace
 | 
			
		||||
                n = tree.extra_data[members.end - 1]; // last parameter
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .@"asm" => {
 | 
			
		||||
            const extra = tree.extraData(datas[n].rhs, Node.Asm);
 | 
			
		||||
            return extra.rparen + end_offset;
 | 
			
		||||
        },
 | 
			
		||||
        .array_init,
 | 
			
		||||
        .struct_init,
 | 
			
		||||
        => {
 | 
			
		||||
            const elements = tree.extraData(datas[n].rhs, Node.SubRange);
 | 
			
		||||
            std.debug.assert(elements.end - elements.start > 0);
 | 
			
		||||
            end_offset += 1; // for the rbrace
 | 
			
		||||
            n = tree.extra_data[elements.end - 1]; // last element
 | 
			
		||||
        },
 | 
			
		||||
        .array_init_comma,
 | 
			
		||||
        .struct_init_comma,
 | 
			
		||||
        .container_decl_arg_trailing,
 | 
			
		||||
        .switch_comma,
 | 
			
		||||
        => {
 | 
			
		||||
            const members = tree.extraData(datas[n].rhs, Node.SubRange);
 | 
			
		||||
            std.debug.assert(members.end - members.start > 0);
 | 
			
		||||
            end_offset += 2; // for the comma + rbrace
 | 
			
		||||
            n = tree.extra_data[members.end - 1]; // last parameter
 | 
			
		||||
        },
 | 
			
		||||
        .array_init_dot,
 | 
			
		||||
        .struct_init_dot,
 | 
			
		||||
        .block,
 | 
			
		||||
        .container_decl,
 | 
			
		||||
        .tagged_union,
 | 
			
		||||
        .builtin_call,
 | 
			
		||||
        => {
 | 
			
		||||
            std.debug.assert(datas[n].rhs - datas[n].lhs > 0);
 | 
			
		||||
            end_offset += 1; // for the rbrace
 | 
			
		||||
            n = tree.extra_data[datas[n].rhs - 1]; // last statement
 | 
			
		||||
        },
 | 
			
		||||
        .array_init_dot_comma,
 | 
			
		||||
        .struct_init_dot_comma,
 | 
			
		||||
        .block_semicolon,
 | 
			
		||||
        .container_decl_trailing,
 | 
			
		||||
        .tagged_union_trailing,
 | 
			
		||||
        .builtin_call_comma,
 | 
			
		||||
        => {
 | 
			
		||||
            std.debug.assert(datas[n].rhs - datas[n].lhs > 0);
 | 
			
		||||
            end_offset += 2; // for the comma/semicolon + rbrace/rparen
 | 
			
		||||
            n = tree.extra_data[datas[n].rhs - 1]; // last member
 | 
			
		||||
        },
 | 
			
		||||
        .call_one,
 | 
			
		||||
        .async_call_one,
 | 
			
		||||
        .array_access,
 | 
			
		||||
        => {
 | 
			
		||||
            end_offset += 1; // for the rparen/rbracket
 | 
			
		||||
            if (datas[n].rhs == 0) {
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
            n = datas[n].rhs;
 | 
			
		||||
        },
 | 
			
		||||
        .array_init_dot_two,
 | 
			
		||||
        .block_two,
 | 
			
		||||
        .builtin_call_two,
 | 
			
		||||
        .struct_init_dot_two,
 | 
			
		||||
        .container_decl_two,
 | 
			
		||||
        .tagged_union_two,
 | 
			
		||||
        => {
 | 
			
		||||
            if (datas[n].rhs != 0) {
 | 
			
		||||
                end_offset += 1; // for the rparen/rbrace
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            } else if (datas[n].lhs != 0) {
 | 
			
		||||
                end_offset += 1; // for the rparen/rbrace
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                switch (tags[n]) {
 | 
			
		||||
                    .array_init_dot_two,
 | 
			
		||||
                    .block_two,
 | 
			
		||||
                    .struct_init_dot_two,
 | 
			
		||||
                    => end_offset += 1, // rbrace
 | 
			
		||||
                    .builtin_call_two => end_offset += 2, // lparen/lbrace + rparen/rbrace
 | 
			
		||||
                    .container_decl_two => {
 | 
			
		||||
                        var i: u32 = 2; // lbrace + rbrace
 | 
			
		||||
                        while (token_tags[main_tokens[n] + i] == .container_doc_comment) i += 1;
 | 
			
		||||
                        end_offset += i;
 | 
			
		||||
                    },
 | 
			
		||||
                    .tagged_union_two => {
 | 
			
		||||
                        var i: u32 = 5; // (enum) {}
 | 
			
		||||
                        while (token_tags[main_tokens[n] + i] == .container_doc_comment) i += 1;
 | 
			
		||||
                        end_offset += i;
 | 
			
		||||
                    },
 | 
			
		||||
                    else => unreachable,
 | 
			
		||||
                }
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .array_init_dot_two_comma,
 | 
			
		||||
        .builtin_call_two_comma,
 | 
			
		||||
        .block_two_semicolon,
 | 
			
		||||
        .struct_init_dot_two_comma,
 | 
			
		||||
        .container_decl_two_trailing,
 | 
			
		||||
        .tagged_union_two_trailing,
 | 
			
		||||
        => {
 | 
			
		||||
            end_offset += 2; // for the comma/semicolon + rbrace/rparen
 | 
			
		||||
            if (datas[n].rhs != 0) {
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            } else if (datas[n].lhs != 0) {
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                return main_tokens[n] + end_offset; // returns { }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .simple_var_decl => {
 | 
			
		||||
            if (datas[n].rhs != 0) {
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            } else if (datas[n].lhs != 0) {
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                end_offset += 1; // from mut token to name
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .aligned_var_decl => {
 | 
			
		||||
            if (datas[n].rhs != 0) {
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            } else if (datas[n].lhs != 0) {
 | 
			
		||||
                end_offset += 1; // for the rparen
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                end_offset += 1; // from mut token to name
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .global_var_decl => {
 | 
			
		||||
            if (datas[n].rhs != 0) {
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                const extra = tree.extraData(datas[n].lhs, Node.GlobalVarDecl);
 | 
			
		||||
                if (extra.section_node != 0) {
 | 
			
		||||
                    end_offset += 1; // for the rparen
 | 
			
		||||
                    n = extra.section_node;
 | 
			
		||||
                } else if (extra.align_node != 0) {
 | 
			
		||||
                    end_offset += 1; // for the rparen
 | 
			
		||||
                    n = extra.align_node;
 | 
			
		||||
                } else if (extra.type_node != 0) {
 | 
			
		||||
                    n = extra.type_node;
 | 
			
		||||
                } else {
 | 
			
		||||
                    end_offset += 1; // from mut token to name
 | 
			
		||||
                    return main_tokens[n] + end_offset;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .local_var_decl => {
 | 
			
		||||
            if (datas[n].rhs != 0) {
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                const extra = tree.extraData(datas[n].lhs, Node.LocalVarDecl);
 | 
			
		||||
                if (extra.align_node != 0) {
 | 
			
		||||
                    end_offset += 1; // for the rparen
 | 
			
		||||
                    n = extra.align_node;
 | 
			
		||||
                } else if (extra.type_node != 0) {
 | 
			
		||||
                    n = extra.type_node;
 | 
			
		||||
                } else {
 | 
			
		||||
                    end_offset += 1; // from mut token to name
 | 
			
		||||
                    return main_tokens[n] + end_offset;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .container_field_init => {
 | 
			
		||||
            if (datas[n].rhs != 0) {
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            } else if (datas[n].lhs != 0) {
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .container_field_align => {
 | 
			
		||||
            if (datas[n].rhs != 0) {
 | 
			
		||||
                end_offset += 1; // for the rparen
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            } else if (datas[n].lhs != 0) {
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .container_field => {
 | 
			
		||||
            const extra = tree.extraData(datas[n].rhs, Node.ContainerField);
 | 
			
		||||
            if (extra.value_expr != 0) {
 | 
			
		||||
                n = extra.value_expr;
 | 
			
		||||
            } else if (extra.align_expr != 0) {
 | 
			
		||||
                end_offset += 1; // for the rparen
 | 
			
		||||
                n = extra.align_expr;
 | 
			
		||||
            } else if (datas[n].lhs != 0) {
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        .array_init_one,
 | 
			
		||||
        .struct_init_one,
 | 
			
		||||
        => {
 | 
			
		||||
            end_offset += 1; // rbrace
 | 
			
		||||
            if (datas[n].rhs == 0) {
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            } else {
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .slice_open,
 | 
			
		||||
        .call_one_comma,
 | 
			
		||||
        .async_call_one_comma,
 | 
			
		||||
        .array_init_one_comma,
 | 
			
		||||
        .struct_init_one_comma,
 | 
			
		||||
        => {
 | 
			
		||||
            end_offset += 2; // ellipsis2 + rbracket, or comma + rparen
 | 
			
		||||
            n = datas[n].rhs;
 | 
			
		||||
            std.debug.assert(n != 0);
 | 
			
		||||
        },
 | 
			
		||||
        .slice => {
 | 
			
		||||
            const extra = tree.extraData(datas[n].rhs, Node.Slice);
 | 
			
		||||
            std.debug.assert(extra.end != 0); // should have used slice_open
 | 
			
		||||
            end_offset += 1; // rbracket
 | 
			
		||||
            n = extra.end;
 | 
			
		||||
        },
 | 
			
		||||
        .slice_sentinel => {
 | 
			
		||||
            const extra = tree.extraData(datas[n].rhs, Node.SliceSentinel);
 | 
			
		||||
            std.debug.assert(extra.sentinel != 0); // should have used slice
 | 
			
		||||
            end_offset += 1; // rbracket
 | 
			
		||||
            n = extra.sentinel;
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        .@"continue" => {
 | 
			
		||||
            if (datas[n].lhs != 0) {
 | 
			
		||||
                return datas[n].lhs + end_offset;
 | 
			
		||||
            } else {
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .@"break" => {
 | 
			
		||||
            if (datas[n].rhs != 0) {
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            } else if (datas[n].lhs != 0) {
 | 
			
		||||
                return datas[n].lhs + end_offset;
 | 
			
		||||
            } else {
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .fn_decl => {
 | 
			
		||||
            if (datas[n].rhs != 0) {
 | 
			
		||||
                n = datas[n].rhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .fn_proto_one => {
 | 
			
		||||
            const extra = tree.extraData(datas[n].lhs, Node.FnProtoOne);
 | 
			
		||||
            // linksection, callconv, align can appear in any order, so we
 | 
			
		||||
            // find the last one here.
 | 
			
		||||
            var max_node: Node.Index = datas[n].rhs;
 | 
			
		||||
            var max_start = token_starts[main_tokens[max_node]];
 | 
			
		||||
            var max_offset: TokenIndex = 0;
 | 
			
		||||
            if (extra.align_expr != 0) {
 | 
			
		||||
                const start = token_starts[main_tokens[extra.align_expr]];
 | 
			
		||||
                if (start > max_start) {
 | 
			
		||||
                    max_node = extra.align_expr;
 | 
			
		||||
                    max_start = start;
 | 
			
		||||
                    max_offset = 1; // for the rparen
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (extra.section_expr != 0) {
 | 
			
		||||
                const start = token_starts[main_tokens[extra.section_expr]];
 | 
			
		||||
                if (start > max_start) {
 | 
			
		||||
                    max_node = extra.section_expr;
 | 
			
		||||
                    max_start = start;
 | 
			
		||||
                    max_offset = 1; // for the rparen
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (extra.callconv_expr != 0) {
 | 
			
		||||
                const start = token_starts[main_tokens[extra.callconv_expr]];
 | 
			
		||||
                if (start > max_start) {
 | 
			
		||||
                    max_node = extra.callconv_expr;
 | 
			
		||||
                    max_start = start;
 | 
			
		||||
                    max_offset = 1; // for the rparen
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            n = max_node;
 | 
			
		||||
            end_offset += max_offset;
 | 
			
		||||
        },
 | 
			
		||||
        .fn_proto => {
 | 
			
		||||
            const extra = tree.extraData(datas[n].lhs, Node.FnProto);
 | 
			
		||||
            // linksection, callconv, align can appear in any order, so we
 | 
			
		||||
            // find the last one here.
 | 
			
		||||
            var max_node: Node.Index = datas[n].rhs;
 | 
			
		||||
            var max_start = token_starts[main_tokens[max_node]];
 | 
			
		||||
            var max_offset: TokenIndex = 0;
 | 
			
		||||
            if (extra.align_expr != 0) {
 | 
			
		||||
                const start = token_starts[main_tokens[extra.align_expr]];
 | 
			
		||||
                if (start > max_start) {
 | 
			
		||||
                    max_node = extra.align_expr;
 | 
			
		||||
                    max_start = start;
 | 
			
		||||
                    max_offset = 1; // for the rparen
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (extra.section_expr != 0) {
 | 
			
		||||
                const start = token_starts[main_tokens[extra.section_expr]];
 | 
			
		||||
                if (start > max_start) {
 | 
			
		||||
                    max_node = extra.section_expr;
 | 
			
		||||
                    max_start = start;
 | 
			
		||||
                    max_offset = 1; // for the rparen
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (extra.callconv_expr != 0) {
 | 
			
		||||
                const start = token_starts[main_tokens[extra.callconv_expr]];
 | 
			
		||||
                if (start > max_start) {
 | 
			
		||||
                    max_node = extra.callconv_expr;
 | 
			
		||||
                    max_start = start;
 | 
			
		||||
                    max_offset = 1; // for the rparen
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            n = max_node;
 | 
			
		||||
            end_offset += max_offset;
 | 
			
		||||
        },
 | 
			
		||||
        .while_cont => {
 | 
			
		||||
            const extra = tree.extraData(datas[n].rhs, Node.WhileCont);
 | 
			
		||||
            std.debug.assert(extra.then_expr != 0);
 | 
			
		||||
            n = extra.then_expr;
 | 
			
		||||
        },
 | 
			
		||||
        .@"while" => {
 | 
			
		||||
            const extra = tree.extraData(datas[n].rhs, Node.While);
 | 
			
		||||
            std.debug.assert(extra.else_expr != 0);
 | 
			
		||||
            n = extra.else_expr;
 | 
			
		||||
        },
 | 
			
		||||
        .@"if", .@"for" => {
 | 
			
		||||
            const extra = tree.extraData(datas[n].rhs, Node.If);
 | 
			
		||||
            std.debug.assert(extra.else_expr != 0);
 | 
			
		||||
            n = extra.else_expr;
 | 
			
		||||
        },
 | 
			
		||||
        .@"suspend" => {
 | 
			
		||||
            if (datas[n].lhs != 0) {
 | 
			
		||||
                n = datas[n].lhs;
 | 
			
		||||
            } else {
 | 
			
		||||
                return main_tokens[n] + end_offset;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        .array_type_sentinel => {
 | 
			
		||||
            const extra = tree.extraData(datas[n].rhs, Node.ArrayTypeSentinel);
 | 
			
		||||
            n = extra.elem_type;
 | 
			
		||||
        },
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ const analysis = @import("analysis.zig");
 | 
			
		||||
const types = @import("types.zig");
 | 
			
		||||
const offsets = @import("offsets.zig");
 | 
			
		||||
const log = std.log.scoped(.references);
 | 
			
		||||
usingnamespace @import("ast.zig");
 | 
			
		||||
 | 
			
		||||
const ast = std.zig.ast;
 | 
			
		||||
 | 
			
		||||
@ -250,7 +251,7 @@ fn symbolReferencesInternal(
 | 
			
		||||
        .@"if",
 | 
			
		||||
        .if_simple,
 | 
			
		||||
        => {
 | 
			
		||||
            const if_node: ast.full.If = if (node_tags[node] == .@"if") tree.ifFull(node) else tree.ifSimple(node);
 | 
			
		||||
            const if_node: ast.full.If = if (node_tags[node] == .@"if") ifFull(tree, node) else tree.ifSimple(node);
 | 
			
		||||
 | 
			
		||||
            try symbolReferencesInternal(arena, store, .{ .node = if_node.ast.cond_expr, .handle = handle }, decl, encoding, context, handler);
 | 
			
		||||
            try symbolReferencesInternal(arena, store, .{ .node = if_node.ast.then_expr, .handle = handle }, decl, encoding, context, handler);
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@ const offsets = @import("offsets.zig");
 | 
			
		||||
const DocumentStore = @import("document_store.zig");
 | 
			
		||||
const analysis = @import("analysis.zig");
 | 
			
		||||
const ast = std.zig.ast;
 | 
			
		||||
const lastToken = offsets.lastToken;
 | 
			
		||||
usingnamespace @import("ast.zig");
 | 
			
		||||
 | 
			
		||||
pub const TokenType = enum(u32) {
 | 
			
		||||
    type,
 | 
			
		||||
@ -700,7 +700,7 @@ fn writeNodeTokens(
 | 
			
		||||
        .@"if",
 | 
			
		||||
        .if_simple,
 | 
			
		||||
        => {
 | 
			
		||||
            const if_node: ast.full.If = if (tag == .@"if") tree.ifFull(node) else tree.ifSimple(node);
 | 
			
		||||
            const if_node: ast.full.If = if (tag == .@"if") ifFull(tree, node) else tree.ifSimple(node);
 | 
			
		||||
 | 
			
		||||
            try writeToken(builder, if_node.ast.if_token, .keyword);
 | 
			
		||||
            try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, if_node.ast.cond_expr });
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user