Optimize document symbols (#1050)

* optimize document symbol generation

* match folding range index to position conversion and documentation to document symbol's

* skip function decls with no name

* skip document symbol field in opaque type
This commit is contained in:
Techatrix
2023-03-12 06:24:42 +00:00
committed by GitHub
parent c203110555
commit ab23ff3616
5 changed files with 291 additions and 264 deletions

View File

@@ -1804,237 +1804,6 @@ pub fn getPositionContext(
return if (tok.tag == .identifier) PositionContext{ .var_access = tok.loc } else .empty;
}
fn addOutlineNodes(allocator: std.mem.Allocator, tree: Ast, child: Ast.Node.Index, context: *GetDocumentSymbolsContext) error{OutOfMemory}!void {
switch (tree.nodes.items(.tag)[child]) {
.string_literal,
.number_literal,
.builtin_call,
.builtin_call_comma,
.builtin_call_two,
.builtin_call_two_comma,
.call,
.call_comma,
.call_one,
.call_one_comma,
.async_call,
.async_call_comma,
.async_call_one,
.async_call_one_comma,
.identifier,
.add,
.add_wrap,
.array_cat,
.array_mult,
.assign,
.assign_bit_and,
.assign_bit_or,
.assign_shl,
.assign_shr,
.assign_bit_xor,
.assign_div,
.assign_sub,
.assign_sub_wrap,
.assign_mod,
.assign_add,
.assign_add_wrap,
.assign_mul,
.assign_mul_wrap,
.bang_equal,
.bit_and,
.bit_or,
.shl,
.shr,
.bit_xor,
.bool_and,
.bool_or,
.div,
.equal_equal,
.error_union,
.greater_or_equal,
.greater_than,
.less_or_equal,
.less_than,
.merge_error_sets,
.mod,
.mul,
.mul_wrap,
.field_access,
.switch_range,
.sub,
.sub_wrap,
.@"orelse",
.address_of,
.@"await",
.bit_not,
.bool_not,
.optional_type,
.negation,
.negation_wrap,
.@"resume",
.@"try",
.array_type,
.array_type_sentinel,
.ptr_type,
.ptr_type_aligned,
.ptr_type_bit_range,
.ptr_type_sentinel,
.slice_open,
.slice_sentinel,
.deref,
.unwrap_optional,
.array_access,
.@"return",
.@"break",
.@"continue",
.array_init,
.array_init_comma,
.array_init_dot,
.array_init_dot_comma,
.array_init_dot_two,
.array_init_dot_two_comma,
.array_init_one,
.array_init_one_comma,
.@"switch",
.switch_comma,
.switch_case,
.switch_case_one,
.@"for",
.for_simple,
.enum_literal,
.struct_init,
.struct_init_comma,
.struct_init_dot,
.struct_init_dot_comma,
.struct_init_dot_two,
.struct_init_dot_two_comma,
.struct_init_one,
.struct_init_one_comma,
.@"while",
.while_simple,
.while_cont,
.@"defer",
.@"if",
.if_simple,
.multiline_string_literal,
.block,
.block_semicolon,
.block_two,
.block_two_semicolon,
.error_set_decl,
=> return,
.container_decl,
.container_decl_trailing,
.container_decl_arg,
.container_decl_arg_trailing,
.container_decl_two,
.container_decl_two_trailing,
.tagged_union,
.tagged_union_trailing,
.tagged_union_enum_tag,
.tagged_union_enum_tag_trailing,
.tagged_union_two,
.tagged_union_two_trailing,
=> {
var buf: [2]Ast.Node.Index = undefined;
const members = tree.fullContainerDecl(&buf, child).?.ast.members;
for (members) |member|
try addOutlineNodes(allocator, tree, member, context);
return;
},
else => {},
}
try getDocumentSymbolsInternal(allocator, tree, child, context);
}
const GetDocumentSymbolsContext = struct {
symbols: *std.ArrayListUnmanaged(types.DocumentSymbol),
encoding: offsets.Encoding,
};
fn getDocumentSymbolsInternal(allocator: std.mem.Allocator, tree: Ast, node: Ast.Node.Index, context: *GetDocumentSymbolsContext) error{OutOfMemory}!void {
const name = getDeclName(tree, node) orelse return;
if (name.len == 0)
return;
const range = offsets.nodeToRange(tree, node, context.encoding);
const tags = tree.nodes.items(.tag);
(try context.symbols.addOne(allocator)).* = .{
.name = name,
.kind = switch (tags[node]) {
.fn_proto,
.fn_proto_simple,
.fn_proto_multi,
.fn_proto_one,
.fn_decl,
=> .Function,
.local_var_decl,
.global_var_decl,
.aligned_var_decl,
.simple_var_decl,
=> .Variable,
.container_field,
.container_field_align,
.container_field_init,
.tagged_union_enum_tag,
.tagged_union_enum_tag_trailing,
.tagged_union,
.tagged_union_trailing,
.tagged_union_two,
.tagged_union_two_trailing,
=> .Field,
else => .Variable,
},
.range = range,
.selectionRange = range,
.detail = "",
.children = ch: {
var children = std.ArrayListUnmanaged(types.DocumentSymbol){};
var child_context = GetDocumentSymbolsContext{
.symbols = &children,
.encoding = context.encoding,
};
var buf: [2]Ast.Node.Index = undefined;
if (tree.fullContainerDecl(&buf, node)) |container_decl| {
for (container_decl.ast.members) |child| {
try addOutlineNodes(allocator, tree, child, &child_context);
}
} else if (tree.fullVarDecl(node)) |var_decl| {
if (var_decl.ast.init_node != 0)
try addOutlineNodes(allocator, tree, var_decl.ast.init_node, &child_context);
} else if (tags[node] == .fn_decl) fn_ch: {
const fn_decl = tree.nodes.items(.data)[node];
var params: [1]Ast.Node.Index = undefined;
const fn_proto = tree.fullFnProto(&params, fn_decl.lhs).?;
if (!isTypeFunction(tree, fn_proto)) break :fn_ch;
const ret_stmt = findReturnStatement(tree, fn_proto, fn_decl.rhs) orelse break :fn_ch;
const type_decl = tree.nodes.items(.data)[ret_stmt].lhs;
if (type_decl != 0)
try addOutlineNodes(allocator, tree, type_decl, &child_context);
}
break :ch children.items;
},
};
}
pub fn getDocumentSymbols(allocator: std.mem.Allocator, tree: Ast, encoding: offsets.Encoding) ![]types.DocumentSymbol {
var symbols = std.ArrayListUnmanaged(types.DocumentSymbol){};
try symbols.ensureTotalCapacity(allocator, tree.rootDecls().len);
var context = GetDocumentSymbolsContext{
.symbols = &symbols,
.encoding = encoding,
};
for (tree.rootDecls()) |idx| {
try getDocumentSymbolsInternal(allocator, tree, idx, &context);
}
return symbols.items;
}
pub const Declaration = union(enum) {
/// Index of the ast node
ast_node: Ast.Node.Index,