From 4ad33c16f9b0236cc23461e67067e80e35d049d0 Mon Sep 17 00:00:00 2001 From: Alexandros Naskos Date: Mon, 18 May 2020 14:26:52 +0300 Subject: [PATCH] Fixed crash when field access completing on a local variable from a type coming from an import --- src/analysis.zig | 66 +++++++++++++----------------------------- src/document_store.zig | 15 +++++++++- src/main.zig | 7 ++--- 3 files changed, 37 insertions(+), 51 deletions(-) diff --git a/src/analysis.zig b/src/analysis.zig index 91a2f00..25be7b5 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -234,7 +234,6 @@ pub fn getChildOfSlice(tree: *ast.Tree, nodes: []*ast.Node, name: []const u8) ?* /// Resolves the type of a node pub fn resolveTypeOfNode(analysis_ctx: *AnalysisContext, node: *ast.Node) ?*ast.Node { - std.debug.warn("NODE {}\n", .{node}); switch (node.id) { .VarDecl => { const vari = node.cast(ast.Node.VarDecl).?; @@ -257,9 +256,9 @@ pub fn resolveTypeOfNode(analysis_ctx: *AnalysisContext, node: *ast.Node) ?*ast. } }, .Identifier => { - // std.debug.warn("IDENTIFIER {}\n", .{analysis_ctx.tree.getNodeSource(node)}); - if (getChildOfSlice(analysis_ctx.tree, analysis_ctx.scope_nodes, analysis_ctx.tree.getNodeSource(node))) |child| { - // std.debug.warn("CHILD {}\n", .{child}); + const identifier = std.mem.dupe(&analysis_ctx.arena.allocator, u8, analysis_ctx.tree.getNodeSource(node)) catch return null; + + if (getChildOfSlice(analysis_ctx.tree, analysis_ctx.scope_nodes, identifier)) |child| { return resolveTypeOfNode(analysis_ctx, child); } else return null; }, @@ -391,9 +390,8 @@ pub fn getFieldAccessTypeNode(analysis_ctx: *AnalysisContext, tokenizer: *std.zi return current_node; }, .Identifier => { - // var root = current_node.cast(ast.Node.Root).?; - // current_node. - if (getChildOfSlice(analysis_ctx.tree, analysis_ctx.scope_nodes, tokenizer.buffer[next.start..next.end])) |child| { + const identifier = std.mem.dupe(&analysis_ctx.arena.allocator, u8, tokenizer.buffer[next.start..next.end]) catch return null; + if (getChildOfSlice(analysis_ctx.tree, analysis_ctx.scope_nodes, identifier)) |child| { if (resolveTypeOfNode(analysis_ctx, child)) |node_type| { current_node = node_type; } else return null; @@ -462,70 +460,46 @@ pub fn nodeToString(tree: *ast.Tree, node: *ast.Node) ?[]const u8 { return null; } -pub fn declsFromIndexInternal(allocator: *std.mem.Allocator, tree: *ast.Tree, node: *ast.Node, nodes: *std.ArrayList(*ast.Node)) anyerror!void { +pub fn declsFromIndexInternal(decls: *std.ArrayList(*ast.Node), tree: *ast.Tree, node: *ast.Node) anyerror!void { switch (node.id) { .FnProto => { const func = node.cast(ast.Node.FnProto).?; var param_index: usize = 0; while (param_index < func.params.len) : (param_index += 1) - try declsFromIndexInternal(allocator, tree, func.params.at(param_index).*, nodes); + try declsFromIndexInternal(decls, tree, func.params.at(param_index).*); if (func.body_node) |body_node| - try declsFromIndexInternal(allocator, tree, body_node, nodes); + try declsFromIndexInternal(decls, tree, body_node); }, .Block => { var index: usize = 0; while (node.iterate(index)) |inode| { - try declsFromIndexInternal(allocator, tree, inode, nodes); + try declsFromIndexInternal(decls, tree, inode); index += 1; } }, - .VarDecl => { - try nodes.append(node); - }, - .ParamDecl => { - try nodes.append(node); - }, - else => { - try nodes.appendSlice(try getCompletionsFromNode(allocator, tree, node)); - }, + .VarDecl, .ParamDecl => try decls.append(node), + else => try getCompletionsFromNode(decls, tree, node), } } -pub fn getCompletionsFromNode(allocator: *std.mem.Allocator, tree: *ast.Tree, node: *ast.Node) ![]*ast.Node { - var nodes = std.ArrayList(*ast.Node).init(allocator); - +pub fn getCompletionsFromNode(decls: *std.ArrayList(*ast.Node), tree: *ast.Tree, node: *ast.Node) !void { var index: usize = 0; - while (node.iterate(index)) |child_node| { - try nodes.append(child_node); - - index += 1; + while (node.iterate(index)) |child_node| : (index += 1) { + try decls.append(child_node); } - - return nodes.items; } -pub fn declsFromIndex(allocator: *std.mem.Allocator, tree: *ast.Tree, index: usize) ![]*ast.Node { - var iindex: usize = 0; - +pub fn declsFromIndex(decls: *std.ArrayList(*ast.Node), tree: *ast.Tree, index: usize) !void { var node = &tree.root_node.base; - var nodes = std.ArrayList(*ast.Node).init(allocator); - try nodes.appendSlice(try getCompletionsFromNode(allocator, tree, node)); - - while (node.iterate(iindex)) |inode| { - if (tree.tokens.at(inode.firstToken()).start < index and index < tree.tokens.at(inode.lastToken()).start) { - try declsFromIndexInternal(allocator, tree, inode, &nodes); + try getCompletionsFromNode(decls, tree, node); + var node_index: usize = 0; + while (node.iterate(node_index)) |inode| : (node_index += 1) { + if (tree.tokens.at(inode.firstToken()).start < index and index < tree.tokens.at(inode.lastToken()).end) { + try declsFromIndexInternal(decls, tree, inode); } - - iindex += 1; } - - if (tree.tokens.at(node.firstToken()).start < index and index < tree.tokens.at(node.lastToken()).start) { - return nodes.items; - } - - return nodes.items; } diff --git a/src/document_store.zig b/src/document_store.zig index 478fd08..d8e0cad 100644 --- a/src/document_store.zig +++ b/src/document_store.zig @@ -257,6 +257,12 @@ pub const AnalysisContext = struct { tree: *std.zig.ast.Tree, scope_nodes: []*std.zig.ast.Node, + fn refreshScopeNodes(self: *AnalysisContext) !void { + var scope_nodes = std.ArrayList(*std.zig.ast.Node).init(&self.arena.allocator); + try analysis.getCompletionsFromNode(&scope_nodes, self.tree, &self.tree.root_node.base); + self.scope_nodes = scope_nodes.items; + } + pub fn onImport(self: *AnalysisContext, import_str: []const u8) !?*std.zig.ast.Node { const allocator = self.store.allocator; const final_uri = (try uriFromImportStr(self.store, self.handle.*, import_str)) orelse return null; @@ -273,6 +279,7 @@ pub const AnalysisContext = struct { self.tree.deinit(); self.tree = try self.handle.tree(allocator); + try self.refreshScopeNodes(); return &self.tree.root_node.base; } } @@ -286,6 +293,7 @@ pub const AnalysisContext = struct { self.tree.deinit(); self.tree = try self.handle.tree(allocator); + try self.refreshScopeNodes(); return &self.tree.root_node.base; } @@ -325,6 +333,7 @@ pub const AnalysisContext = struct { // If we return null, no one should access the tree. self.tree.deinit(); self.tree = try self.handle.tree(allocator); + try self.refreshScopeNodes(); return &self.tree.root_node.base; } @@ -335,12 +344,16 @@ pub const AnalysisContext = struct { pub fn analysisContext(self: *DocumentStore, handle: *Handle, arena: *std.heap.ArenaAllocator, position: types.Position) !AnalysisContext { const tree = try handle.tree(self.allocator); + + var scope_nodes = std.ArrayList(*std.zig.ast.Node).init(&arena.allocator); + try analysis.declsFromIndex(&scope_nodes, tree, try handle.document.positionToIndex(position)); + return AnalysisContext{ .store = self, .handle = handle, .arena = arena, .tree = tree, - .scope_nodes = try analysis.declsFromIndex(&arena.allocator, tree, try handle.document.positionToIndex(position)) + .scope_nodes = scope_nodes.items, }; } diff --git a/src/main.zig b/src/main.zig index a5d78fe..450a430 100644 --- a/src/main.zig +++ b/src/main.zig @@ -280,9 +280,9 @@ fn completeGlobal(id: i64, pos_index: usize, handle: DocumentStore.Handle, confi // Deallocate all temporary data. defer arena.deinit(); - // var decls = tree.root_node.decls.iterator(0); - var decls = try analysis.declsFromIndex(&arena.allocator, tree, pos_index); - for (decls) |decl_ptr| { + var decl_nodes = std.ArrayList(*std.zig.ast.Node).init(&arena.allocator); + try analysis.declsFromIndex(&decl_nodes, tree, pos_index); + for (decl_nodes.items) |decl_ptr| { var decl = decl_ptr.*; try nodeToCompletion(&completions, tree, decl_ptr, config); } @@ -310,7 +310,6 @@ fn completeFieldAccess(id: i64, handle: *DocumentStore.Handle, position: types.P const line = try handle.document.getLine(@intCast(usize, position.line)); var tokenizer = std.zig.Tokenizer.init(line[line_start_idx..]); - // var decls = try analysis.declsFromIndex(&arena.allocator, analysis_ctx.tree, try handle.document.positionToIndex(position)); if (analysis.getFieldAccessTypeNode(&analysis_ctx, &tokenizer)) |node| { try nodeToCompletion(&completions, analysis_ctx.tree, node, config); }