Fixed error completion generation when making document scopes

This commit is contained in:
Alexandros Naskos 2021-03-29 12:28:52 +03:00
parent 4529b056cd
commit 2d168ed63e
No known key found for this signature in database
GPG Key ID: 02BF2E72B0EA32D2
3 changed files with 97 additions and 35 deletions

View File

@ -2611,41 +2611,52 @@ fn makeScopeInternal(
.data = .{ .container = node_idx }, .data = .{ .container = node_idx },
}; };
const scope_idx = scopes.items.len - 1; const scope_idx = scopes.items.len - 1;
var uses = std.ArrayList(*const ast.Node.Index).init(allocator); var uses = std.ArrayListUnmanaged(*const ast.Node.Index){};
var tests = std.ArrayList(ast.Node.Index).init(allocator); var tests = std.ArrayListUnmanaged(ast.Node.Index){};
errdefer { errdefer {
scopes.items[scope_idx].decls.deinit(); scopes.items[scope_idx].decls.deinit();
uses.deinit(); uses.deinit(allocator);
tests.deinit(); 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| { for (ast_decls) |*ptr_decl| {
const decl = ptr_decl.*; const decl = ptr_decl.*;
if (tags[decl] == .@"usingnamespace") { if (tags[decl] == .@"usingnamespace") {
try uses.append(ptr_decl); try uses.append(allocator, ptr_decl);
continue; 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; const name = getDeclName(tree, decl) orelse continue;
if (tags[decl] == .test_decl) { if (tags[decl] == .test_decl) {
try tests.append(decl); try tests.append(allocator, decl);
continue; continue;
} }
if (node_tag == .error_set_decl) { const container_field = switch (tags[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]) {
.container_field => tree.containerField(decl), .container_field => tree.containerField(decl),
.container_field_align => tree.containerFieldAlign(decl), .container_field_align => tree.containerFieldAlign(decl),
.container_field_init => tree.containerFieldInit(decl), .container_field_init => tree.containerFieldInit(decl),
@ -2658,7 +2669,7 @@ fn makeScopeInternal(
continue; 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, .container_decl_trailing => tree.containerDecl(node_idx),
.container_decl_arg, .container_decl_arg_trailing => tree.containerDeclArg(node_idx), .container_decl_arg, .container_decl_arg_trailing => tree.containerDeclArg(node_idx),
.container_decl_two, .container_decl_two_trailing => blk: { .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].tests = tests.toOwnedSlice(allocator);
scopes.items[scope_idx].uses = uses.toOwnedSlice(); scopes.items[scope_idx].uses = uses.toOwnedSlice(allocator);
return; return;
} }
@ -2727,21 +2738,63 @@ fn makeScopeInternal(
var it = func.iterate(tree); var it = func.iterate(tree);
while (it.next()) |param| { while (it.next()) |param| {
// Add parameter decls
if (param.name_token) |name_token| { 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 // 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) { 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; return;
}, },
.test_decl => { .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,
.block_semicolon, .block_semicolon,

View File

@ -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 std = @import("std");
const types = @import("types.zig"); 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 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_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_default = comptime if (is_struct) std.meta.trait.hasDecls(actual_type, .{
const is_transform = comptime if (is_struct) std.meta.trait.hasDecls(actual_type, .{ "original_type", "transform" }) else false; "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 (value.Object.get(field.name)) |json_field| {
if (is_exists) { if (is_exists) {
@ -46,7 +56,10 @@ fn fromDynamicTreeInternal(arena: *std.heap.ArenaAllocator, value: std.json.Valu
} else if (is_transform) { } else if (is_transform) {
var original_value: actual_type.original_type = undefined; var original_value: actual_type.original_type = undefined;
try fromDynamicTreeInternal(arena, json_field, &original_value); 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) { } else if (is_default) {
try fromDynamicTreeInternal(arena, json_field, &@field(out, field.name).value); try fromDynamicTreeInternal(arena, json_field, &@field(out, field.name).value);
} else if (is_optional) { } else if (is_optional) {
@ -117,11 +130,7 @@ pub fn fromDynamicTree(arena: *std.heap.ArenaAllocator, comptime T: type, value:
return out; return out;
} }
//! This file contains request types zls handles. const MaybeStringArray = Default([]const []const u8, &.{});
//! Note that the parameter types may be incomplete.
//! We only define what we actually use.
const MaybeStringArray = Default([]const []const u8, &[0][]const u8{});
pub const Initialize = struct { pub const Initialize = struct {
pub const ClientCapabilities = struct { pub const ClientCapabilities = struct {

View File

@ -331,8 +331,8 @@ const InitializeResult = struct {
workspaceSymbolProvider: bool, workspaceSymbolProvider: bool,
rangeProvider: bool, rangeProvider: bool,
documentProvider: bool, documentProvider: bool,
workspace: struct { workspace: ?struct {
workspaceFolders: struct { workspaceFolders: ?struct {
supported: bool, supported: bool,
changeNotifications: bool, changeNotifications: bool,
}, },