From 2d168ed63ef3804291327a36a083e58399379f33 Mon Sep 17 00:00:00 2001 From: Alexandros Naskos Date: Mon, 29 Mar 2021 12:28:52 +0300 Subject: [PATCH] Fixed error completion generation when making document scopes --- src/analysis.zig | 103 +++++++++++++++++++++++++++++++++++------------ src/requests.zig | 25 ++++++++---- src/types.zig | 4 +- 3 files changed, 97 insertions(+), 35 deletions(-) diff --git a/src/analysis.zig b/src/analysis.zig index 4c60e08..99a8ed3 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -2611,41 +2611,52 @@ fn makeScopeInternal( .data = .{ .container = node_idx }, }; const scope_idx = scopes.items.len - 1; - var uses = std.ArrayList(*const ast.Node.Index).init(allocator); - var tests = std.ArrayList(ast.Node.Index).init(allocator); + var uses = std.ArrayListUnmanaged(*const ast.Node.Index){}; + var tests = std.ArrayListUnmanaged(ast.Node.Index){}; errdefer { scopes.items[scope_idx].decls.deinit(); - uses.deinit(); - tests.deinit(); + uses.deinit(allocator); + tests.deinit(allocator); + } + + if (node_tag == .error_set_decl) { + // All identifiers in main_token..data.lhs are error fields. + var i = main_tokens[node_idx]; + while (i < data[node_idx].rhs) : (i += 1) { + if (token_tags[i] == .identifier) { + (try error_completions.addOne(allocator)).* = .{ + .label = tree.tokenSlice(i), + .kind = .Constant, + .insertTextFormat = .PlainText, + .insertText = tree.tokenSlice(i), + }; + } + } } for (ast_decls) |*ptr_decl| { const decl = ptr_decl.*; if (tags[decl] == .@"usingnamespace") { - try uses.append(ptr_decl); + try uses.append(allocator, ptr_decl); continue; } - try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, decl); + try makeScopeInternal( + allocator, + scopes, + error_completions, + enum_completions, + tree, + decl, + ); const name = getDeclName(tree, decl) orelse continue; if (tags[decl] == .test_decl) { - try tests.append(decl); + try tests.append(allocator, decl); continue; } - if (node_tag == .error_set_decl) { - (try error_completions.addOne(allocator)).* = .{ - .label = name, - .kind = .Constant, - .documentation = if (try getDocComments(allocator, tree, decl, .Markdown)) |docs| .{ - .kind = .Markdown, - .value = docs, - } else null, - }; - } - - const container_field: ?ast.full.ContainerField = switch (tags[decl]) { + const container_field = switch (tags[decl]) { .container_field => tree.containerField(decl), .container_field_align => tree.containerFieldAlign(decl), .container_field_init => tree.containerFieldInit(decl), @@ -2658,7 +2669,7 @@ fn makeScopeInternal( continue; } - const container_decl: ?ast.full.ContainerDecl = switch (node_tag) { + const container_decl = switch (node_tag) { .container_decl, .container_decl_trailing => tree.containerDecl(node_idx), .container_decl_arg, .container_decl_arg_trailing => tree.containerDeclArg(node_idx), .container_decl_two, .container_decl_two_trailing => blk: { @@ -2700,8 +2711,8 @@ fn makeScopeInternal( } } - scopes.items[scope_idx].tests = tests.toOwnedSlice(); - scopes.items[scope_idx].uses = uses.toOwnedSlice(); + scopes.items[scope_idx].tests = tests.toOwnedSlice(allocator); + scopes.items[scope_idx].uses = uses.toOwnedSlice(allocator); return; } @@ -2727,21 +2738,63 @@ fn makeScopeInternal( var it = func.iterate(tree); while (it.next()) |param| { + // Add parameter decls if (param.name_token) |name_token| { - if (try scopes.items[scope_idx].decls.fetchPut(tree.tokenSlice(name_token), .{ .param_decl = param })) |existing| { + if (try scopes.items[scope_idx].decls.fetchPut( + tree.tokenSlice(name_token), + .{ .param_decl = param }, + )) |existing| { // TODO record a redefinition error } } + // Visit parameter types to pick up any error sets and enum + // completions + try makeScopeInternal( + allocator, + scopes, + error_completions, + enum_completions, + tree, + param.type_expr, + ); } + // Visit the return type + try makeScopeInternal( + allocator, + scopes, + error_completions, + enum_completions, + tree, + // TODO: This should be the proto + if (fn_tag == .fn_decl) + data[data[node_idx].lhs].rhs + else + data[node_idx].rhs, + ); + // Visit the function body if (fn_tag == .fn_decl) { - try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, data[node_idx].rhs); + try makeScopeInternal( + allocator, + scopes, + error_completions, + enum_completions, + tree, + data[node_idx].rhs, + ); } return; }, .test_decl => { - return try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, data[node_idx].rhs); + return try makeScopeInternal( + allocator, + scopes, + error_completions, + enum_completions, + tree, + data[node_idx].rhs, + ); }, .block, .block_semicolon, diff --git a/src/requests.zig b/src/requests.zig index 80a2e42..6d3f4e0 100644 --- a/src/requests.zig +++ b/src/requests.zig @@ -1,3 +1,7 @@ +//! This file contains request types zls handles. +//! Note that the parameter types may be incomplete. +//! We only define what we actually use. + const std = @import("std"); const types = @import("types.zig"); @@ -37,8 +41,14 @@ fn fromDynamicTreeInternal(arena: *std.heap.ArenaAllocator, value: std.json.Valu const actual_type = if (is_optional) std.meta.Child(field.field_type) else field.field_type; const is_struct = comptime std.meta.trait.is(.Struct)(actual_type); - const is_default = comptime if (is_struct) std.meta.trait.hasDecls(actual_type, .{ "default", "value_type" }) else false; - const is_transform = comptime if (is_struct) std.meta.trait.hasDecls(actual_type, .{ "original_type", "transform" }) else false; + const is_default = comptime if (is_struct) std.meta.trait.hasDecls(actual_type, .{ + "default", + "value_type", + }) else false; + const is_transform = comptime if (is_struct) std.meta.trait.hasDecls(actual_type, .{ + "original_type", + "transform", + }) else false; if (value.Object.get(field.name)) |json_field| { if (is_exists) { @@ -46,7 +56,10 @@ fn fromDynamicTreeInternal(arena: *std.heap.ArenaAllocator, value: std.json.Valu } else if (is_transform) { var original_value: actual_type.original_type = undefined; try fromDynamicTreeInternal(arena, json_field, &original_value); - @field(out, field.name) = actual_type{ .value = actual_type.transform(original_value) catch return error.MalformedJson }; + @field(out, field.name) = actual_type{ + .value = actual_type.transform(original_value) catch + return error.MalformedJson, + }; } else if (is_default) { try fromDynamicTreeInternal(arena, json_field, &@field(out, field.name).value); } else if (is_optional) { @@ -117,11 +130,7 @@ pub fn fromDynamicTree(arena: *std.heap.ArenaAllocator, comptime T: type, value: return out; } -//! This file contains request types zls handles. -//! Note that the parameter types may be incomplete. -//! We only define what we actually use. - -const MaybeStringArray = Default([]const []const u8, &[0][]const u8{}); +const MaybeStringArray = Default([]const []const u8, &.{}); pub const Initialize = struct { pub const ClientCapabilities = struct { diff --git a/src/types.zig b/src/types.zig index 13633a3..e6a087e 100644 --- a/src/types.zig +++ b/src/types.zig @@ -331,8 +331,8 @@ const InitializeResult = struct { workspaceSymbolProvider: bool, rangeProvider: bool, documentProvider: bool, - workspace: struct { - workspaceFolders: struct { + workspace: ?struct { + workspaceFolders: ?struct { supported: bool, changeNotifications: bool, },