From 46456384344af82c9eeb72d4cfe054967433d15a Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Mon, 1 Mar 2021 16:02:24 +0100 Subject: [PATCH] Fixes and completions --- src/analysis.zig | 26 ++++--- src/main.zig | 176 ++++++++++++++++++++++----------------------- src/offsets.zig | 4 +- src/references.zig | 2 +- 4 files changed, 108 insertions(+), 100 deletions(-) diff --git a/src/analysis.zig b/src/analysis.zig index c442dfc..ea5f0e5 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -79,14 +79,14 @@ pub fn collectDocComments( } /// Gets a function signature (keywords, name, return value) -pub fn getFunctionSignature(tree: ast.Tree, func: *ast.full.FnProto) []const u8 { +pub fn getFunctionSignature(tree: ast.Tree, func: ast.full.FnProto) []const u8 { const start = tree.tokenLocation(func.ast.fn_token).line_start; const end = tree.tokenLocation(func.ast.return_type).line_end; return tree.source[start..end]; } /// Gets a function snippet insert text -pub fn getFunctionSnippet(allocator: *std.mem.Allocator, tree: ast.Tree, func: *ast.full.FnProto, skip_self_param: bool) ![]const u8 { +pub fn getFunctionSnippet(allocator: *std.mem.Allocator, tree: ast.Tree, func: ast.full.FnProto, skip_self_param: bool) ![]const u8 { const name_index = func.name_token orelse unreachable; var buffer = std.ArrayList(u8).init(allocator); @@ -143,14 +143,14 @@ pub fn getFunctionSnippet(allocator: *std.mem.Allocator, tree: ast.Tree, func: * } /// Gets a function signature (keywords, name, return value) -pub fn getVariableSignature(tree: ast.Tree, var_decl: *ast.full.VarDecl) []const u8 { +pub fn getVariableSignature(tree: ast.Tree, var_decl: ast.full.VarDecl) []const u8 { const start = tree.tokenLocation(0, var_decl.ast.mut_token).line_start; const end = tree.tokenLocation(@truncate(u32, start), tree.lastToken(var_decl.ast.init_node)).line_end; return tree.source[start..end]; } // analysis.getContainerFieldSignature(handle.tree, field) -pub fn getContainerFieldSignature(tree: ast.Tree, field: *ast.full.ContainerField) []const u8 { +pub fn getContainerFieldSignature(tree: ast.Tree, field: ast.full.ContainerField) []const u8 { const start = tree.tokenLocation(0, field.ast.name_token).line_start; const end = tree.tokenLocation(@truncate(u32, start), tree.lastToken(field.ast.value_expr)).line_start; return tree.source[start..end]; @@ -430,7 +430,7 @@ fn resolveUnwrapErrorType( return null; } -fn isPtrType(tree: ast.Tree, node: ast.Node.Index) bool { +pub fn isPtrType(tree: ast.Tree, node: ast.Node.Index) bool { return switch (tree.nodes.items(.tag)[node]) { .ptr_type, .ptr_type_aligned, @@ -1807,7 +1807,7 @@ pub const DeclWithHandle = struct { } }; -fn containerField(tree: ast.Tree, node: ast.Node.Index) ?ast.full.ContainerField { +pub fn containerField(tree: ast.Tree, node: ast.Node.Index) ?ast.full.ContainerField { return switch (tree.nodes.items(.tag)[node]) { .container_field => tree.containerField(node), .container_field_init => tree.containerFieldInit(node), @@ -1816,6 +1816,16 @@ fn containerField(tree: ast.Tree, node: ast.Node.Index) ?ast.full.ContainerField }; } +pub fn ptrType(tree: ast.Tree, node: ast.Node.Index) ?ast.full.PtrType { + return switch (tree.nodes.items(.tag)[node]) { + .ptr_type => tree.ptrType(node), + .ptr_type_aligned => tree.ptrTypeAligned(node), + .ptr_type_bit_range => tree.ptrTypeBitRange(node), + .ptr_type_sentinel => tree.ptrTypeSentinel(node), + else => null, + }; +} + fn findContainerScope(container_handle: NodeWithHandle) ?*Scope { const container = container_handle.node; const handle = container_handle.handle; @@ -2218,7 +2228,7 @@ fn nodeSourceRange(tree: ast.Tree, node: ast.Node.Index) SourceRange { }; } -fn isContainer(tag: ast.Node.Tag) bool { +pub fn isContainer(tag: ast.Node.Tag) bool { return switch (tag) { .container_decl, .container_decl_trailing, @@ -2265,7 +2275,7 @@ fn declMembers(tree: ast.Tree, tag: ast.Node.Tag, node_idx: ast.Node.Index) []co /// Returns an `ast.full.VarDecl` for a given node index. /// Returns null if the tag doesn't match -fn varDecl(tree: ast.Tree, node_idx: ast.Node.Index) ?ast.full.VarDecl { +pub fn varDecl(tree: ast.Tree, node_idx: ast.Node.Index) ?ast.full.VarDecl { return switch (tree.nodes.items(.tag)[node_idx]) { .global_var_decl => tree.globalVarDecl(node_idx), .local_var_decl => tree.localVarDecl(node_idx), diff --git a/src/main.zig b/src/main.zig index c38b06c..e9cce95 100644 --- a/src/main.zig +++ b/src/main.zig @@ -332,6 +332,10 @@ fn nodeToCompletion( ) error{OutOfMemory}!void { const node = node_handle.node; const handle = node_handle.handle; + const tree = handle.tree; + const node_tags = tree.nodes.items(.tag); + const datas = tree.nodes.items(.data); + const token_tags = tree.tokens.items(.tag); const doc_kind: types.MarkupContent.Kind = if (client_capabilities.completion_doc_supports_md) .Markdown @@ -351,7 +355,7 @@ fn nodeToCompletion( else null; - if (node.tag == .ErrorSetDecl or node.tag == .Root or node.tag == .ContainerDecl) { + if (analysis.isContainer(node_tags[node])) { const context = DeclToCompletionContext{ .completions = list, .config = &config, @@ -363,44 +367,43 @@ fn nodeToCompletion( if (is_type_val) return; - switch (node.tag) { - .FnProto => { - const func = node.cast(std.zig.ast.Node.FnProto).?; - if (func.getNameToken()) |name_token| { + switch (node_tags[node]) { + .fn_proto, .fn_proto_multi, .fn_proto_one, .fn_proto_multi, .fn_decl => { + var buf: [1]std.zig.ast.Node.Index = undefined; + const func = analysis.fnProto(tree, node, &buf).?; + if (func.name_token) |name_token| { const use_snippets = config.enable_snippets and client_capabilities.supports_snippets; const insert_text = if (use_snippets) blk: { // TODO Also check if we are dot accessing from a type val and dont skip in that case. - const skip_self_param = if (func.params_len > 0) param_check: { - const in_container = analysis.innermostContainer(handle, handle.tree.token_locs[func.firstToken()].start); + const skip_self_param = if (func.ast.params.len > 0) param_check: { + const in_container = analysis.innermostContainer(handle, tree.tokenLocation(0, func.ast.fn_token).line_start); - switch (func.paramsConst()[0].param_type) { - .type_expr => |type_node| { - if (try analysis.resolveTypeOfNode(&document_store, arena, .{ - .node = type_node, - .handle = handle, - })) |resolved_type| { - if (std.meta.eql(in_container, resolved_type)) - break :param_check true; - } + var it = func.iterate(tree); + const param = it.next().?; - if (type_node.castTag(.PtrType)) |ptr_type| { - if (try analysis.resolveTypeOfNode(&document_store, arena, .{ - .node = ptr_type.rhs, - .handle = handle, - })) |resolved_prefix_op| { - if (std.meta.eql(in_container, resolved_prefix_op)) - break :param_check true; - } - } - - break :param_check false; - }, - else => break :param_check false, + if (try analysis.resolveTypeOfNode(&document_store, arena, .{ + .node = param.type_expr, + .handle = handle, + })) |resolved_type| { + if (std.meta.eql(in_container, resolved_type)) + break :param_check true; } + + if (analysis.isPtrType(tree, param.type_expr)) { + if (try analysis.resolveTypeOfNode(&document_store, arena, .{ + .node = datas[param.type_expr].rhs, + .handle = handle, + })) |resolved_prefix_op| { + if (std.meta.eql(in_container, resolved_prefix_op)) + break :param_check true; + } + } + + break :param_check false; } else false; - break :blk try analysis.getFunctionSnippet(&arena.allocator, handle.tree, func, skip_self_param); + break :blk try analysis.getFunctionSnippet(&arena.allocator, tree, func, skip_self_param); } else null; const is_type_function = analysis.isTypeFunction(handle.tree, func); @@ -415,9 +418,9 @@ fn nodeToCompletion( }); } }, - .VarDecl => { - const var_decl = node.cast(std.zig.ast.Node.VarDecl).?; - const is_const = handle.tree.token_ids[var_decl.mut_token] == .Keyword_const; + .global_var_decl, .local_var_decl, .aligned_var_decl, .simple_var_decl => { + const var_decl = analysis.varDecl(tree, node).?; + const is_const = token_tags[var_decl.ast.mut_token] == .keyword_const; if (try analysis.resolveVarDeclAlias(&document_store, arena, node_handle)) |result| { const context = DeclToCompletionContext{ @@ -430,57 +433,46 @@ fn nodeToCompletion( } try list.append(.{ - .label = handle.tree.tokenSlice(var_decl.name_token), + .label = handle.tree.tokenSlice(var_decl.ast.mut_token + 1), .kind = if (is_const) .Constant else .Variable, .documentation = doc, - .detail = analysis.getVariableSignature(handle.tree, var_decl), + .detail = analysis.getVariableSignature(tree, var_decl), }); }, - .ContainerField => { - const field = node.cast(std.zig.ast.Node.ContainerField).?; + .container_field, .container_field_align, .container_field_init => { + const field = analysis.containerField(tree, node).?; try list.append(.{ - .label = handle.tree.tokenSlice(field.name_token), + .label = handle.tree.tokenSlice(field.ast.name_token), .kind = .Field, .documentation = doc, .detail = analysis.getContainerFieldSignature(handle.tree, field), }); }, - .SliceType => { - try list.append(.{ - .label = "len", - .kind = .Field, - }); - try list.append(.{ - .label = "ptr", - .kind = .Field, - }); - }, - .ArrayType => { + .array_type, .array_type_sentinel => { try list.append(.{ .label = "len", .kind = .Field, }); }, - .PtrType => { - if (config.operator_completions) { - try list.append(.{ - .label = "*", - .kind = .Operator, - }); + .ptr_type, .ptr_type_aligned, .ptr_type_bit_range, .ptr_type_sentinel => { + const ptr_type = analysis.ptrType(tree, node).?; + + switch (ptr_type.size) { + .One, .C => if (config.operator_completions) { + try list.append(.{ + .label = "*", + .kind = .Operator, + }); + }, + .Many, .Slice => return list.append(.{ .label = "len", .kind = .Field }), } - const ptr_type = node.castTag(.PtrType).?; - if (ptr_type.rhs.castTag(.ArrayType) != null) { - try list.append(.{ - .label = "len", - .kind = .Field, - }); - } else if (unwrapped) |actual_type| { + if (unwrapped) |actual_type| { try typeToCompletion(arena, list, .{ .original = actual_type }, orig_handle, config); } return; }, - .OptionalType => { + .optional_type => { if (config.operator_completions) { try list.append(.{ .label = "?", @@ -489,7 +481,7 @@ fn nodeToCompletion( } return; }, - .StringLiteral => { + .string_literal => { try list.append(.{ .label = "len", .kind = .Field, @@ -500,7 +492,7 @@ fn nodeToCompletion( .label = string, .kind = .Field, .documentation = doc, - .detail = handle.tree.getNodeSource(node), + .detail = tree.getNodeSource(node), }); }, } @@ -564,8 +556,13 @@ fn gotoDefinitionSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, de }); } -fn hoverSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, decl_handle: analysis.DeclWithHandle) (std.os.WriteError || error{OutOfMemory})!void { +fn hoverSymbol( + id: types.RequestId, + arena: *std.heap.ArenaAllocator, + decl_handle: analysis.DeclWithHandle, +) (std.os.WriteError || error{OutOfMemory})!void { const handle = decl_handle.handle; + const tree = handle.tree; const hover_kind: types.MarkupContent.Kind = if (client_capabilities.hover_supports_md) .Markdown else .PlainText; const md_string = switch (decl_handle.decl.*) { @@ -574,26 +571,20 @@ fn hoverSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, decl_handle return try hoverSymbol(id, arena, result); } - const doc_str = if (try analysis.getDocComments(&arena.allocator, handle.tree, node, hover_kind)) |str| + const doc_str = if (try analysis.getDocComments(&arena.allocator, tree, node, hover_kind)) |str| str else ""; - const signature_str = switch (node.tag) { - .VarDecl => blk: { - const var_decl = node.cast(std.zig.ast.Node.VarDecl).?; - break :blk analysis.getVariableSignature(handle.tree, var_decl); - }, - .FnProto => blk: { - const fn_decl = node.cast(std.zig.ast.Node.FnProto).?; - break :blk analysis.getFunctionSignature(handle.tree, fn_decl); - }, - .ContainerField => blk: { - const field = node.cast(std.zig.ast.Node.ContainerField).?; - break :blk analysis.getContainerFieldSignature(handle.tree, field); - }, - else => analysis.nodeToString(handle.tree, node) orelse return try respondGeneric(id, null_result_response), - }; + var buf: [1]std.zig.ast.Node.Index = undefined; + const signature_str = if (analysis.varDecl(tree, node)) |var_decl| blk: { + break :blk analysis.getVariableSignature(tree, var_decl); + } else if (analysis.fnProto(tree, node, &buf)) |fn_proto| blk: { + break :blk analysis.getFunctionSignature(tree, fn_proto); + } else if (analysis.containerField(tree, node)) |field| blk: { + break :blk analysis.getContainerFieldSignature(tree, field); + } else analysis.nodeToString(tree, node) orelse + return try respondGeneric(id, null_result_response); break :ast_node if (hover_kind == .Markdown) try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```\n{s}", .{ signature_str, doc_str }) @@ -601,31 +592,38 @@ fn hoverSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, decl_handle try std.fmt.allocPrint(&arena.allocator, "{s}\n{s}", .{ signature_str, doc_str }); }, .param_decl => |param| param_decl: { - const doc_str = if (param.doc_comments) |doc_comments| + const doc_str = if (param.first_doc_comment) |doc_comments| try analysis.collectDocComments(&arena.allocator, handle.tree, doc_comments, hover_kind) else ""; - const signature_str = handle.tree.source[handle.tree.token_locs[param.firstToken()].start..handle.tree.token_locs[param.lastToken()].end]; + const first_token = param.first_doc_comment orelse + param.comptime_noalias orelse + param.name_token orelse + param.anytype_ellipsis3 orelse + tree.firstToken(param.type_expr); + const last_token = tree.lastToken(param.type_expr); + + const signature_str = tree.source[tree.tokenLocation(0, first_token).line_start..tree.tokenLocation(0, last_token).line_end]; break :param_decl if (hover_kind == .Markdown) try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```\n{s}", .{ signature_str, doc_str }) else try std.fmt.allocPrint(&arena.allocator, "{s}\n{s}", .{ signature_str, doc_str }); }, .pointer_payload => |payload| if (hover_kind == .Markdown) - try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{handle.tree.tokenSlice(payload.node.value_symbol.firstToken())}) + try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{tree.tokenSlice(payload.name)}) else - try std.fmt.allocPrint(&arena.allocator, "{s}", .{handle.tree.tokenSlice(payload.node.value_symbol.firstToken())}), + try std.fmt.allocPrint(&arena.allocator, "{s}", .{tree.tokenSlice(payload.name)}), // .array_payload => |payload| if (hover_kind == .Markdown) // try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{handle.tree.tokenSlice(payload.identifier.firstToken())}) // else // try std.fmt.allocPrint(&arena.allocator, "{s}", .{handle.tree.tokenSlice(payload.identifier.firstToken())}), .switch_payload => |payload| if (hover_kind == .Markdown) - try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{handle.tree.tokenSlice(payload.node.value_symbol.firstToken())}) + try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{tree.tokenSlice(payload.node)}) else - try std.fmt.allocPrint(&arena.allocator, "{s}", .{handle.tree.tokenSlice(payload.node.value_symbol.firstToken())}), + try std.fmt.allocPrint(&arena.allocator, "{s}", .{tree.tokenSlice(payload.node)}), .label_decl => |label_decl| block: { - const source = handle.tree.source[handle.tree.token_locs[label_decl.firstToken()].start..handle.tree.token_locs[label_decl.lastToken()].end]; + const source = tree.tokenSlice(label_decl); break :block if (hover_kind == .Markdown) try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{source}) else diff --git a/src/offsets.zig b/src/offsets.zig index fac44ee..8201924 100644 --- a/src/offsets.zig +++ b/src/offsets.zig @@ -113,9 +113,9 @@ pub fn tokenLength(tree: std.zig.ast.Tree, token: std.zig.ast.TokenIndex, encodi if (encoding == .utf8) return token_loc.line_end - token_loc.line_start; - var i: usize = token_loc.start; + var i: usize = token_loc.line_start; var utf16_len: usize = 0; - while (i < token_loc.end) { + while (i < token_loc.line_end) { const n = std.unicode.utf8ByteSequenceLength(tree.source[i]) catch unreachable; const codepoint = std.unicode.utf8Decode(tree.source[i .. i + n]) catch unreachable; if (codepoint < 0x10000) { diff --git a/src/references.zig b/src/references.zig index 6bef4f5..73b2095 100644 --- a/src/references.zig +++ b/src/references.zig @@ -78,7 +78,7 @@ fn symbolReferencesInternal( const node = node_handle.node; const handle = node_handle.handle; - switch (node.tag) { + switch (handle.tree.nodes.items(.tag)[node]) { .ContainerDecl, .Root, .Block => { var idx: usize = 0; while (node.iterate(idx)) |child| : (idx += 1) {