From 9b08d9e88a1c70881a0bbe9ce8f26305b5f30f47 Mon Sep 17 00:00:00 2001 From: Alexandros Naskos Date: Wed, 10 Jun 2020 19:01:44 +0300 Subject: [PATCH] Started removing scope_nodes, using symbol table instead --- src/analysis.zig | 339 ++++++++++++++--------------------------- src/document_store.zig | 45 ------ src/main.zig | 82 ++++++---- 3 files changed, 170 insertions(+), 296 deletions(-) diff --git a/src/analysis.zig b/src/analysis.zig index 5110c75..f1b06e0 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -3,23 +3,6 @@ const AnalysisContext = @import("document_store.zig").AnalysisContext; const ast = std.zig.ast; const types = @import("types.zig"); -/// REALLY BAD CODE, PLEASE DON'T USE THIS!!!!!!! (only for testing) -pub fn getFunctionByName(tree: *ast.Tree, name: []const u8) ?*ast.Node.FnProto { - var decls = tree.root_node.decls.iterator(0); - while (decls.next()) |decl_ptr| { - var decl = decl_ptr.*; - switch (decl.id) { - .FnProto => { - const func = decl.cast(ast.Node.FnProto).?; - if (std.mem.eql(u8, tree.tokenSlice(func.name_token.?), name)) return func; - }, - else => {}, - } - } - - return null; -} - /// Get a declaration's doc comment node fn getDocCommentNode(tree: *ast.Tree, node: *ast.Node) ?*ast.Node.DocComment { if (node.cast(ast.Node.FnProto)) |func| { @@ -836,213 +819,12 @@ fn makeVarDeclNode( return &var_decl_node.base; } -pub fn declsFromIndexInternal( - arena: *std.heap.ArenaAllocator, - decls: *std.ArrayList(*ast.Node), - tree: *ast.Tree, - node: *ast.Node, - source_index: usize, - innermost_container: **ast.Node, -) error{OutOfMemory}!void { - switch (node.id) { - .Root, .ContainerDecl => { - innermost_container.* = node; - var node_idx: usize = 0; - while (node.iterate(node_idx)) |child_node| : (node_idx += 1) { - // Skip over container fields, we can only dot access those. - if (child_node.id == .ContainerField) continue; - - const is_contained = nodeContainsSourceIndex(tree, child_node, source_index); - // If the cursor is in a variable decls it will insert itself anyway, we don't need to take care of it. - if ((is_contained and child_node.id != .VarDecl) or !is_contained) try decls.append(child_node); - if (is_contained) { - try declsFromIndexInternal(arena, decls, tree, child_node, source_index, innermost_container); - } - } - }, - .FnProto => { - const func = node.cast(ast.Node.FnProto).?; - - // TODO: This is a hack to enable param decls with the new parser - for (func.paramsConst()) |param| { - if (param.param_type != .type_expr or param.name_token == null) continue; - - try decls.append(try makeVarDeclNode( - &arena.allocator, - param.doc_comments, - param.comptime_token, - param.name_token.?, - param.param_type.type_expr, - null, - )); - } - - if (func.body_node) |body_node| { - if (!nodeContainsSourceIndex(tree, body_node, source_index)) return; - try declsFromIndexInternal(arena, decls, tree, body_node, source_index, innermost_container); - } - }, - .TestDecl => { - const test_decl = node.cast(ast.Node.TestDecl).?; - if (!nodeContainsSourceIndex(tree, test_decl.body_node, source_index)) return; - try declsFromIndexInternal(arena, decls, tree, test_decl.body_node, source_index, innermost_container); - }, - .Block => { - var inode_idx: usize = 0; - while (node.iterate(inode_idx)) |inode| : (inode_idx += 1) { - if (nodeComesAfterSourceIndex(tree, inode, source_index)) return; - try declsFromIndexInternal(arena, decls, tree, inode, source_index, innermost_container); - } - }, - .Comptime => { - const comptime_stmt = node.cast(ast.Node.Comptime).?; - if (nodeComesAfterSourceIndex(tree, comptime_stmt.expr, source_index)) return; - try declsFromIndexInternal(arena, decls, tree, comptime_stmt.expr, source_index, innermost_container); - }, - .If => { - const if_node = node.cast(ast.Node.If).?; - if (nodeContainsSourceIndex(tree, if_node.body, source_index)) { - if (if_node.payload) |payload| { - std.debug.assert(payload.id == .PointerPayload); - const ptr_payload = payload.cast(ast.Node.PointerPayload).?; - std.debug.assert(ptr_payload.value_symbol.id == .Identifier); - - try decls.append(try makeVarDeclNode( - &arena.allocator, - null, - null, - ptr_payload.value_symbol.firstToken(), - null, - try makeUnwrapNode(&arena.allocator, if_node.condition), - )); - } - return try declsFromIndexInternal(arena, decls, tree, if_node.body, source_index, innermost_container); - } - - if (if_node.@"else") |else_node| { - if (nodeContainsSourceIndex(tree, else_node.body, source_index)) { - if (else_node.payload) |payload| { - try declsFromIndexInternal(arena, decls, tree, payload, source_index, innermost_container); - } - return try declsFromIndexInternal(arena, decls, tree, else_node.body, source_index, innermost_container); - } - } - }, - .While => { - const while_node = node.cast(ast.Node.While).?; - if (nodeContainsSourceIndex(tree, while_node.body, source_index)) { - if (while_node.payload) |payload| { - std.debug.assert(payload.id == .PointerPayload); - const ptr_payload = payload.cast(ast.Node.PointerPayload).?; - std.debug.assert(ptr_payload.value_symbol.id == .Identifier); - - try decls.append(try makeVarDeclNode( - &arena.allocator, - null, - null, - ptr_payload.value_symbol.firstToken(), - null, - try makeUnwrapNode(&arena.allocator, while_node.condition), - )); - } - return try declsFromIndexInternal(arena, decls, tree, while_node.body, source_index, innermost_container); - } - - if (while_node.@"else") |else_node| { - if (nodeContainsSourceIndex(tree, else_node.body, source_index)) { - if (else_node.payload) |payload| { - try declsFromIndexInternal(arena, decls, tree, payload, source_index, innermost_container); - } - return try declsFromIndexInternal(arena, decls, tree, else_node.body, source_index, innermost_container); - } - } - }, - .For => { - const for_node = node.cast(ast.Node.For).?; - if (nodeContainsSourceIndex(tree, for_node.body, source_index)) { - std.debug.assert(for_node.payload.id == .PointerIndexPayload); - const ptr_idx_payload = for_node.payload.cast(ast.Node.PointerIndexPayload).?; - std.debug.assert(ptr_idx_payload.value_symbol.id == .Identifier); - try decls.append(try makeVarDeclNode( - &arena.allocator, - null, - null, - ptr_idx_payload.value_symbol.firstToken(), - null, - try makeAccessNode(&arena.allocator, for_node.array_expr), - )); - - if (ptr_idx_payload.index_symbol) |idx| { - try decls.append(idx); - } - - return try declsFromIndexInternal(arena, decls, tree, for_node.body, source_index, innermost_container); - } - - if (for_node.@"else") |else_node| { - if (nodeContainsSourceIndex(tree, else_node.body, source_index)) { - if (else_node.payload) |payload| { - try declsFromIndexInternal(arena, decls, tree, payload, source_index, innermost_container); - } - return try declsFromIndexInternal(arena, decls, tree, else_node.body, source_index, innermost_container); - } - } - }, - .Switch => { - const switch_node = node.cast(ast.Node.Switch).?; - for (switch_node.casesConst()) |case| { - const case_node = case.*.cast(ast.Node.SwitchCase).?; - if (nodeContainsSourceIndex(tree, case_node.expr, source_index)) { - if (case_node.payload) |payload| { - try declsFromIndexInternal(arena, decls, tree, payload, source_index, innermost_container); - } - return try declsFromIndexInternal(arena, decls, tree, case_node.expr, source_index, innermost_container); - } - } - }, - // TODO: These convey no type information... - .Payload => try decls.append(node.cast(ast.Node.Payload).?.error_symbol), - .PointerPayload => try decls.append(node.cast(ast.Node.PointerPayload).?.value_symbol), - // This should be completely handled for the .For code. - .PointerIndexPayload => unreachable, - .VarDecl => { - try decls.append(node); - if (node.cast(ast.Node.VarDecl).?.init_node) |child| { - if (nodeContainsSourceIndex(tree, child, source_index)) { - try declsFromIndexInternal(arena, decls, tree, child, source_index, innermost_container); - } - } - }, - .Use => {}, - else => {}, - } -} - -pub fn addChildrenNodes(decls: *std.ArrayList(*ast.Node), tree: *ast.Tree, node: *ast.Node) !void { - var node_idx: usize = 0; - while (node.iterate(node_idx)) |child_node| : (node_idx += 1) { - try decls.append(child_node); - } -} - -pub fn declsFromIndex(arena: *std.heap.ArenaAllocator, decls: *std.ArrayList(*ast.Node), tree: *ast.Tree, source_index: usize) !*ast.Node { - var innermost_container = &tree.root_node.base; - try declsFromIndexInternal(arena, decls, tree, &tree.root_node.base, source_index, &innermost_container); - return innermost_container; -} - fn nodeContainsSourceIndex(tree: *ast.Tree, node: *ast.Node, source_index: usize) bool { const first_token = tree.token_locs[node.firstToken()]; const last_token = tree.token_locs[node.lastToken()]; return source_index >= first_token.start and source_index <= last_token.end; } -fn nodeComesAfterSourceIndex(tree: *ast.Tree, node: *ast.Node, source_index: usize) bool { - const first_token = tree.token_locs[node.firstToken()]; - const last_token = tree.token_locs[node.lastToken()]; - return source_index < first_token.start; -} - pub fn getImportStr(tree: *ast.Tree, source_index: usize) ?[]const u8 { var node = &tree.root_node.base; @@ -1289,7 +1071,6 @@ pub fn getDocumentSymbols(allocator: *std.mem.Allocator, tree: *ast.Tree) ![]typ const DocumentStore = @import("document_store.zig"); -// TODO Will I need to store a handle with the nodes? pub const Declaration = union(enum) { ast_node: *ast.Node, param_decl: *ast.Node.FnProto.ParamDecl, @@ -1307,13 +1088,110 @@ pub const Declaration = union(enum) { }, }; +pub const DeclWithHandle = struct { + decl: *Declaration, + handle: *DocumentStore.Handle, + + pub fn location(self: DeclWithHandle) ast.Tree.Location { + const tree = self.handle.tree; + return switch (self.decl.*) { + .ast_node => |n| block: { + const name_token = getDeclNameToken(tree, n).?; + break :block tree.tokenLocation(0, name_token); + }, + .param_decl => |p| tree.tokenLocation(0, p.name_token.?), + .pointer_payload => |pp| tree.tokenLocation(0, pp.node.value_symbol.firstToken()), + .array_payload => |ap| tree.tokenLocation(0, ap.identifier.firstToken()), + .switch_payload => |sp| tree.tokenLocation(0, sp.node.value_symbol.firstToken()), + }; + } +}; + +pub fn iterateSymbolsGlobal( + store: *DocumentStore, + handle: *DocumentStore.Handle, + source_index: usize, + comptime callback: var, + context: var, +) !void { + for (handle.document_scope.scopes) |scope| { + if (source_index >= scope.range.start and source_index < scope.range.end) { + var decl_it = scope.decls.iterator(); + while (decl_it.next()) |entry| { + try callback(context, DeclWithHandle{ .decl = &entry.value, .handle = handle }); + } + + for (scope.uses) |use| { + // @TODO Resolve uses, iterate over their symbols. + } + } + + if (scope.range.start >= source_index) return; + } +} + +pub fn lookupSymbolGlobal(store: *DocumentStore, handle: *DocumentStore.Handle, symbol: []const u8, source_index: usize) !?DeclWithHandle { + for (handle.document_scope.scopes) |scope| { + if (source_index >= scope.range.start and source_index < scope.range.end) { + if (scope.decls.get(symbol)) |candidate| { + switch (candidate.value) { + .ast_node => |node| { + if (node.id == .ContainerField) continue; + }, + else => {}, + } + return DeclWithHandle{ + .decl = &candidate.value, + .handle = handle, + }; + } + + for (scope.uses) |use| { + // @TODO Resolve use, lookup symbol in resulting scope. + } + } + + if (scope.range.start >= source_index) return null; + } + + return null; +} + +pub fn lookupSymbolContainer(store: *DocumentScope, handle: *DocumentStore.Handle, container: *ast.Node, symbol: []const u8, accept_fields: bool) !?DeclWithHandle { + std.debug.assert(container.id == .ContainerDecl or container.id == .Root); + // Find the container scope. + var maybe_container_scope: ?*Scope = null; + for (handle.document_scope.scopes) |*scope| { + switch (scope.*) { + .container => |node| if (node == container) { + maybe_container_scope = scope; + break; + }, + } + } + + if (maybe_container_scope) |container_scope| { + if (container_scope.decls.get(symbol)) |candidate| { + switch (candidate.value) { + .ast_node => |node| { + if (node.id == .ContainerDecl and !accept_fields) return null; + }, + else => {}, + } + return &candidate.value; + } + + for (container_scope.uses) |use| { + // @TODO Resolve use, lookup symbol in resulting scope. + } + return null; + } + unreachable; +} + pub const DocumentScope = struct { scopes: []const Scope, - // TODO Methods - - // TODO When looking up a symbol, have an accept_field argument. - pub fn debugPrint(self: DocumentScope) void { for (self.scopes) |scope| { std.debug.warn( @@ -1357,11 +1235,10 @@ pub const Scope = struct { range: SourceRange, decls: std.StringHashMap(Declaration), + tests: []const *ast.Node, uses: []const *ast.Node.Use, data: Data, - - // TODO Methods }; pub fn makeDocumentScope(allocator: *std.mem.Allocator, tree: *ast.Tree) !DocumentScope { @@ -1381,6 +1258,10 @@ fn nodeSourceRange(tree: *ast.Tree, node: *ast.Node) SourceRange { }; } +// TODO Make enum and error stores per-document +// CLear the doc ones before calling this and +// rebuild them here. + fn makeScopeInternal( allocator: *std.mem.Allocator, scopes: *std.ArrayList(Scope), @@ -1398,14 +1279,17 @@ fn makeScopeInternal( .range = nodeSourceRange(tree, node), .decls = std.StringHashMap(Declaration).init(allocator), .uses = &[0]*ast.Node.Use{}, + .tests = &[0]*ast.Node{}, .data = .{ .container = node }, }; var scope_idx = scopes.items.len - 1; var uses = std.ArrayList(*ast.Node.Use).init(allocator); + var tests = std.ArrayList(*ast.Node).init(allocator); errdefer { scopes.items[scope_idx].decls.deinit(); uses.deinit(); + tests.deinit(); } for (ast_decls) |decl| { @@ -1416,6 +1300,11 @@ fn makeScopeInternal( try makeScopeInternal(allocator, scopes, tree, decl); const name = getDeclName(tree, decl) orelse continue; + if (decl.id == .TestDecl) { + try tests.append(decl); + continue; + } + if (try scopes.items[scope_idx].decls.put(name, .{ .ast_node = decl })) |existing| { // TODO Record a redefinition error. } diff --git a/src/document_store.zig b/src/document_store.zig index b657d20..4fe1429 100644 --- a/src/document_store.zig +++ b/src/document_store.zig @@ -540,8 +540,6 @@ pub const AnalysisContext = struct { // This arena is used for temporary allocations while analyzing, // not for the tree allocations. arena: *std.heap.ArenaAllocator, - scope_nodes: []*std.zig.ast.Node, - in_container: *std.zig.ast.Node, std_uri: ?[]const u8, error_completions: *TagStore, enum_completions: *TagStore, @@ -550,25 +548,6 @@ pub const AnalysisContext = struct { return self.handle.tree; } - fn refreshScopeNodes(self: *AnalysisContext) !void { - var scope_nodes = std.ArrayList(*std.zig.ast.Node).init(&self.arena.allocator); - try analysis.addChildrenNodes(&scope_nodes, self.tree(), &self.tree().root_node.base); - self.scope_nodes = scope_nodes.items; - self.in_container = &self.tree().root_node.base; - } - - pub fn onContainer(self: *AnalysisContext, container: *std.zig.ast.Node) !void { - std.debug.assert(container.id == .ContainerDecl or container.id == .Root); - - if (self.in_container != container) { - self.in_container = container; - - var scope_nodes = std.ArrayList(*std.zig.ast.Node).fromOwnedSlice(&self.arena.allocator, self.scope_nodes); - try analysis.addChildrenNodes(&scope_nodes, self.tree(), container); - 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( @@ -588,7 +567,6 @@ pub const AnalysisContext = struct { // If we did, set our new handle and return the parsed tree root node. if (std.mem.eql(u8, uri, final_uri)) { self.handle = self.store.getHandle(final_uri) orelse return null; - try self.refreshScopeNodes(); return &self.tree().root_node.base; } } @@ -603,7 +581,6 @@ pub const AnalysisContext = struct { new_handle.count += 1; self.handle = new_handle; - try self.refreshScopeNodes(); return &self.tree().root_node.base; } @@ -639,24 +616,8 @@ pub const AnalysisContext = struct { self.handle = try newDocument(self.store, duped_final_uri, file_contents); } - try self.refreshScopeNodes(); return &self.tree().root_node.base; } - - pub fn clone(self: *AnalysisContext) !AnalysisContext { - // Copy the cope nodes, the rest are references - // that are not owned by the context. - return AnalysisContext{ - .store = self.store, - .handle = self.handle, - .arena = self.arena, - .scope_nodes = try std.mem.dupe(&self.arena.allocator, *std.zig.ast.Node, self.scope_nodes), - .in_container = self.in_container, - .std_uri = self.std_uri, - .error_completions = self.error_completions, - .enum_completions = self.enum_completions, - }; - } }; pub fn stdUriFromLibPath(allocator: *std.mem.Allocator, zig_lib_path: ?[]const u8) !?[]const u8 { @@ -680,19 +641,13 @@ pub fn analysisContext( self: *DocumentStore, handle: *Handle, arena: *std.heap.ArenaAllocator, - position: usize, zig_lib_path: ?[]const u8, ) !AnalysisContext { - var scope_nodes = std.ArrayList(*std.zig.ast.Node).init(&arena.allocator); - const in_container = try analysis.declsFromIndex(arena, &scope_nodes, handle.tree, position); - const std_uri = try stdUriFromLibPath(&arena.allocator, zig_lib_path); return AnalysisContext{ .store = self, .handle = handle, .arena = arena, - .scope_nodes = scope_nodes.items, - .in_container = in_container, .std_uri = std_uri, .error_completions = &self.error_completions, .enum_completions = &self.enum_completions, diff --git a/src/main.zig b/src/main.zig index 3732310..095c820 100644 --- a/src/main.zig +++ b/src/main.zig @@ -218,8 +218,8 @@ const ResolveVarDeclFnAliasRewsult = struct { }; fn resolveVarDeclFnAlias(analysis_ctx: *DocumentStore.AnalysisContext, decl: *std.zig.ast.Node) !ResolveVarDeclFnAliasRewsult { - var child_analysis_context = try analysis_ctx.clone(); if (decl.cast(std.zig.ast.Node.VarDecl)) |var_decl| { + var child_analysis_context = analysis_ctx.*; const child_node = block: { if (var_decl.type_node) |type_node| { if (std.mem.eql(u8, "type", analysis_ctx.tree().tokenSlice(type_node.firstToken()))) { @@ -376,18 +376,26 @@ fn identifierFromPosition(pos_index: usize, handle: DocumentStore.Handle) []cons return text[start_idx + 1 .. end_idx]; } -fn gotoDefinitionSymbol(id: types.RequestId, analysis_ctx: *DocumentStore.AnalysisContext, decl: *std.zig.ast.Node) !void { - const result = try resolveVarDeclFnAlias(analysis_ctx, decl); +fn gotoDefinitionSymbol(id: types.RequestId, analysis_ctx: *DocumentStore.AnalysisContext, decl_handle: analysis.DeclWithHandle) !void { + var handle = analysis_ctx.handle; - const name_token = analysis.getDeclNameToken(result.analysis_ctx.tree(), result.decl) orelse - return try respondGeneric(id, null_result_response); + const location = switch (decl_handle.decl.*) { + .ast_node => |node| block: { + const result = try resolveVarDeclFnAlias(analysis_ctx, node); + handle = result.analysis_ctx.handle; + const name_token = analysis.getDeclNameToken(handle.tree, result.decl) orelse + return try respondGeneric(id, null_result_response); + break :block handle.tree.tokenLocation(0, name_token); + }, + else => decl_handle.location(), + }; try send(types.Response{ .id = id, .result = .{ .Location = .{ - .uri = result.analysis_ctx.handle.document.uri, - .range = astLocationToRange(result.analysis_ctx.tree().tokenLocation(0, name_token)), + .uri = handle.document.uri, + .range = astLocationToRange(location), }, }, }); @@ -424,22 +432,20 @@ fn hoverSymbol(id: types.RequestId, analysis_ctx: *DocumentStore.AnalysisContext }); } -fn getSymbolGlobal(arena: *std.heap.ArenaAllocator, pos_index: usize, handle: DocumentStore.Handle) !?*std.zig.ast.Node { - const name = identifierFromPosition(pos_index, handle); +fn getSymbolGlobal(arena: *std.heap.ArenaAllocator, pos_index: usize, handle: *DocumentStore.Handle) !?analysis.DeclWithHandle { + const name = identifierFromPosition(pos_index, handle.*); if (name.len == 0) return null; - var decl_nodes = std.ArrayList(*std.zig.ast.Node).init(&arena.allocator); - _ = try analysis.declsFromIndex(arena, &decl_nodes, handle.tree, pos_index); - - return analysis.getChildOfSlice(handle.tree, decl_nodes.items, name); + return try analysis.lookupSymbolGlobal(&document_store, handle, name, pos_index); } fn gotoDefinitionGlobal(id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: Config) !void { var arena = std.heap.ArenaAllocator.init(allocator); defer arena.deinit(); - const decl = (try getSymbolGlobal(&arena, pos_index, handle.*)) orelse return try respondGeneric(id, null_result_response); - var analysis_ctx = try document_store.analysisContext(handle, &arena, pos_index, config.zig_lib_path); + const decl = (try getSymbolGlobal(&arena, pos_index, handle)) orelse return try respondGeneric(id, null_result_response); + + var analysis_ctx = try document_store.analysisContext(decl.handle, &arena, config.zig_lib_path); return try gotoDefinitionSymbol(id, &analysis_ctx, decl); } @@ -482,7 +488,7 @@ fn gotoDefinitionFieldAccess( var arena = std.heap.ArenaAllocator.init(allocator); defer arena.deinit(); - var analysis_ctx = try document_store.analysisContext(handle, &arena, try handle.document.positionToIndex(position), config.zig_lib_path); + var analysis_ctx = try document_store.analysisContext(handle, &arena, config.zig_lib_path); const decl = (try getSymbolFieldAccess(&analysis_ctx, position, range, config)) orelse return try respondGeneric(id, null_result_response); return try gotoDefinitionSymbol(id, &analysis_ctx, decl); } @@ -530,6 +536,24 @@ fn gotoDefinitionString(id: types.RequestId, pos_index: usize, handle: *Document }); } +const DeclToCompletionContext = struct { + completions: *std.ArrayList(types.CompletionItem), + config: *const Config, + arena: *std.heap.ArenaAllocator, +}; + +fn decltoCompletion(context: DeclToCompletionContext, decl_handle: analysis.DeclWithHandle) !void { + switch (decl_handle.decl.*) { + .ast_node => |node| { + // @TODO Remove analysis context + var analysis_ctx = try document_store.analysisContext(decl_handle.handle, context.arena, context.config.zig_lib_path); + try nodeToCompletion(context.completions, &analysis_ctx, decl_handle.handle, node, context.config.*); + }, + else => {}, + // @TODO The rest + } +} + fn completeGlobal(id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: Config) !void { // We use a local arena allocator to deallocate all temporary data without iterating var arena = std.heap.ArenaAllocator.init(allocator); @@ -537,16 +561,22 @@ fn completeGlobal(id: types.RequestId, pos_index: usize, handle: *DocumentStore. // Deallocate all temporary data. defer arena.deinit(); - var analysis_ctx = try document_store.analysisContext(handle, &arena, pos_index, config.zig_lib_path); - for (analysis_ctx.scope_nodes) |decl_ptr| { - var decl = decl_ptr.*; - if (decl.id == .Use) { - std.debug.warn("Found use!", .{}); - continue; - } + const context = DeclToCompletionContext{ + .completions = &completions, + .config = &config, + .arena = &arena, + }; + try analysis.iterateSymbolsGlobal(&document_store, handle, pos_index, decltoCompletion, context); - try nodeToCompletion(&completions, &analysis_ctx, handle, decl_ptr, config); - } + // for (analysis_ctx.scope_nodes) |decl_ptr| { + // var decl = decl_ptr.*; + // if (decl.id == .Use) { + // std.debug.warn("Found use!", .{}); + // continue; + // } + + // try nodeToCompletion(&completions, &analysis_ctx, handle, decl_ptr, config); + // } try send(types.Response{ .id = id, @@ -563,7 +593,7 @@ fn completeFieldAccess(id: types.RequestId, handle: *DocumentStore.Handle, posit var arena = std.heap.ArenaAllocator.init(allocator); defer arena.deinit(); - var analysis_ctx = try document_store.analysisContext(handle, &arena, try handle.document.positionToIndex(position), config.zig_lib_path); + var analysis_ctx = try document_store.analysisContext(handle, &arena, config.zig_lib_path); var completions = std.ArrayList(types.CompletionItem).init(&arena.allocator); const line = try handle.document.getLine(@intCast(usize, position.line));