diff --git a/src/analysis.zig b/src/analysis.zig index 4c97053..fd30de8 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -2186,27 +2186,62 @@ fn makeScopeInternal( .TestDecl => { return try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, node.castTag(.TestDecl).?.body_node); }, + .LabeledBlock => { + const block = node.castTag(.LabeledBlock).?; + std.debug.assert(tree.token_ids[block.label] == .Identifier); + var scope = try scopes.addOne(allocator); + scope.* = .{ + .range = .{ + .start = tree.token_locs[block.lbrace].start, + .end = tree.token_locs[block.rbrace].end, + }, + .decls = std.StringHashMap(Declaration).init(allocator), + .uses = &[0]*ast.Node.Use{}, + .tests = &[0]*ast.Node{}, + .data = .other, + }; + errdefer scope.decls.deinit(); + + try scope.decls.putNoClobber(tree.tokenSlice(block.label), .{ + .label_decl = node, + }); + + (try scopes.addOne(allocator)).* = .{ + .range = nodeSourceRange(tree, node), + .decls = std.StringHashMap(Declaration).init(allocator), + .uses = &[0]*ast.Node.Use{}, + .tests = &[0]*ast.Node{}, + .data = .{ .block = node }, + }; + var scope_idx = scopes.items.len - 1; + var uses = std.ArrayList(*ast.Node.Use).init(allocator); + + errdefer { + scopes.items[scope_idx].decls.deinit(); + uses.deinit(); + } + + var child_idx: usize = 0; + while (node.iterate(child_idx)) |child_node| : (child_idx += 1) { + if (child_node.castTag(.Use)) |use| { + try uses.append(use); + continue; + } + + try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, child_node); + if (child_node.castTag(.VarDecl)) |var_decl| { + const name = tree.tokenSlice(var_decl.name_token); + if (try scopes.items[scope_idx].decls.fetchPut(name, .{ .ast_node = child_node })) |existing| { + // TODO Record a redefinition error. + } + } + } + + scopes.items[scope_idx].uses = uses.toOwnedSlice(); + return; + }, .Block => { const block = node.castTag(.Block).?; - if (block.label) |label| { - std.debug.assert(tree.token_ids[label] == .Identifier); - var scope = try scopes.addOne(allocator); - scope.* = .{ - .range = .{ - .start = tree.token_locs[block.lbrace].start, - .end = tree.token_locs[block.rbrace].end, - }, - .decls = std.StringHashMap(Declaration).init(allocator), - .uses = &[0]*ast.Node.Use{}, - .tests = &[0]*ast.Node{}, - .data = .other, - }; - errdefer scope.decls.deinit(); - - try scope.decls.putNoClobber(tree.tokenSlice(label), .{ - .label_decl = node, - }); - } (try scopes.addOne(allocator)).* = .{ .range = nodeSourceRange(tree, node), diff --git a/src/semantic_tokens.zig b/src/semantic_tokens.zig index 4f6ff92..6b39f8b 100644 --- a/src/semantic_tokens.zig +++ b/src/semantic_tokens.zig @@ -233,11 +233,14 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D defer arena.child_allocator.free(child_frame); switch (node.tag) { - .Root, .Block => { - const first_tok = if (node.cast(ast.Node.Block)) |block_node| block: { + .Root, .Block, .LabeledBlock => { + const first_tok = if (node.castTag(.LabeledBlock)) |block_node| block: { try writeToken(builder, block_node.label, .label); break :block block_node.lbrace + 1; - } else 0; + } else if (node.castTag(.Block)) |block_node| + block_node.lbrace + 1 + else + 0; var gap_highlighter = GapHighlighter.init(builder, first_tok); var child_idx: usize = 0;