diff --git a/src/analysis.zig b/src/analysis.zig index 0806029..c10f610 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -190,25 +190,14 @@ pub fn getChild(tree: *ast.Tree, node: *ast.Node, name: []const u8) ?*ast.Node { /// Resolves the type of a node pub fn resolveTypeOfNode(analysis_ctx: *AnalysisContext, node: *ast.Node) ?*ast.Node { - std.debug.warn("Resolving node of type {}\n{}\n", .{ node.id, analysis_ctx.tree.getNodeSource(node) }); + std.debug.warn("Resolving node of type {}\n", .{node.id}); switch (node.id) { .VarDecl => { const vari = node.cast(ast.Node.VarDecl).?; - if (vari.lib_name) |lib_name_node| { - if (nodeToString(analysis_ctx.tree, lib_name_node)) |lib_name_str| { - // if (std.mem.eql(u8, lib_name_str, "ArrayList")) { - std.debug.warn("Evaluating var decl. {}\n", .{lib_name_str}); - // } - } - } - return resolveTypeOfNode(analysis_ctx, vari.type_node orelse vari.init_node.?) orelse null; }, .FnProto => { - const func = node.cast(ast.Node.FnProto).?; - switch (func.return_type) { - .Explicit, .InferErrorSet => |return_type| return resolveTypeOfNode(analysis_ctx, return_type), - } + return node; }, .Identifier => { if (getChild(analysis_ctx.tree, &analysis_ctx.tree.root_node.base, analysis_ctx.tree.getNodeSource(node))) |child| { @@ -229,7 +218,15 @@ pub fn resolveTypeOfNode(analysis_ctx: *AnalysisContext, node: *ast.Node) ?*ast. const suffix_op = node.cast(ast.Node.SuffixOp).?; switch (suffix_op.op) { .Call => { - return resolveTypeOfNode(analysis_ctx, suffix_op.lhs.node); + const func_decl = resolveTypeOfNode(analysis_ctx, suffix_op.lhs.node) orelse return null; + + if (func_decl.id == .FnProto) { + const func = node.cast(ast.Node.FnProto).?; + switch (func.return_type) { + .Explicit, .InferErrorSet => |return_type| return resolveTypeOfNode(analysis_ctx, return_type), + } + } + return null; }, else => {}, } @@ -239,12 +236,14 @@ pub fn resolveTypeOfNode(analysis_ctx: *AnalysisContext, node: *ast.Node) ?*ast. switch (infix_op.op) { .Period => { std.debug.warn("\n\n\nPeriod\n\n\n", .{}); + std.debug.warn("InfixOp file = {}\n{}\n", .{ analysis_ctx.handle.document.uri, analysis_ctx.tree.getNodeSource(&analysis_ctx.tree.root_node.base) }); + std.debug.warn("InfixOp full = {}\n", .{analysis_ctx.tree.getNodeSource(node)}); // Save the child string from this tree since the tree may switch when processing // an import lhs. var rhs_str = nodeToString(analysis_ctx.tree, infix_op.rhs) orelse return null; + std.debug.warn("InfixOp rhs_str = {}\n", .{rhs_str}); // Use the analysis context temporary arena to store the rhs string. rhs_str = std.mem.dupe(&analysis_ctx.arena.allocator, u8, rhs_str) catch return null; - std.debug.warn("InfixOp rhs_str = {}\n", .{rhs_str}); const left = resolveTypeOfNode(analysis_ctx, infix_op.lhs) orelse return null; std.debug.warn("InfixOp left = {}\n", .{left}); const child = getChild(analysis_ctx.tree, left, rhs_str) orelse return null; @@ -272,6 +271,7 @@ pub fn resolveTypeOfNode(analysis_ctx: *AnalysisContext, node: *ast.Node) ?*ast. const builtin_call = node.cast(ast.Node.BuiltinCall).?; if (!std.mem.eql(u8, analysis_ctx.tree.tokenSlice(builtin_call.builtin_token), "@import")) return null; if (builtin_call.params.len > 1) return null; + std.debug.warn("Importing {}\n", .{analysis_ctx.tree.getNodeSource(node)}); const import_param = builtin_call.params.at(0).*; if (import_param.id != .StringLiteral) return null; diff --git a/src/document_store.zig b/src/document_store.zig index 2ad2256..89176b2 100644 --- a/src/document_store.zig +++ b/src/document_store.zig @@ -44,8 +44,8 @@ pub fn init(self: *DocumentStore, allocator: *std.mem.Allocator, zig_lib_path: ? errdefer self.handles.deinit(); if (zig_lib_path) |zpath| { - const std_path = std.fs.path.resolve(allocator, &[_][]const u8 { - zpath, "./std/std.zig" + const std_path = std.fs.path.resolve(allocator, &[_][]const u8{ + zpath, "./std/std.zig", }) catch |err| block: { std.debug.warn("Failed to resolve zig std library path, error: {}\n", .{err}); self.std_uri = null; @@ -207,11 +207,11 @@ pub fn applyChanges(self: *DocumentStore, handle: *Handle, content_changes: std. if (change.Object.getValue("range")) |range| { const start_pos = types.Position{ .line = range.Object.getValue("start").?.Object.getValue("line").?.Integer, - .character = range.Object.getValue("start").?.Object.getValue("character").?.Integer + .character = range.Object.getValue("start").?.Object.getValue("character").?.Integer, }; const end_pos = types.Position{ .line = range.Object.getValue("end").?.Object.getValue("line").?.Integer, - .character = range.Object.getValue("end").?.Object.getValue("character").?.Integer + .character = range.Object.getValue("end").?.Object.getValue("character").?.Integer, }; const change_text = change.Object.getValue("text").?.String; @@ -232,12 +232,12 @@ pub fn applyChanges(self: *DocumentStore, handle: *Handle, content_changes: std. // The first part of the string, [0 .. start_index] need not be changed. // We then copy the last part of the string, [end_index ..] to its // new position, [start_index + change_len .. ] - std.mem.copy(u8, document.mem[start_index + change_text.len..][0 .. old_len - end_index], document.mem[end_index .. old_len]); + std.mem.copy(u8, document.mem[start_index + change_text.len ..][0 .. old_len - end_index], document.mem[end_index..old_len]); // Finally, we copy the changes over. - std.mem.copy(u8, document.mem[start_index..][0 .. change_text.len], change_text); + std.mem.copy(u8, document.mem[start_index..][0..change_text.len], change_text); // Reset the text substring. - document.text = document.mem[0 .. new_len]; + document.text = document.mem[0..new_len]; } else { const change_text = change.Object.getValue("text").?.String; const old_len = document.text.len; @@ -248,8 +248,8 @@ pub fn applyChanges(self: *DocumentStore, handle: *Handle, content_changes: std. document.mem = try self.allocator.realloc(document.mem, realloc_len); } - std.mem.copy(u8, document.mem[0 .. change_text.len], change_text); - document.text = document.mem[0 .. change_text.len]; + std.mem.copy(u8, document.mem[0..change_text.len], change_text); + document.text = document.mem[0..change_text.len]; } } @@ -258,8 +258,7 @@ pub fn applyChanges(self: *DocumentStore, handle: *Handle, content_changes: std. fn uriFromImportStr(store: *DocumentStore, handle: *Handle, import_str: []const u8) !?[]const u8 { return if (std.mem.eql(u8, import_str, "std")) - if (store.std_uri) |std_root_uri| try std.mem.dupe(store.allocator, u8, std_root_uri) - else { + if (store.std_uri) |std_root_uri| try std.mem.dupe(store.allocator, u8, std_root_uri) else { std.debug.warn("Cannot resolve std library import, path is null.\n", .{}); return null; } @@ -269,8 +268,8 @@ fn uriFromImportStr(store: *DocumentStore, handle: *Handle, import_str: []const defer store.allocator.free(path); const dir_path = std.fs.path.dirname(path) orelse ""; - const import_path = try std.fs.path.resolve(store.allocator, &[_][]const u8 { - dir_path, import_str + const import_path = try std.fs.path.resolve(store.allocator, &[_][]const u8{ + dir_path, import_str, }); defer store.allocator.free(import_path); diff --git a/src/main.zig b/src/main.zig index 2e6df79..9c4fad3 100644 --- a/src/main.zig +++ b/src/main.zig @@ -285,12 +285,17 @@ fn completeFieldAccess(id: i64, handle: *DocumentStore.Handle, position: types.P var tokenizer = std.zig.Tokenizer.init(line[line_start_idx..]); if (analysis.getFieldAccessTypeNode(&analysis_ctx, &tokenizer)) |node| { + const initial_document = try std.mem.dupe(&arena.allocator, u8, analysis_ctx.handle.document.uri); var index: usize = 0; while (node.iterate(index)) |child_node| { - if (analysis.isNodePublic(analysis_ctx.tree, child_node)) { + std.debug.warn("Document uri = {}\nInitial uri = {}\n", .{ analysis_ctx.handle.document.uri, initial_document }); + std.debug.assert(std.mem.eql(u8, initial_document, analysis_ctx.handle.document.uri)); + if (analysis.isNodePublic(analysis_ctx.tree, child_node)) { // TODO: Not great to allocate it again and again inside a loop - var node_analysis_ctx = (try document_store.analysisContext(handle, &arena)) orelse { + // Creating a new context, so that we don't destroy the tree that is iterated above when resolving imports + std.debug.warn("\ncompleteFieldAccess calling resolveTypeOfNode for {}\nIn document {}\n", .{ analysis_ctx.tree.getNodeSource(child_node), analysis_ctx.handle.document.uri }); + var node_analysis_ctx = (try document_store.analysisContext(analysis_ctx.handle, &arena)) orelse { return send(types.Response{ .id = .{ .Integer = id }, .result = .{ @@ -303,9 +308,22 @@ fn completeFieldAccess(id: i64, handle: *DocumentStore.Handle, position: types.P }; defer node_analysis_ctx.deinit(); - const resolved_node = analysis.resolveTypeOfNode(&node_analysis_ctx, child_node) orelse child_node; + const resolved_node = analysis.resolveTypeOfNode(&node_analysis_ctx, child_node); + if (resolved_node) |n| { + std.debug.warn("completeFieldAccess resolveTypeOfNode result = {}\n", .{resolved_node}); + } - if (try nodeToCompletion(&arena.allocator, node_analysis_ctx.tree, resolved_node, config)) |completion| { + const completion_node: struct { node: *std.zig.ast.Node, context: *DocumentStore.AnalysisContext } = blk: { + if (resolved_node) |n| { + break :blk .{ .node = n, .context = &node_analysis_ctx }; + } + + break :blk .{ .node = child_node, .context = &analysis_ctx }; + }; + + std.debug.warn("completeFieldAccess resolved_node = {}\n", .{completion_node.context.tree.getNodeSource(completion_node.node)}); + + if (try nodeToCompletion(&arena.allocator, completion_node.context.tree, completion_node.node, config)) |completion| { try completions.append(completion); } }