diff --git a/README.md b/README.md index d6d5deb..ed7a195 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Building `zls` is very easy. You will need [a build of Zig master](https://zigla ```bash git clone --recurse-submodules https://github.com/zigtools/zls cd zls -zig build -Drelease-safe +zig build -Doptimize=ReleaseSafe ``` #### Build Options diff --git a/src/Server.zig b/src/Server.zig index 14863e2..99da738 100644 --- a/src/Server.zig +++ b/src/Server.zig @@ -508,7 +508,7 @@ fn autofix(server: *Server, allocator: std.mem.Allocator, handle: *const Documen }; var builder = code_actions.Builder{ - .arena = server.arena, + .arena = server.arena.allocator(), .document_store = &server.document_store, .handle = handle, .offset_encoding = server.offset_encoding, @@ -652,7 +652,6 @@ fn nodeToCompletion( }; try analysis.iterateSymbolsContainer( &server.document_store, - server.arena, node_handle, orig_handle, declToCompletion, @@ -676,7 +675,7 @@ fn nodeToCompletion( const use_snippets = server.config.enable_snippets and server.client_capabilities.supports_snippets; const insert_text = if (use_snippets) blk: { const skip_self_param = !(parent_is_type_val orelse true) and - try analysis.hasSelfParam(server.arena, &server.document_store, handle, func); + try analysis.hasSelfParam(&server.document_store, handle, func); break :blk try analysis.getFunctionSnippet(server.arena.allocator(), tree, func, skip_self_param); } else tree.tokenSlice(func.name_token.?); @@ -700,7 +699,7 @@ fn nodeToCompletion( const var_decl = tree.fullVarDecl(node).?; const is_const = token_tags[var_decl.ast.mut_token] == .keyword_const; - if (try analysis.resolveVarDeclAlias(&server.document_store, server.arena, node_handle)) |result| { + if (try analysis.resolveVarDeclAlias(&server.document_store, node_handle)) |result| { const context = DeclToCompletionContext{ .server = server, .completions = list, @@ -845,7 +844,7 @@ fn gotoDefinitionSymbol( const name_token = switch (decl_handle.decl.*) { .ast_node => |node| block: { if (resolve_alias) { - if (try analysis.resolveVarDeclAlias(&server.document_store, server.arena, .{ .node = node, .handle = handle })) |result| { + if (try analysis.resolveVarDeclAlias(&server.document_store, .{ .node = node, .handle = handle })) |result| { handle = result.handle; break :block result.nameToken(); @@ -875,7 +874,7 @@ fn hoverSymbol(server: *Server, decl_handle: analysis.DeclWithHandle) error{OutO const def_str = switch (decl_handle.decl.*) { .ast_node => |node| def: { - if (try analysis.resolveVarDeclAlias(&server.document_store, server.arena, .{ .node = node, .handle = handle })) |result| { + if (try analysis.resolveVarDeclAlias(&server.document_store, .{ .node = node, .handle = handle })) |result| { return try server.hoverSymbol(result); } doc_str = try analysis.getDocComments(server.arena.allocator(), tree, node, hover_kind); @@ -915,7 +914,8 @@ fn hoverSymbol(server: *Server, decl_handle: analysis.DeclWithHandle) error{OutO }; var bound_type_params = analysis.BoundTypeParams{}; - const resolved_type = try decl_handle.resolveType(&server.document_store, server.arena, &bound_type_params); + defer bound_type_params.deinit(server.document_store.allocator); + const resolved_type = try decl_handle.resolveType(&server.document_store, &bound_type_params); const resolved_type_str = if (resolved_type) |rt| if (rt.type.is_type_val) switch (rt.type.data) { @@ -1005,7 +1005,7 @@ fn getSymbolGlobal( const name = identifierFromPosition(pos_index, handle.*); if (name.len == 0) return null; - return try analysis.lookupSymbolGlobal(&server.document_store, server.arena, handle, name, pos_index); + return try analysis.lookupSymbolGlobal(&server.document_store, handle, name, pos_index); } fn gotoDefinitionLabel( @@ -1146,7 +1146,7 @@ fn getSymbolFieldAccess( var held_range = try server.arena.allocator().dupeZ(u8, offsets.locToSlice(handle.text, loc)); var tokenizer = std.zig.Tokenizer.init(held_range); - if (try analysis.getFieldAccessType(&server.document_store, server.arena, handle, source_index, &tokenizer)) |result| { + if (try analysis.getFieldAccessType(&server.document_store, handle, source_index, &tokenizer)) |result| { const container_handle = result.unwrapped orelse result.original; const container_handle_node = switch (container_handle.type.data) { .other => |n| n, @@ -1154,7 +1154,6 @@ fn getSymbolFieldAccess( }; return try analysis.lookupSymbolContainer( &server.document_store, - server.arena, .{ .node = container_handle_node, .handle = container_handle.handle }, name, true, @@ -1381,7 +1380,7 @@ fn completeGlobal(server: *Server, pos_index: usize, handle: *const DocumentStor .completions = &completions, .orig_handle = handle, }; - try analysis.iterateSymbolsGlobal(&server.document_store, server.arena, handle, pos_index, declToCompletion, context); + try analysis.iterateSymbolsGlobal(&server.document_store, handle, pos_index, declToCompletion, context); try populateSnippedCompletions(server.arena.allocator(), &completions, &snipped_data.generic, server.config.*, null); if (server.client_capabilities.label_details_support) { @@ -1404,7 +1403,7 @@ fn completeFieldAccess(server: *Server, handle: *const DocumentStore.Handle, sou var held_loc = try allocator.dupeZ(u8, offsets.locToSlice(handle.text, loc)); var tokenizer = std.zig.Tokenizer.init(held_loc); - const result = (try analysis.getFieldAccessType(&server.document_store, server.arena, handle, source_index, &tokenizer)) orelse return null; + const result = (try analysis.getFieldAccessType(&server.document_store, handle, source_index, &tokenizer)) orelse return null; try server.typeToCompletion(&completions, result, handle); if (server.client_capabilities.label_details_support) { for (completions.items) |*item| { @@ -2466,7 +2465,7 @@ fn generalReferencesHandler(server: *Server, request: GeneralReferencesRequest) try references.labelReferences(allocator, decl, server.offset_encoding, include_decl) else try references.symbolReferences( - server.arena, + allocator, &server.document_store, decl, server.offset_encoding, @@ -2538,7 +2537,7 @@ fn inlayHintHandler(server: *Server, request: types.InlayHintParams) Error!?[]ty // we need the regenerate hints when the document itself or its imported documents change // with caching it would also make sense to generate all hints instead of only the visible ones const hints = try inlay_hints.writeRangeInlayHint( - server.arena, + server.arena.allocator(), server.config.*, &server.document_store, handle, @@ -2589,7 +2588,7 @@ fn codeActionHandler(server: *Server, request: types.CodeActionParams) Error!?[] const handle = server.document_store.getHandle(request.textDocument.uri) orelse return null; var builder = code_actions.Builder{ - .arena = server.arena, + .arena = server.arena.allocator(), .document_store = &server.document_store, .handle = handle, .offset_encoding = server.offset_encoding, diff --git a/src/analysis.zig b/src/analysis.zig index 5dccd6f..9e3427d 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -186,7 +186,7 @@ pub fn getFunctionSnippet(allocator: std.mem.Allocator, tree: Ast, func: Ast.ful return buffer.toOwnedSlice(allocator); } -pub fn hasSelfParam(arena: *std.heap.ArenaAllocator, document_store: *DocumentStore, handle: *const DocumentStore.Handle, func: Ast.full.FnProto) !bool { +pub fn hasSelfParam(document_store: *DocumentStore, handle: *const DocumentStore.Handle, func: Ast.full.FnProto) !bool { // Non-decl prototypes cannot have a self parameter. if (func.name_token == null) return false; if (func.ast.params.len == 0) return false; @@ -199,7 +199,7 @@ pub fn hasSelfParam(arena: *std.heap.ArenaAllocator, document_store: *DocumentSt const token_starts = tree.tokens.items(.start); const in_container = innermostContainer(handle, token_starts[func.ast.fn_token]); - if (try resolveTypeOfNode(document_store, arena, .{ + if (try resolveTypeOfNode(document_store, .{ .node = param.type_expr, .handle = handle, })) |resolved_type| { @@ -208,7 +208,7 @@ pub fn hasSelfParam(arena: *std.heap.ArenaAllocator, document_store: *DocumentSt } if (ast.fullPtrType(tree, param.type_expr)) |ptr_type| { - if (try resolveTypeOfNode(document_store, arena, .{ + if (try resolveTypeOfNode(document_store, .{ .node = ptr_type.ast.child_type, .handle = handle, })) |resolved_prefix_op| { @@ -323,7 +323,7 @@ pub fn getDeclName(tree: Ast, node: Ast.Node.Index) ?[]const u8 { }; } -fn resolveVarDeclAliasInternal(store: *DocumentStore, arena: *std.heap.ArenaAllocator, node_handle: NodeWithHandle, root: bool) error{OutOfMemory}!?DeclWithHandle { +fn resolveVarDeclAliasInternal(store: *DocumentStore, node_handle: NodeWithHandle, root: bool) error{OutOfMemory}!?DeclWithHandle { _ = root; const handle = node_handle.handle; const tree = handle.tree; @@ -335,7 +335,6 @@ fn resolveVarDeclAliasInternal(store: *DocumentStore, arena: *std.heap.ArenaAllo const token = main_tokens[node_handle.node]; return try lookupSymbolGlobal( store, - arena, handle, tree.tokenSlice(token), tree.tokens.items(.start)[token], @@ -350,13 +349,13 @@ fn resolveVarDeclAliasInternal(store: *DocumentStore, arena: *std.heap.ArenaAllo if (!std.mem.eql(u8, name, "@import") and !std.mem.eql(u8, name, "@cImport")) return null; - const inner_node = (try resolveTypeOfNode(store, arena, .{ .node = lhs, .handle = handle })) orelse return null; + const inner_node = (try resolveTypeOfNode(store, .{ .node = lhs, .handle = handle })) orelse return null; // assert root node std.debug.assert(inner_node.type.data.other == 0); break :block NodeWithHandle{ .node = inner_node.type.data.other, .handle = inner_node.handle }; - } else if (try resolveVarDeclAliasInternal(store, arena, .{ .node = lhs, .handle = handle }, false)) |decl_handle| block: { + } else if (try resolveVarDeclAliasInternal(store, .{ .node = lhs, .handle = handle }, false)) |decl_handle| block: { if (decl_handle.decl.* != .ast_node) return null; - const resolved = (try resolveTypeOfNode(store, arena, .{ .node = decl_handle.decl.ast_node, .handle = decl_handle.handle })) orelse return null; + const resolved = (try resolveTypeOfNode(store, .{ .node = decl_handle.decl.ast_node, .handle = decl_handle.handle })) orelse return null; const resolved_node = switch (resolved.type.data) { .other => |n| n, else => return null, @@ -365,7 +364,7 @@ fn resolveVarDeclAliasInternal(store: *DocumentStore, arena: *std.heap.ArenaAllo break :block NodeWithHandle{ .node = resolved_node, .handle = resolved.handle }; } else return null; - return try lookupSymbolContainer(store, arena, container_node, tree.tokenSlice(datas[node_handle.node].rhs), false); + return try lookupSymbolContainer(store, container_node, tree.tokenSlice(datas[node_handle.node].rhs), false); } return null; } @@ -376,7 +375,7 @@ fn resolveVarDeclAliasInternal(store: *DocumentStore, arena: *std.heap.ArenaAllo /// const decl = @import("decl-file.zig").decl; /// const other = decl.middle.other; ///``` -pub fn resolveVarDeclAlias(store: *DocumentStore, arena: *std.heap.ArenaAllocator, decl_handle: NodeWithHandle) !?DeclWithHandle { +pub fn resolveVarDeclAlias(store: *DocumentStore, decl_handle: NodeWithHandle) !?DeclWithHandle { const decl = decl_handle.node; const handle = decl_handle.handle; const tree = handle.tree; @@ -393,7 +392,7 @@ pub fn resolveVarDeclAlias(store: *DocumentStore, arena: *std.heap.ArenaAllocato if (!std.mem.eql(u8, tree.tokenSlice(var_decl.ast.mut_token + 1), name)) return null; - return try resolveVarDeclAliasInternal(store, arena, .{ .node = base_exp, .handle = handle }, true); + return try resolveVarDeclAliasInternal(store, .{ .node = base_exp, .handle = handle }, true); } } @@ -441,7 +440,7 @@ fn findReturnStatement(tree: Ast, fn_decl: Ast.full.FnProto, body: Ast.Node.Inde return findReturnStatementInternal(tree, fn_decl, body, &already_found); } -pub fn resolveReturnType(store: *DocumentStore, arena: *std.heap.ArenaAllocator, fn_decl: Ast.full.FnProto, handle: *const DocumentStore.Handle, bound_type_params: *BoundTypeParams, fn_body: ?Ast.Node.Index) !?TypeWithHandle { +pub fn resolveReturnType(store: *DocumentStore, fn_decl: Ast.full.FnProto, handle: *const DocumentStore.Handle, bound_type_params: *BoundTypeParams, fn_body: ?Ast.Node.Index) !?TypeWithHandle { const tree = handle.tree; if (isTypeFunction(tree, fn_decl) and fn_body != null) { // If this is a type function and it only contains a single return statement that returns @@ -449,7 +448,7 @@ pub fn resolveReturnType(store: *DocumentStore, arena: *std.heap.ArenaAllocator, const ret = findReturnStatement(tree, fn_decl, fn_body.?) orelse return null; const data = tree.nodes.items(.data)[ret]; if (data.lhs != 0) { - return try resolveTypeOfNodeInternal(store, arena, .{ + return try resolveTypeOfNodeInternal(store, .{ .node = data.lhs, .handle = handle, }, bound_type_params); @@ -461,7 +460,7 @@ pub fn resolveReturnType(store: *DocumentStore, arena: *std.heap.ArenaAllocator, if (fn_decl.ast.return_type == 0) return null; const return_type = fn_decl.ast.return_type; const ret = .{ .node = return_type, .handle = handle }; - const child_type = (try resolveTypeOfNodeInternal(store, arena, ret, bound_type_params)) orelse + const child_type = (try resolveTypeOfNodeInternal(store, ret, bound_type_params)) orelse return null; const is_inferred_error = tree.tokens.items(.tag)[tree.firstToken(return_type) - 1] == .bang; @@ -478,14 +477,14 @@ pub fn resolveReturnType(store: *DocumentStore, arena: *std.heap.ArenaAllocator, } /// Resolves the child type of an optional type -fn resolveUnwrapOptionalType(store: *DocumentStore, arena: *std.heap.ArenaAllocator, opt: TypeWithHandle, bound_type_params: *BoundTypeParams) !?TypeWithHandle { +fn resolveUnwrapOptionalType(store: *DocumentStore, opt: TypeWithHandle, bound_type_params: *BoundTypeParams) !?TypeWithHandle { const opt_node = switch (opt.type.data) { .other => |n| n, else => return null, }; if (opt.handle.tree.nodes.items(.tag)[opt_node] == .optional_type) { - return ((try resolveTypeOfNodeInternal(store, arena, .{ + return ((try resolveTypeOfNodeInternal(store, .{ .node = opt.handle.tree.nodes.items(.data)[opt_node].lhs, .handle = opt.handle, }, bound_type_params)) orelse return null).instanceTypeVal(); @@ -494,7 +493,7 @@ fn resolveUnwrapOptionalType(store: *DocumentStore, arena: *std.heap.ArenaAlloca return null; } -fn resolveUnwrapErrorType(store: *DocumentStore, arena: *std.heap.ArenaAllocator, rhs: TypeWithHandle, bound_type_params: *BoundTypeParams) !?TypeWithHandle { +fn resolveUnwrapErrorType(store: *DocumentStore, rhs: TypeWithHandle, bound_type_params: *BoundTypeParams) !?TypeWithHandle { const rhs_node = switch (rhs.type.data) { .other => |n| n, .error_union => |n| return TypeWithHandle{ @@ -505,7 +504,7 @@ fn resolveUnwrapErrorType(store: *DocumentStore, arena: *std.heap.ArenaAllocator }; if (rhs.handle.tree.nodes.items(.tag)[rhs_node] == .error_union) { - return ((try resolveTypeOfNodeInternal(store, arena, .{ + return ((try resolveTypeOfNodeInternal(store, .{ .node = rhs.handle.tree.nodes.items(.data)[rhs_node].rhs, .handle = rhs.handle, }, bound_type_params)) orelse return null).instanceTypeVal(); @@ -515,7 +514,7 @@ fn resolveUnwrapErrorType(store: *DocumentStore, arena: *std.heap.ArenaAllocator } /// Resolves the child type of a deref type -fn resolveDerefType(store: *DocumentStore, arena: *std.heap.ArenaAllocator, deref: TypeWithHandle, bound_type_params: *BoundTypeParams) !?TypeWithHandle { +fn resolveDerefType(store: *DocumentStore, deref: TypeWithHandle, bound_type_params: *BoundTypeParams) !?TypeWithHandle { const deref_node = switch (deref.type.data) { .other => |n| n, .pointer => |n| return TypeWithHandle{ @@ -534,7 +533,7 @@ fn resolveDerefType(store: *DocumentStore, arena: *std.heap.ArenaAllocator, dere if (ast.fullPtrType(tree, deref_node)) |ptr_type| { switch (token_tag) { .asterisk => { - return ((try resolveTypeOfNodeInternal(store, arena, .{ + return ((try resolveTypeOfNodeInternal(store, .{ .node = ptr_type.ast.child_type, .handle = deref.handle, }, bound_type_params)) orelse return null).instanceTypeVal(); @@ -547,7 +546,7 @@ fn resolveDerefType(store: *DocumentStore, arena: *std.heap.ArenaAllocator, dere } /// Resolves slicing and array access -fn resolveBracketAccessType(store: *DocumentStore, arena: *std.heap.ArenaAllocator, lhs: TypeWithHandle, rhs: enum { Single, Range }, bound_type_params: *BoundTypeParams) !?TypeWithHandle { +fn resolveBracketAccessType(store: *DocumentStore, lhs: TypeWithHandle, rhs: enum { Single, Range }, bound_type_params: *BoundTypeParams) !?TypeWithHandle { const lhs_node = switch (lhs.type.data) { .other => |n| n, else => return null, @@ -560,7 +559,7 @@ fn resolveBracketAccessType(store: *DocumentStore, arena: *std.heap.ArenaAllocat if (tag == .array_type or tag == .array_type_sentinel) { if (rhs == .Single) - return ((try resolveTypeOfNodeInternal(store, arena, .{ + return ((try resolveTypeOfNodeInternal(store, .{ .node = data.rhs, .handle = lhs.handle, }, bound_type_params)) orelse return null).instanceTypeVal(); @@ -571,7 +570,7 @@ fn resolveBracketAccessType(store: *DocumentStore, arena: *std.heap.ArenaAllocat } else if (ast.fullPtrType(tree, lhs_node)) |ptr_type| { if (ptr_type.size == .Slice) { if (rhs == .Single) { - return ((try resolveTypeOfNodeInternal(store, arena, .{ + return ((try resolveTypeOfNodeInternal(store, .{ .node = ptr_type.ast.child_type, .handle = lhs.handle, }, bound_type_params)) orelse return null).instanceTypeVal(); @@ -584,8 +583,8 @@ fn resolveBracketAccessType(store: *DocumentStore, arena: *std.heap.ArenaAllocat } /// Called to remove one level of pointerness before a field access -pub fn resolveFieldAccessLhsType(store: *DocumentStore, arena: *std.heap.ArenaAllocator, lhs: TypeWithHandle, bound_type_params: *BoundTypeParams) !TypeWithHandle { - return (try resolveDerefType(store, arena, lhs, bound_type_params)) orelse lhs; +pub fn resolveFieldAccessLhsType(store: *DocumentStore, lhs: TypeWithHandle, bound_type_params: *BoundTypeParams) !TypeWithHandle { + return (try resolveDerefType(store, lhs, bound_type_params)) orelse lhs; } pub const BoundTypeParams = std.AutoHashMapUnmanaged(Ast.full.FnProto.Param, TypeWithHandle); @@ -623,7 +622,7 @@ pub fn isTypeIdent(text: []const u8) bool { } /// Resolves the type of a node -pub fn resolveTypeOfNodeInternal(store: *DocumentStore, arena: *std.heap.ArenaAllocator, node_handle: NodeWithHandle, bound_type_params: *BoundTypeParams) error{OutOfMemory}!?TypeWithHandle { +pub fn resolveTypeOfNodeInternal(store: *DocumentStore, node_handle: NodeWithHandle, bound_type_params: *BoundTypeParams) error{OutOfMemory}!?TypeWithHandle { // If we were asked to resolve this node before, // it is self-referential and we cannot resolve it. for (resolve_trail.items) |i| { @@ -652,14 +651,14 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, arena: *std.heap.ArenaAl const var_decl = tree.fullVarDecl(node).?; if (var_decl.ast.type_node != 0) { const decl_type = .{ .node = var_decl.ast.type_node, .handle = handle }; - if (try resolveTypeOfNodeInternal(store, arena, decl_type, bound_type_params)) |typ| + if (try resolveTypeOfNodeInternal(store, decl_type, bound_type_params)) |typ| return typ.instanceTypeVal(); } if (var_decl.ast.init_node == 0) return null; const value = .{ .node = var_decl.ast.init_node, .handle = handle }; - return try resolveTypeOfNodeInternal(store, arena, value, bound_type_params); + return try resolveTypeOfNodeInternal(store, value, bound_type_params); }, .identifier => { const name = offsets.nodeToSlice(tree, node); @@ -673,7 +672,6 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, arena: *std.heap.ArenaAl if (try lookupSymbolGlobal( store, - arena, handle, name, starts[main_tokens[node]], @@ -688,7 +686,7 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, arena: *std.heap.ArenaAl }, else => {}, } - return try child.resolveType(store, arena, bound_type_params); + return try child.resolveType(store, bound_type_params); } return null; }, @@ -705,7 +703,7 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, arena: *std.heap.ArenaAl const call = tree.fullCall(¶ms, node) orelse unreachable; const callee = .{ .node = call.ast.fn_expr, .handle = handle }; - const decl = (try resolveTypeOfNodeInternal(store, arena, callee, bound_type_params)) orelse + const decl = (try resolveTypeOfNodeInternal(store, callee, bound_type_params)) orelse return null; if (decl.type.is_type_val) return null; @@ -722,7 +720,7 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, arena: *std.heap.ArenaAl // TODO: Back-parse to extract the self argument? var it = fn_decl.iterate(&decl.handle.tree); if (token_tags[call.ast.lparen - 2] == .period) { - if (try hasSelfParam(arena, store, decl.handle, fn_decl)) { + if (try hasSelfParam(store, decl.handle, fn_decl)) { _ = ast.nextFnParam(&it); expected_params -= 1; } @@ -739,19 +737,18 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, arena: *std.heap.ArenaAl const argument = .{ .node = call.ast.params[i], .handle = handle }; const argument_type = (try resolveTypeOfNodeInternal( store, - arena, argument, bound_type_params, )) orelse continue; if (!argument_type.type.is_type_val) continue; - try bound_type_params.put(arena.allocator(), decl_param, argument_type); + try bound_type_params.put(store.allocator, decl_param, argument_type); } const has_body = decl.handle.tree.nodes.items(.tag)[decl_node] == .fn_decl; const body = decl.handle.tree.nodes.items(.data)[decl_node].rhs; - if (try resolveReturnType(store, arena, fn_decl, decl.handle, bound_type_params, if (has_body) body else null)) |ret| { + if (try resolveReturnType(store, fn_decl, decl.handle, bound_type_params, if (has_body) body else null)) |ret| { return ret; } else if (store.config.use_comptime_interpreter) { // TODO: Better case-by-case; we just use the ComptimeInterpreter when all else fails, @@ -828,7 +825,7 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, arena: *std.heap.ArenaAl .address_of, => { const base = .{ .node = datas[node].lhs, .handle = handle }; - const base_type = (try resolveTypeOfNodeInternal(store, arena, base, bound_type_params)) orelse + const base_type = (try resolveTypeOfNodeInternal(store, base, bound_type_params)) orelse return null; return switch (node_tags[node]) { .@"comptime", @@ -846,13 +843,13 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, arena: *std.heap.ArenaAl .slice, .slice_sentinel, .slice_open, - => try resolveBracketAccessType(store, arena, base_type, .Range, bound_type_params), - .deref => try resolveDerefType(store, arena, base_type, bound_type_params), - .unwrap_optional => try resolveUnwrapOptionalType(store, arena, base_type, bound_type_params), - .array_access => try resolveBracketAccessType(store, arena, base_type, .Single, bound_type_params), - .@"orelse" => try resolveUnwrapOptionalType(store, arena, base_type, bound_type_params), - .@"catch" => try resolveUnwrapErrorType(store, arena, base_type, bound_type_params), - .@"try" => try resolveUnwrapErrorType(store, arena, base_type, bound_type_params), + => try resolveBracketAccessType(store, base_type, .Range, bound_type_params), + .deref => try resolveDerefType(store, base_type, bound_type_params), + .unwrap_optional => try resolveUnwrapOptionalType(store, base_type, bound_type_params), + .array_access => try resolveBracketAccessType(store, base_type, .Single, bound_type_params), + .@"orelse" => try resolveUnwrapOptionalType(store, base_type, bound_type_params), + .@"catch" => try resolveUnwrapErrorType(store, base_type, bound_type_params), + .@"try" => try resolveUnwrapErrorType(store, base_type, bound_type_params), .address_of => { const lhs_node = switch (base_type.type.data) { .other => |n| n, @@ -872,8 +869,7 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, arena: *std.heap.ArenaAl // If we are accessing a pointer type, remove one pointerness level :) const left_type = try resolveFieldAccessLhsType( store, - arena, - (try resolveTypeOfNodeInternal(store, arena, .{ + (try resolveTypeOfNodeInternal(store, .{ .node = datas[node].lhs, .handle = handle, }, bound_type_params)) orelse return null, @@ -887,12 +883,11 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, arena: *std.heap.ArenaAl if (try lookupSymbolContainer( store, - arena, .{ .node = left_type_node, .handle = left_type.handle }, tree.tokenSlice(datas[node].rhs), !left_type.type.is_type_val, )) |child| { - return try child.resolveType(store, arena, bound_type_params); + return try child.resolveType(store, bound_type_params); } else return null; }, .array_type, @@ -946,7 +941,7 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, arena: *std.heap.ArenaAl }); if (cast_map.has(call_name)) { if (params.len < 1) return null; - return ((try resolveTypeOfNodeInternal(store, arena, .{ + return ((try resolveTypeOfNodeInternal(store, .{ .node = params[0], .handle = handle, }, bound_type_params)) orelse return null).instanceTypeVal(); @@ -956,7 +951,7 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, arena: *std.heap.ArenaAl // TODO Do peer type resolution, we just keep the first for now. if (std.mem.eql(u8, call_name, "@TypeOf")) { if (params.len < 1) return null; - var resolved_type = (try resolveTypeOfNodeInternal(store, arena, .{ + var resolved_type = (try resolveTypeOfNodeInternal(store, .{ .node = params[0], .handle = handle, }, bound_type_params)) orelse return null; @@ -967,12 +962,14 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, arena: *std.heap.ArenaAl } if (std.mem.eql(u8, call_name, "@typeInfo")) { - const zig_lib_path = try URI.fromPath(arena.allocator(), store.config.zig_lib_path orelse return null); + const zig_lib_path = try URI.fromPath(store.allocator, store.config.zig_lib_path orelse return null); + defer store.allocator.free(zig_lib_path); - const builtin_uri = URI.pathRelative(arena.allocator(), zig_lib_path, "/std/builtin.zig") catch |err| switch (err) { + const builtin_uri = URI.pathRelative(store.allocator, zig_lib_path, "/std/builtin.zig") catch |err| switch (err) { error.OutOfMemory => |e| return e, else => return null, }; + defer store.allocator.free(builtin_uri); const new_handle = store.getOrLoadHandle(builtin_uri) orelse return null; const root_scope_decls = new_handle.document_scope.scopes.items(.decls)[0]; @@ -996,7 +993,8 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, arena: *std.heap.ArenaAl if (node_tags[import_param] != .string_literal) return null; const import_str = tree.tokenSlice(main_tokens[import_param]); - const import_uri = (try store.uriFromImportStr(arena.allocator(), handle.*, import_str[1 .. import_str.len - 1])) orelse return null; + const import_uri = (try store.uriFromImportStr(store.allocator, handle.*, import_str[1 .. import_str.len - 1])) orelse return null; + defer store.allocator.free(import_uri); const new_handle = store.getOrLoadHandle(import_uri) orelse return null; @@ -1167,9 +1165,10 @@ pub const TypeWithHandle = struct { } }; -pub fn resolveTypeOfNode(store: *DocumentStore, arena: *std.heap.ArenaAllocator, node_handle: NodeWithHandle) error{OutOfMemory}!?TypeWithHandle { +pub fn resolveTypeOfNode(store: *DocumentStore, node_handle: NodeWithHandle) error{OutOfMemory}!?TypeWithHandle { var bound_type_params = BoundTypeParams{}; - return resolveTypeOfNodeInternal(store, arena, node_handle, &bound_type_params); + defer bound_type_params.deinit(store.allocator); + return resolveTypeOfNodeInternal(store, node_handle, &bound_type_params); } /// Collects all `@import`'s we can find into a slice of import paths (without quotes). @@ -1235,28 +1234,28 @@ pub const FieldAccessReturn = struct { unwrapped: ?TypeWithHandle = null, }; -pub fn getFieldAccessType(store: *DocumentStore, arena: *std.heap.ArenaAllocator, handle: *const DocumentStore.Handle, source_index: usize, tokenizer: *std.zig.Tokenizer) !?FieldAccessReturn { +pub fn getFieldAccessType(store: *DocumentStore, handle: *const DocumentStore.Handle, source_index: usize, tokenizer: *std.zig.Tokenizer) !?FieldAccessReturn { var current_type: ?TypeWithHandle = null; var bound_type_params = BoundTypeParams{}; + defer bound_type_params.deinit(store.allocator); while (true) { const tok = tokenizer.next(); switch (tok.tag) { .eof => return FieldAccessReturn{ .original = current_type orelse return null, - .unwrapped = try resolveDerefType(store, arena, current_type orelse return null, &bound_type_params), + .unwrapped = try resolveDerefType(store, current_type orelse return null, &bound_type_params), }, .identifier => { const ct_handle = if (current_type) |c| c.handle else handle; if (try lookupSymbolGlobal( store, - arena, ct_handle, tokenizer.buffer[tok.loc.start..tok.loc.end], source_index, )) |child| { - current_type = (try child.resolveType(store, arena, &bound_type_params)) orelse return null; + current_type = (try child.resolveType(store, &bound_type_params)) orelse return null; } else return null; }, .period => { @@ -1268,7 +1267,7 @@ pub fn getFieldAccessType(store: *DocumentStore, arena: *std.heap.ArenaAllocator if (ct.isFunc()) return null; return FieldAccessReturn{ .original = ct, - .unwrapped = try resolveDerefType(store, arena, ct, &bound_type_params), + .unwrapped = try resolveDerefType(store, ct, &bound_type_params), }; } else { return null; @@ -1279,14 +1278,14 @@ pub fn getFieldAccessType(store: *DocumentStore, arena: *std.heap.ArenaAllocator if (current_type) |ct| { return FieldAccessReturn{ .original = ct, - .unwrapped = try resolveDerefType(store, arena, ct, &bound_type_params), + .unwrapped = try resolveDerefType(store, ct, &bound_type_params), }; } else { return null; } } - current_type = try resolveFieldAccessLhsType(store, arena, current_type orelse return null, &bound_type_params); + current_type = try resolveFieldAccessLhsType(store, current_type orelse return null, &bound_type_params); const current_type_node = switch (current_type.?.type.data) { .other => |n| n, @@ -1295,14 +1294,12 @@ pub fn getFieldAccessType(store: *DocumentStore, arena: *std.heap.ArenaAllocator if (try lookupSymbolContainer( store, - arena, .{ .node = current_type_node, .handle = current_type.?.handle }, tokenizer.buffer[after_period.loc.start..after_period.loc.end], !current_type.?.type.is_type_val, )) |child| { current_type.? = (try child.resolveType( store, - arena, &bound_type_params, )) orelse return null; } else return null; @@ -1310,7 +1307,6 @@ pub fn getFieldAccessType(store: *DocumentStore, arena: *std.heap.ArenaAllocator .question_mark => { current_type = (try resolveUnwrapOptionalType( store, - arena, current_type orelse return null, &bound_type_params, )) orelse return null; @@ -1324,7 +1320,6 @@ pub fn getFieldAccessType(store: *DocumentStore, arena: *std.heap.ArenaAllocator .period_asterisk => { current_type = (try resolveDerefType( store, - arena, current_type orelse return null, &bound_type_params, )) orelse return null; @@ -1350,7 +1345,7 @@ pub fn getFieldAccessType(store: *DocumentStore, arena: *std.heap.ArenaAllocator const body = cur_tree.nodes.items(.data)[current_type_node].rhs; // TODO Actually bind params here when calling functions instead of just skipping args. - if (try resolveReturnType(store, arena, func, current_type.?.handle, &bound_type_params, if (has_body) body else null)) |ret| { + if (try resolveReturnType(store, func, current_type.?.handle, &bound_type_params, if (has_body) body else null)) |ret| { current_type = ret; // Skip to the right paren var paren_count: usize = 1; @@ -1381,7 +1376,7 @@ pub fn getFieldAccessType(store: *DocumentStore, arena: *std.heap.ArenaAllocator } } else return null; - current_type = (try resolveBracketAccessType(store, arena, current_type orelse return null, if (is_range) .Range else .Single, &bound_type_params)) orelse return null; + current_type = (try resolveBracketAccessType(store, current_type orelse return null, if (is_range) .Range else .Single, &bound_type_params)) orelse return null; }, else => { log.debug("Unimplemented token: {}", .{tok.tag}); @@ -1393,7 +1388,7 @@ pub fn getFieldAccessType(store: *DocumentStore, arena: *std.heap.ArenaAllocator if (current_type) |ct| { return FieldAccessReturn{ .original = ct, - .unwrapped = try resolveDerefType(store, arena, ct, &bound_type_params), + .unwrapped = try resolveDerefType(store, ct, &bound_type_params), }; } else { return null; @@ -2021,14 +2016,13 @@ pub const DeclWithHandle = struct { }; } - pub fn resolveType(self: DeclWithHandle, store: *DocumentStore, arena: *std.heap.ArenaAllocator, bound_type_params: *BoundTypeParams) !?TypeWithHandle { + pub fn resolveType(self: DeclWithHandle, store: *DocumentStore, bound_type_params: *BoundTypeParams) !?TypeWithHandle { const tree = self.handle.tree; const node_tags = tree.nodes.items(.tag); const main_tokens = tree.nodes.items(.main_token); return switch (self.decl.*) { .ast_node => |node| try resolveTypeOfNodeInternal( store, - arena, .{ .node = node, .handle = self.handle }, bound_type_params, ), @@ -2048,15 +2042,13 @@ pub const DeclWithHandle = struct { } return ((try resolveTypeOfNodeInternal( store, - arena, .{ .node = param_decl.type_expr, .handle = self.handle }, bound_type_params, )) orelse return null).instanceTypeVal(); }, .pointer_payload => |pay| try resolveUnwrapOptionalType( store, - arena, - (try resolveTypeOfNodeInternal(store, arena, .{ + (try resolveTypeOfNodeInternal(store, .{ .node = pay.condition, .handle = self.handle, }, bound_type_params)) orelse return null, @@ -2064,8 +2056,7 @@ pub const DeclWithHandle = struct { ), .array_payload => |pay| try resolveBracketAccessType( store, - arena, - (try resolveTypeOfNodeInternal(store, arena, .{ + (try resolveTypeOfNodeInternal(store, .{ .node = pay.array_expr, .handle = self.handle, }, bound_type_params)) orelse return null, @@ -2080,7 +2071,7 @@ pub const DeclWithHandle = struct { .switch_payload => |pay| { if (pay.items.len == 0) return null; // TODO Peer type resolution, we just use the first item for now. - const switch_expr_type = (try resolveTypeOfNodeInternal(store, arena, .{ + const switch_expr_type = (try resolveTypeOfNodeInternal(store, .{ .node = pay.switch_expr, .handle = self.handle, }, bound_type_params)) orelse return null; @@ -2100,7 +2091,6 @@ pub const DeclWithHandle = struct { if (container_field.ast.type_expr != 0) { return ((try resolveTypeOfNodeInternal( store, - arena, .{ .node = container_field.ast.type_expr, .handle = switch_expr_type.handle }, bound_type_params, )) orelse return null).instanceTypeVal(); @@ -2132,7 +2122,7 @@ fn findContainerScopeIndex(container_handle: NodeWithHandle) ?usize { } else null; } -fn iterateSymbolsContainerInternal(store: *DocumentStore, arena: *std.heap.ArenaAllocator, container_handle: NodeWithHandle, orig_handle: *const DocumentStore.Handle, comptime callback: anytype, context: anytype, instance_access: bool, use_trail: *std.ArrayList(Ast.Node.Index)) error{OutOfMemory}!void { +fn iterateSymbolsContainerInternal(store: *DocumentStore, container_handle: NodeWithHandle, orig_handle: *const DocumentStore.Handle, comptime callback: anytype, context: anytype, instance_access: bool, use_trail: *std.ArrayList(Ast.Node.Index)) error{OutOfMemory}!void { const container = container_handle.node; const handle = container_handle.handle; @@ -2179,7 +2169,7 @@ fn iterateSymbolsContainerInternal(store: *DocumentStore, arena: *std.heap.Arena try use_trail.append(use); const lhs = tree.nodes.items(.data)[use].lhs; - const use_expr = (try resolveTypeOfNode(store, arena, .{ + const use_expr = (try resolveTypeOfNode(store, .{ .node = lhs, .handle = handle, })) orelse continue; @@ -2190,7 +2180,6 @@ fn iterateSymbolsContainerInternal(store: *DocumentStore, arena: *std.heap.Arena }; try iterateSymbolsContainerInternal( store, - arena, .{ .node = use_expr_node, .handle = use_expr.handle }, orig_handle, callback, @@ -2231,9 +2220,10 @@ pub fn iterateEnclosingScopes(document_scope: DocumentScope, source_index: usize }; } -pub fn iterateSymbolsContainer(store: *DocumentStore, arena: *std.heap.ArenaAllocator, container_handle: NodeWithHandle, orig_handle: *const DocumentStore.Handle, comptime callback: anytype, context: anytype, instance_access: bool) error{OutOfMemory}!void { - var use_trail = std.ArrayList(Ast.Node.Index).init(arena.allocator()); - return try iterateSymbolsContainerInternal(store, arena, container_handle, orig_handle, callback, context, instance_access, &use_trail); +pub fn iterateSymbolsContainer(store: *DocumentStore, container_handle: NodeWithHandle, orig_handle: *const DocumentStore.Handle, comptime callback: anytype, context: anytype, instance_access: bool) error{OutOfMemory}!void { + var use_trail = std.ArrayList(Ast.Node.Index).init(store.allocator); + defer use_trail.deinit(); + return try iterateSymbolsContainerInternal(store, container_handle, orig_handle, callback, context, instance_access, &use_trail); } pub fn iterateLabels(handle: *const DocumentStore.Handle, source_index: usize, comptime callback: anytype, context: anytype) error{OutOfMemory}!void { @@ -2252,7 +2242,7 @@ pub fn iterateLabels(handle: *const DocumentStore.Handle, source_index: usize, c } } -fn iterateSymbolsGlobalInternal(store: *DocumentStore, arena: *std.heap.ArenaAllocator, handle: *const DocumentStore.Handle, source_index: usize, comptime callback: anytype, context: anytype, use_trail: *std.ArrayList(Ast.Node.Index)) error{OutOfMemory}!void { +fn iterateSymbolsGlobalInternal(store: *DocumentStore, handle: *const DocumentStore.Handle, source_index: usize, comptime callback: anytype, context: anytype, use_trail: *std.ArrayList(Ast.Node.Index)) error{OutOfMemory}!void { const scope_decls = handle.document_scope.scopes.items(.decls); const scope_uses = handle.document_scope.scopes.items(.uses); @@ -2272,7 +2262,6 @@ fn iterateSymbolsGlobalInternal(store: *DocumentStore, arena: *std.heap.ArenaAll const use_expr = (try resolveTypeOfNode( store, - arena, .{ .node = handle.tree.nodes.items(.data)[use].lhs, .handle = handle }, )) orelse continue; const use_expr_node = switch (use_expr.type.data) { @@ -2281,7 +2270,6 @@ fn iterateSymbolsGlobalInternal(store: *DocumentStore, arena: *std.heap.ArenaAll }; try iterateSymbolsContainerInternal( store, - arena, .{ .node = use_expr_node, .handle = use_expr.handle }, handle, callback, @@ -2293,9 +2281,10 @@ fn iterateSymbolsGlobalInternal(store: *DocumentStore, arena: *std.heap.ArenaAll } } -pub fn iterateSymbolsGlobal(store: *DocumentStore, arena: *std.heap.ArenaAllocator, handle: *const DocumentStore.Handle, source_index: usize, comptime callback: anytype, context: anytype) error{OutOfMemory}!void { - var use_trail = std.ArrayList(Ast.Node.Index).init(arena.allocator()); - return try iterateSymbolsGlobalInternal(store, arena, handle, source_index, callback, context, &use_trail); +pub fn iterateSymbolsGlobal(store: *DocumentStore, handle: *const DocumentStore.Handle, source_index: usize, comptime callback: anytype, context: anytype) error{OutOfMemory}!void { + var use_trail = std.ArrayList(Ast.Node.Index).init(store.allocator); + defer use_trail.deinit(); + return try iterateSymbolsGlobalInternal(store, handle, source_index, callback, context, &use_trail); } pub fn innermostBlockScopeIndex(handle: DocumentStore.Handle, source_index: usize) usize { @@ -2340,7 +2329,7 @@ pub fn innermostContainer(handle: *const DocumentStore.Handle, source_index: usi return TypeWithHandle.typeVal(.{ .node = current, .handle = handle }); } -fn resolveUse(store: *DocumentStore, arena: *std.heap.ArenaAllocator, uses: []const Ast.Node.Index, symbol: []const u8, handle: *const DocumentStore.Handle) error{OutOfMemory}!?DeclWithHandle { +fn resolveUse(store: *DocumentStore, uses: []const Ast.Node.Index, symbol: []const u8, handle: *const DocumentStore.Handle) error{OutOfMemory}!?DeclWithHandle { if (uses.len == 0) return null; // If we were asked to resolve this symbol before, @@ -2354,7 +2343,7 @@ fn resolveUse(store: *DocumentStore, arena: *std.heap.ArenaAllocator, uses: []co if (handle.tree.nodes.items(.data).len <= index) continue; const expr = .{ .node = handle.tree.nodes.items(.data)[index].lhs, .handle = handle }; - const expr_type_node = (try resolveTypeOfNode(store, arena, expr)) orelse + const expr_type_node = (try resolveTypeOfNode(store, expr)) orelse continue; const expr_type = .{ @@ -2365,7 +2354,7 @@ fn resolveUse(store: *DocumentStore, arena: *std.heap.ArenaAllocator, uses: []co .handle = expr_type_node.handle, }; - if (try lookupSymbolContainer(store, arena, expr_type, symbol, false)) |candidate| { + if (try lookupSymbolContainer(store, expr_type, symbol, false)) |candidate| { if (candidate.handle == handle or candidate.isPublic()) { return candidate; } @@ -2393,7 +2382,7 @@ pub fn lookupLabel(handle: *const DocumentStore.Handle, symbol: []const u8, sour return null; } -pub fn lookupSymbolGlobal(store: *DocumentStore, arena: *std.heap.ArenaAllocator, handle: *const DocumentStore.Handle, symbol: []const u8, source_index: usize) error{OutOfMemory}!?DeclWithHandle { +pub fn lookupSymbolGlobal(store: *DocumentStore, handle: *const DocumentStore.Handle, symbol: []const u8, source_index: usize) error{OutOfMemory}!?DeclWithHandle { const innermost_scope_idx = innermostBlockScopeIndex(handle.*, source_index); const scope_locs = handle.document_scope.scopes.items(.loc); @@ -2417,7 +2406,7 @@ pub fn lookupSymbolGlobal(store: *DocumentStore, arena: *std.heap.ArenaAllocator .handle = handle, }; } - if (try resolveUse(store, arena, scope_uses[curr].items, symbol, handle)) |result| return result; + if (try resolveUse(store, scope_uses[curr].items, symbol, handle)) |result| return result; } if (curr == 0) break; } @@ -2426,7 +2415,6 @@ pub fn lookupSymbolGlobal(store: *DocumentStore, arena: *std.heap.ArenaAllocator pub fn lookupSymbolContainer( store: *DocumentStore, - arena: *std.heap.ArenaAllocator, container_handle: NodeWithHandle, symbol: []const u8, /// If true, we are looking up the symbol like we are accessing through a field access @@ -2459,7 +2447,7 @@ pub fn lookupSymbolContainer( return DeclWithHandle{ .decl = candidate.value_ptr, .handle = handle }; } - if (try resolveUse(store, arena, scope_uses[container_scope_index].items, symbol, handle)) |result| return result; + if (try resolveUse(store, scope_uses[container_scope_index].items, symbol, handle)) |result| return result; } return null; diff --git a/src/code_actions.zig b/src/code_actions.zig index 2140222..a00d961 100644 --- a/src/code_actions.zig +++ b/src/code_actions.zig @@ -9,7 +9,7 @@ const types = @import("lsp.zig"); const offsets = @import("offsets.zig"); pub const Builder = struct { - arena: *std.heap.ArenaAllocator, + arena: std.mem.Allocator, document_store: *DocumentStore, handle: *const DocumentStore.Handle, offset_encoding: offsets.Encoding, @@ -54,9 +54,8 @@ pub const Builder = struct { } pub fn createWorkspaceEdit(self: *Builder, edits: []const types.TextEdit) error{OutOfMemory}!types.WorkspaceEdit { - const allocator = self.arena.allocator(); var workspace_edit = types.WorkspaceEdit{ .changes = .{} }; - try workspace_edit.changes.?.putNoClobber(allocator, self.handle.uri, try allocator.dupe(types.TextEdit, edits)); + try workspace_edit.changes.?.putNoClobber(self.arena, self.handle.uri, try self.arena.dupe(types.TextEdit, edits)); return workspace_edit; } @@ -67,7 +66,7 @@ fn handleNonCamelcaseFunction(builder: *Builder, actions: *std.ArrayListUnmanage if (std.mem.allEqual(u8, identifier_name, '_')) return; - const new_text = try createCamelcaseText(builder.arena.allocator(), identifier_name); + const new_text = try createCamelcaseText(builder.arena, identifier_name); const action1 = types.CodeAction{ .title = "make function name camelCase", @@ -76,7 +75,7 @@ fn handleNonCamelcaseFunction(builder: *Builder, actions: *std.ArrayListUnmanage .edit = try builder.createWorkspaceEdit(&.{builder.createTextEditLoc(loc, new_text)}), }; - try actions.append(builder.arena.allocator(), action1); + try actions.append(builder.arena, action1); } fn handleUnusedFunctionParameter(builder: *Builder, actions: *std.ArrayListUnmanaged(types.CodeAction), loc: offsets.Loc) !void { @@ -91,7 +90,6 @@ fn handleUnusedFunctionParameter(builder: *Builder, actions: *std.ArrayListUnman const decl = (try analysis.lookupSymbolGlobal( builder.document_store, - builder.arena, builder.handle, identifier_name, loc.start, @@ -125,7 +123,7 @@ fn handleUnusedFunctionParameter(builder: *Builder, actions: *std.ArrayListUnman .edit = try builder.createWorkspaceEdit(&.{builder.createTextEditLoc(getParamRemovalRange(tree, payload.param), "")}), }; - try actions.appendSlice(builder.arena.allocator(), &.{ action1, action2 }); + try actions.appendSlice(builder.arena, &.{ action1, action2 }); } fn handleUnusedVariableOrConstant(builder: *Builder, actions: *std.ArrayListUnmanaged(types.CodeAction), loc: offsets.Loc) !void { @@ -137,7 +135,6 @@ fn handleUnusedVariableOrConstant(builder: *Builder, actions: *std.ArrayListUnma const decl = (try analysis.lookupSymbolGlobal( builder.document_store, - builder.arena, builder.handle, identifier_name, loc.start, @@ -157,7 +154,7 @@ fn handleUnusedVariableOrConstant(builder: *Builder, actions: *std.ArrayListUnma const index = token_starts[last_token] + 1; - try actions.append(builder.arena.allocator(), .{ + try actions.append(builder.arena, .{ .title = "discard value", .kind = .@"source.fixAll", .isPreferred = true, @@ -174,7 +171,7 @@ fn handleUnusedIndexCapture(builder: *Builder, actions: *std.ArrayListUnmanaged( if (is_value_discarded) { // |_, i| -> // TODO fix formatting - try actions.append(builder.arena.allocator(), .{ + try actions.append(builder.arena, .{ .title = "remove capture", .kind = .quickfix, .isPreferred = true, @@ -183,7 +180,7 @@ fn handleUnusedIndexCapture(builder: *Builder, actions: *std.ArrayListUnmanaged( } else { // |v, i| -> |v| // |v, _| -> |v| - try actions.append(builder.arena.allocator(), .{ + try actions.append(builder.arena, .{ .title = "remove index capture", .kind = .quickfix, .isPreferred = true, @@ -202,7 +199,7 @@ fn handleUnusedCapture(builder: *Builder, actions: *std.ArrayListUnmanaged(types // by adding a discard in the block scope if (capture_locs.index != null) { // |v, i| -> |_, i| - try actions.append(builder.arena.allocator(), .{ + try actions.append(builder.arena, .{ .title = "discard capture", .kind = .quickfix, .isPreferred = true, @@ -211,7 +208,7 @@ fn handleUnusedCapture(builder: *Builder, actions: *std.ArrayListUnmanaged(types } else { // |v| -> // TODO fix formatting - try actions.append(builder.arena.allocator(), .{ + try actions.append(builder.arena, .{ .title = "remove capture", .kind = .quickfix, .isPreferred = true, @@ -223,7 +220,7 @@ fn handleUnusedCapture(builder: *Builder, actions: *std.ArrayListUnmanaged(types fn handlePointlessDiscard(builder: *Builder, actions: *std.ArrayListUnmanaged(types.CodeAction), loc: offsets.Loc) !void { const edit_loc = getDiscardLoc(builder.handle.text, loc) orelse return; - try actions.append(builder.arena.allocator(), .{ + try actions.append(builder.arena, .{ .title = "remove pointless discard", .kind = .@"source.fixAll", .isPreferred = true, @@ -300,10 +297,8 @@ fn createDiscardText(builder: *Builder, identifier_name: []const u8, declaration }; const additional_indent = if (add_block_indentation) detectIndentation(builder.handle.text) else ""; - const allocator = builder.arena.allocator(); const new_text_len = 1 + indent.len + additional_indent.len + "_ = ;".len + identifier_name.len; - var new_text = try std.ArrayListUnmanaged(u8).initCapacity(allocator, new_text_len); - errdefer new_text.deinit(allocator); + var new_text = try std.ArrayListUnmanaged(u8).initCapacity(builder.arena, new_text_len); new_text.appendAssumeCapacity('\n'); new_text.appendSliceAssumeCapacity(indent); @@ -312,7 +307,7 @@ fn createDiscardText(builder: *Builder, identifier_name: []const u8, declaration new_text.appendSliceAssumeCapacity(identifier_name); new_text.appendAssumeCapacity(';'); - return new_text.toOwnedSlice(allocator); + return new_text.toOwnedSlice(builder.arena); } fn getParamRemovalRange(tree: Ast, param: Ast.full.FnProto.Param) offsets.Loc { diff --git a/src/inlay_hints.zig b/src/inlay_hints.zig index b12c08b..725ee1d 100644 --- a/src/inlay_hints.zig +++ b/src/inlay_hints.zig @@ -24,7 +24,7 @@ pub const InlayHint = struct { }; const Builder = struct { - arena: *std.heap.ArenaAllocator, + arena: std.mem.Allocator, store: *DocumentStore, config: *const Config, handle: *const DocumentStore.Handle, @@ -38,15 +38,15 @@ const Builder = struct { const prefix = if (tooltip_noalias) if (tooltip_comptime) "noalias comptime " else "noalias " else if (tooltip_comptime) "comptime " else ""; if (self.hover_kind == .markdown) { - break :blk try std.fmt.allocPrint(self.arena.allocator(), "```zig\n{s}{s}\n```", .{ prefix, tooltip }); + break :blk try std.fmt.allocPrint(self.arena, "```zig\n{s}{s}\n```", .{ prefix, tooltip }); } - break :blk try std.fmt.allocPrint(self.arena.allocator(), "{s}{s}", .{ prefix, tooltip }); + break :blk try std.fmt.allocPrint(self.arena, "{s}{s}", .{ prefix, tooltip }); }; - try self.hints.append(self.arena.allocator(), .{ + try self.hints.append(self.arena, .{ .token_index = token_index, - .label = try std.fmt.allocPrint(self.arena.allocator(), "{s}:", .{label}), + .label = try std.fmt.allocPrint(self.arena, "{s}:", .{label}), .kind = .Parameter, .tooltip = .{ .kind = self.hover_kind, @@ -56,7 +56,7 @@ const Builder = struct { } fn toOwnedSlice(self: *Builder) error{OutOfMemory}![]InlayHint { - return self.hints.toOwnedSlice(self.arena.allocator()); + return self.hints.toOwnedSlice(self.arena); } }; @@ -81,7 +81,7 @@ fn writeCallHint(builder: *Builder, call: Ast.full.Call, decl_handle: analysis.D var i: usize = 0; var it = fn_proto.iterate(&decl_tree); - if (try analysis.hasSelfParam(builder.arena, builder.store, decl_handle.handle, fn_proto)) { + if (try analysis.hasSelfParam(builder.store, decl_handle.handle, fn_proto)) { _ = ast.nextFnParam(&it); } @@ -179,7 +179,7 @@ fn writeCallNodeHint(builder: *Builder, call: Ast.full.Call) !void { const source_index = offsets.tokenToIndex(tree, main_tokens[call.ast.fn_expr]); const name = offsets.tokenToSlice(tree, main_tokens[call.ast.fn_expr]); - if (try analysis.lookupSymbolGlobal(builder.store, builder.arena, handle, name, source_index)) |decl_handle| { + if (try analysis.lookupSymbolGlobal(builder.store, handle, name, source_index)) |decl_handle| { try writeCallHint(builder, call, decl_handle); } }, @@ -191,18 +191,17 @@ fn writeCallNodeHint(builder: *Builder, call: Ast.full.Call) !void { const start = offsets.tokenToIndex(tree, lhsToken); const rhs_loc = offsets.tokenToLoc(tree, rhsToken); - var held_range = try builder.arena.allocator().dupeZ(u8, handle.text[start..rhs_loc.end]); + var held_range = try builder.arena.dupeZ(u8, handle.text[start..rhs_loc.end]); var tokenizer = std.zig.Tokenizer.init(held_range); // note: we have the ast node, traversing it would probably yield better results // than trying to re-tokenize and re-parse it - if (try analysis.getFieldAccessType(builder.store, builder.arena, handle, rhs_loc.end, &tokenizer)) |result| { + if (try analysis.getFieldAccessType(builder.store, handle, rhs_loc.end, &tokenizer)) |result| { const container_handle = result.unwrapped orelse result.original; switch (container_handle.type.data) { .other => |container_handle_node| { if (try analysis.lookupSymbolContainer( builder.store, - builder.arena, .{ .node = container_handle_node, .handle = container_handle.handle }, tree.tokenSlice(rhsToken), true, @@ -276,7 +275,7 @@ fn writeNodeInlayHint( /// only parameter hints are created /// only hints in the given loc are created pub fn writeRangeInlayHint( - arena: *std.heap.ArenaAllocator, + arena: std.mem.Allocator, config: Config, store: *DocumentStore, handle: *const DocumentStore.Handle, @@ -292,7 +291,7 @@ pub fn writeRangeInlayHint( .hover_kind = hover_kind, }; - const nodes = try ast.nodesAtLoc(arena.allocator(), handle.tree, loc); + const nodes = try ast.nodesAtLoc(arena, handle.tree, loc); for (nodes) |child| { try writeNodeInlayHint(&builder, child); diff --git a/src/references.zig b/src/references.zig index 7d03983..433907e 100644 --- a/src/references.zig +++ b/src/references.zig @@ -54,7 +54,7 @@ pub fn labelReferences( } const Builder = struct { - arena: *std.heap.ArenaAllocator, + allocator: std.mem.Allocator, locations: std.ArrayListUnmanaged(types.Location) = .{}, /// this is the declaration we are searching for decl_handle: analysis.DeclWithHandle, @@ -66,8 +66,12 @@ const Builder = struct { handle: *const DocumentStore.Handle, }; + pub fn deinit(self: *Builder) void { + self.locations.deinit(self.allocator); + } + pub fn add(self: *Builder, handle: *const DocumentStore.Handle, token_index: Ast.TokenIndex) error{OutOfMemory}!void { - try self.locations.append(self.arena.allocator(), .{ + try self.locations.append(self.allocator, .{ .uri = handle.uri, .range = offsets.tokenToRange(handle.tree, token_index, self.encoding), }); @@ -96,7 +100,6 @@ const Builder = struct { const child = (try analysis.lookupSymbolGlobal( builder.store, - builder.arena, handle, offsets.tokenToSlice(handle.tree, identifier_token), starts[identifier_token], @@ -108,12 +111,11 @@ const Builder = struct { }, .field_access => { var bound_type_params = analysis.BoundTypeParams{}; + defer bound_type_params.deinit(builder.store.allocator); const left_type = try analysis.resolveFieldAccessLhsType( builder.store, - builder.arena, (try analysis.resolveTypeOfNodeInternal( builder.store, - builder.arena, .{ .node = datas[node].lhs, .handle = handle }, &bound_type_params, )) orelse return, @@ -127,7 +129,6 @@ const Builder = struct { const child = (try analysis.lookupSymbolContainer( builder.store, - builder.arena, .{ .node = left_type_node, .handle = left_type.handle }, offsets.tokenToSlice(handle.tree, datas[node].rhs), !left_type.type.is_type_val, @@ -143,7 +144,7 @@ const Builder = struct { }; pub fn symbolReferences( - arena: *std.heap.ArenaAllocator, + allocator: std.mem.Allocator, store: *DocumentStore, decl_handle: analysis.DeclWithHandle, encoding: offsets.Encoding, @@ -157,11 +158,12 @@ pub fn symbolReferences( std.debug.assert(decl_handle.decl.* != .label_decl); // use `labelReferences` instead var builder = Builder{ - .arena = arena, + .allocator = allocator, .store = store, .decl_handle = decl_handle, .encoding = encoding, }; + errdefer builder.deinit(); const curr_handle = decl_handle.handle; if (include_decl) try builder.add(curr_handle, decl_handle.nameToken()); @@ -178,6 +180,12 @@ pub fn symbolReferences( if (decl_handle.decl.* != .ast_node or !workspace) return builder.locations; var dependencies = std.StringArrayHashMapUnmanaged(void){}; + defer { + for (dependencies.keys()) |uri| { + allocator.free(uri); + } + dependencies.deinit(allocator); + } for (store.handles.values()) |handle| { if (skip_std_references and std.mem.indexOf(u8, handle.uri, "std") != null) { @@ -186,10 +194,17 @@ pub fn symbolReferences( } var handle_dependencies = std.ArrayListUnmanaged([]const u8){}; - try store.collectDependencies(arena.allocator(), handle.*, &handle_dependencies); + defer { + for (handle_dependencies.items) |uri| { + allocator.free(uri); + } + handle_dependencies.deinit(allocator); + } + try store.collectDependencies(allocator, handle.*, &handle_dependencies); + try dependencies.ensureUnusedCapacity(allocator, handle_dependencies.items.len); for (handle_dependencies.items) |uri| { - try dependencies.put(arena.allocator(), uri, {}); + dependencies.putAssumeCapacity(uri, {}); } } diff --git a/src/semantic_tokens.zig b/src/semantic_tokens.zig index 254f551..1a5e257 100644 --- a/src/semantic_tokens.zig +++ b/src/semantic_tokens.zig @@ -344,7 +344,7 @@ fn writeNodeTokens(builder: *Builder, maybe_node: ?Ast.Node.Index) error{OutOfMe try writeToken(builder, var_decl.comptime_token, .keyword); try writeToken(builder, var_decl.ast.mut_token, .keyword); - if (try analysis.resolveTypeOfNode(builder.store, builder.arena, .{ .node = node, .handle = handle })) |decl_type| { + if (try analysis.resolveTypeOfNode(builder.store, .{ .node = node, .handle = handle })) |decl_type| { try colorIdentifierBasedOnType(builder, decl_type, var_decl.ast.mut_token + 1, .{ .declaration = true }); } else { try writeTokenMod(builder, var_decl.ast.mut_token + 1, .variable, .{ .declaration = true }); @@ -418,7 +418,6 @@ fn writeNodeTokens(builder: *Builder, maybe_node: ?Ast.Node.Index) error{OutOfMe if (try analysis.lookupSymbolGlobal( builder.store, - builder.arena, handle, name, tree.tokens.items(.start)[main_token], @@ -427,7 +426,9 @@ fn writeNodeTokens(builder: *Builder, maybe_node: ?Ast.Node.Index) error{OutOfMe return try writeToken(builder, main_token, .parameter); } var bound_type_params = analysis.BoundTypeParams{}; - if (try child.resolveType(builder.store, builder.arena, &bound_type_params)) |decl_type| { + defer bound_type_params.deinit(builder.store.allocator); + + if (try child.resolveType(builder.store, &bound_type_params)) |decl_type| { try colorIdentifierBasedOnType(builder, decl_type, main_token, .{}); } else { try writeTokenMod(builder, main_token, .variable, .{}); @@ -628,7 +629,6 @@ fn writeNodeTokens(builder: *Builder, maybe_node: ?Ast.Node.Index) error{OutOfMe field_token_type = if (try analysis.resolveTypeOfNode( builder.store, - builder.arena, .{ .node = struct_init.ast.type_expr, .handle = handle }, )) |struct_type| switch (struct_type.type.data) { .other => |type_node| if (ast.isContainer(struct_type.handle.tree, type_node)) @@ -843,12 +843,12 @@ fn writeNodeTokens(builder: *Builder, maybe_node: ?Ast.Node.Index) error{OutOfMe // writeToken code. // Maybe we can hook into it insead? Also applies to Identifier and VarDecl var bound_type_params = analysis.BoundTypeParams{}; + defer bound_type_params.deinit(builder.store.allocator); + const lhs_type = try analysis.resolveFieldAccessLhsType( builder.store, - builder.arena, (try analysis.resolveTypeOfNodeInternal( builder.store, - builder.arena, .{ .node = data.lhs, .handle = handle }, &bound_type_params, )) orelse return, @@ -860,7 +860,6 @@ fn writeNodeTokens(builder: *Builder, maybe_node: ?Ast.Node.Index) error{OutOfMe }; if (try analysis.lookupSymbolContainer( builder.store, - builder.arena, .{ .node = left_type_node, .handle = lhs_type.handle }, tree.tokenSlice(data.rhs), !lhs_type.type.is_type_val, @@ -884,7 +883,7 @@ fn writeNodeTokens(builder: *Builder, maybe_node: ?Ast.Node.Index) error{OutOfMe else => {}, } - if (try decl_type.resolveType(builder.store, builder.arena, &bound_type_params)) |resolved_type| { + if (try decl_type.resolveType(builder.store, &bound_type_params)) |resolved_type| { try colorIdentifierBasedOnType(builder, resolved_type, data.rhs, .{}); } } diff --git a/src/signature_help.zig b/src/signature_help.zig index b14bf17..2ff44bf 100644 --- a/src/signature_help.zig +++ b/src/signature_help.zig @@ -16,7 +16,7 @@ fn fnProtoToSignatureInfo(document_store: *DocumentStore, arena: *std.heap.Arena const proto_comments = (try analysis.getDocComments(alloc, tree, fn_node, .markdown)) orelse ""; const arg_idx = if (skip_self_param) blk: { - const has_self_param = try analysis.hasSelfParam(arena, document_store, handle, proto); + const has_self_param = try analysis.hasSelfParam(document_store, handle, proto); break :blk commas + @boolToInt(has_self_param); } else commas; @@ -260,7 +260,6 @@ pub fn getSignatureInfo(document_store: *DocumentStore, arena: *std.heap.ArenaAl var tokenizer = std.zig.Tokenizer.init(held_expr); if (try analysis.getFieldAccessType( document_store, - arena, handle, expr_start, &tokenizer, @@ -296,7 +295,6 @@ pub fn getSignatureInfo(document_store: *DocumentStore, arena: *std.heap.ArenaAl const skip_self_param = !type_handle.type.is_type_val; const decl_handle = (try analysis.lookupSymbolContainer( document_store, - arena, .{ .node = node, .handle = type_handle.handle }, name, true, @@ -315,7 +313,6 @@ pub fn getSignatureInfo(document_store: *DocumentStore, arena: *std.heap.ArenaAl if (try analysis.resolveVarDeclAlias( document_store, - arena, .{ .node = node, .handle = decl_handle.handle }, )) |resolved| { switch (resolved.decl.*) {