Merge pull request #238 from Luukdegram/std-fixes
Update to Zig std's new AST format
This commit is contained in:
commit
2b488347ff
@ -63,6 +63,7 @@ The following options are currently available.
|
|||||||
| `build_runner_cache_path` | `?[]const u8` | `null` | Path to a directroy that will be used as zig's cache when running `zig run build_runner.zig ...`. `null` is equivalent to `${KnownFloders.Cache}/zls` |
|
| `build_runner_cache_path` | `?[]const u8` | `null` | Path to a directroy that will be used as zig's cache when running `zig run build_runner.zig ...`. `null` is equivalent to `${KnownFloders.Cache}/zls` |
|
||||||
| `enable_semantic_tokens` | `bool` | `true` | Enables semantic token support when the client also supports it. |
|
| `enable_semantic_tokens` | `bool` | `true` | Enables semantic token support when the client also supports it. |
|
||||||
| `operator_completions` | `bool` | `true` | Enables `*` and `?` operators in completion lists. |
|
| `operator_completions` | `bool` | `true` | Enables `*` and `?` operators in completion lists. |
|
||||||
|
| `skip_std_references` | `bool` | `false` | When true, skips searching for references in std. Improves lookup speed for functions in user's code. Renaming and go-to-definition will continue to work as is.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
2559
src/analysis.zig
2559
src/analysis.zig
File diff suppressed because it is too large
Load Diff
@ -25,3 +25,7 @@ enable_semantic_tokens: bool = true,
|
|||||||
|
|
||||||
/// Whether to enable `*` and `?` operators in completion lists
|
/// Whether to enable `*` and `?` operators in completion lists
|
||||||
operator_completions: bool = true,
|
operator_completions: bool = true,
|
||||||
|
|
||||||
|
/// Skips references to std. This will improve lookup speeds.
|
||||||
|
/// Going to definition however will continue to work
|
||||||
|
skip_std_references: bool = false,
|
||||||
|
@ -22,7 +22,7 @@ pub const Handle = struct {
|
|||||||
document: types.TextDocument,
|
document: types.TextDocument,
|
||||||
count: usize,
|
count: usize,
|
||||||
import_uris: std.ArrayList([]const u8),
|
import_uris: std.ArrayList([]const u8),
|
||||||
tree: *std.zig.ast.Tree,
|
tree: std.zig.ast.Tree,
|
||||||
document_scope: analysis.DocumentScope,
|
document_scope: analysis.DocumentScope,
|
||||||
|
|
||||||
associated_build_file: ?*BuildFile,
|
associated_build_file: ?*BuildFile,
|
||||||
@ -143,8 +143,8 @@ fn newDocument(self: *DocumentStore, uri: []const u8, text: []u8) anyerror!*Hand
|
|||||||
var handle = try self.allocator.create(Handle);
|
var handle = try self.allocator.create(Handle);
|
||||||
errdefer self.allocator.destroy(handle);
|
errdefer self.allocator.destroy(handle);
|
||||||
|
|
||||||
const tree = try std.zig.parse(self.allocator, text);
|
var tree = try std.zig.parse(self.allocator, text);
|
||||||
errdefer tree.deinit();
|
errdefer tree.deinit(self.allocator);
|
||||||
|
|
||||||
const document_scope = try analysis.makeDocumentScope(self.allocator, tree);
|
const document_scope = try analysis.makeDocumentScope(self.allocator, tree);
|
||||||
errdefer document_scope.deinit(self.allocator);
|
errdefer document_scope.deinit(self.allocator);
|
||||||
@ -326,7 +326,7 @@ fn decrementCount(self: *DocumentStore, uri: []const u8) void {
|
|||||||
self.decrementBuildFileRefs(build_file);
|
self.decrementBuildFileRefs(build_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
entry.value.tree.deinit();
|
entry.value.tree.deinit(self.allocator);
|
||||||
self.allocator.free(entry.value.document.mem);
|
self.allocator.free(entry.value.document.mem);
|
||||||
|
|
||||||
for (entry.value.import_uris.items) |import_uri| {
|
for (entry.value.import_uris.items) |import_uri| {
|
||||||
@ -354,7 +354,7 @@ pub fn getHandle(self: *DocumentStore, uri: []const u8) ?*Handle {
|
|||||||
// Check if the document text is now sane, move it to sane_text if so.
|
// Check if the document text is now sane, move it to sane_text if so.
|
||||||
fn refreshDocument(self: *DocumentStore, handle: *Handle, zig_lib_path: ?[]const u8) !void {
|
fn refreshDocument(self: *DocumentStore, handle: *Handle, zig_lib_path: ?[]const u8) !void {
|
||||||
log.debug("New text for document {s}", .{handle.uri()});
|
log.debug("New text for document {s}", .{handle.uri()});
|
||||||
handle.tree.deinit();
|
handle.tree.deinit(self.allocator);
|
||||||
handle.tree = try std.zig.parse(self.allocator, handle.document.text);
|
handle.tree = try std.zig.parse(self.allocator, handle.document.text);
|
||||||
|
|
||||||
handle.document_scope.deinit(self.allocator);
|
handle.document_scope.deinit(self.allocator);
|
||||||
@ -613,7 +613,7 @@ pub fn deinit(self: *DocumentStore) void {
|
|||||||
var entry_iterator = self.handles.iterator();
|
var entry_iterator = self.handles.iterator();
|
||||||
while (entry_iterator.next()) |entry| {
|
while (entry_iterator.next()) |entry| {
|
||||||
entry.value.document_scope.deinit(self.allocator);
|
entry.value.document_scope.deinit(self.allocator);
|
||||||
entry.value.tree.deinit();
|
entry.value.tree.deinit(self.allocator);
|
||||||
self.allocator.free(entry.value.document.mem);
|
self.allocator.free(entry.value.document.mem);
|
||||||
|
|
||||||
for (entry.value.import_uris.items) |uri| {
|
for (entry.value.import_uris.items) |uri| {
|
||||||
|
282
src/main.zig
282
src/main.zig
@ -199,8 +199,8 @@ fn publishDiagnostics(arena: *std.heap.ArenaAllocator, handle: DocumentStore.Han
|
|||||||
|
|
||||||
var diagnostics = std.ArrayList(types.Diagnostic).init(&arena.allocator);
|
var diagnostics = std.ArrayList(types.Diagnostic).init(&arena.allocator);
|
||||||
|
|
||||||
for (tree.errors) |*err| {
|
for (tree.errors) |err| {
|
||||||
const loc = tree.tokenLocation(0, err.loc());
|
const loc = tree.tokenLocation(0, err.token);
|
||||||
|
|
||||||
var mem_buffer: [256]u8 = undefined;
|
var mem_buffer: [256]u8 = undefined;
|
||||||
var fbs = std.io.fixedBufferStream(&mem_buffer);
|
var fbs = std.io.fixedBufferStream(&mem_buffer);
|
||||||
@ -209,7 +209,7 @@ fn publishDiagnostics(arena: *std.heap.ArenaAllocator, handle: DocumentStore.Han
|
|||||||
try diagnostics.append(.{
|
try diagnostics.append(.{
|
||||||
.range = astLocationToRange(loc),
|
.range = astLocationToRange(loc),
|
||||||
.severity = .Error,
|
.severity = .Error,
|
||||||
.code = @tagName(err.*),
|
.code = @tagName(err.tag),
|
||||||
.source = "zls",
|
.source = "zls",
|
||||||
.message = try std.mem.dupe(&arena.allocator, u8, fbs.getWritten()),
|
.message = try std.mem.dupe(&arena.allocator, u8, fbs.getWritten()),
|
||||||
// .relatedInformation = undefined
|
// .relatedInformation = undefined
|
||||||
@ -217,16 +217,21 @@ fn publishDiagnostics(arena: *std.heap.ArenaAllocator, handle: DocumentStore.Han
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tree.errors.len == 0) {
|
if (tree.errors.len == 0) {
|
||||||
for (tree.root_node.decls()) |decl| {
|
for (tree.rootDecls()) |decl_idx| {
|
||||||
switch (decl.tag) {
|
const decl = tree.nodes.items(.tag)[decl_idx];
|
||||||
.FnProto => blk: {
|
switch (decl) {
|
||||||
const func = decl.cast(std.zig.ast.Node.FnProto).?;
|
.fn_proto,
|
||||||
const is_extern = func.getExternExportInlineToken() != null;
|
.fn_proto_multi,
|
||||||
if (is_extern)
|
.fn_proto_one,
|
||||||
break :blk;
|
.fn_proto_simple,
|
||||||
|
.fn_decl,
|
||||||
|
=> blk: {
|
||||||
|
var buf: [1]std.zig.ast.Node.Index = undefined;
|
||||||
|
const func = analysis.fnProto(tree, decl_idx, &buf).?;
|
||||||
|
if (func.extern_export_token != null) break :blk;
|
||||||
|
|
||||||
if (config.warn_style) {
|
if (config.warn_style) {
|
||||||
if (func.getNameToken()) |name_token| {
|
if (func.name_token) |name_token| {
|
||||||
const loc = tree.tokenLocation(0, name_token);
|
const loc = tree.tokenLocation(0, name_token);
|
||||||
|
|
||||||
const is_type_function = analysis.isTypeFunction(tree, func);
|
const is_type_function = analysis.isTypeFunction(tree, func);
|
||||||
@ -331,6 +336,10 @@ fn nodeToCompletion(
|
|||||||
) error{OutOfMemory}!void {
|
) error{OutOfMemory}!void {
|
||||||
const node = node_handle.node;
|
const node = node_handle.node;
|
||||||
const handle = node_handle.handle;
|
const handle = node_handle.handle;
|
||||||
|
const tree = handle.tree;
|
||||||
|
const node_tags = tree.nodes.items(.tag);
|
||||||
|
const datas = tree.nodes.items(.data);
|
||||||
|
const token_tags = tree.tokens.items(.tag);
|
||||||
|
|
||||||
const doc_kind: types.MarkupContent.Kind = if (client_capabilities.completion_doc_supports_md)
|
const doc_kind: types.MarkupContent.Kind = if (client_capabilities.completion_doc_supports_md)
|
||||||
.Markdown
|
.Markdown
|
||||||
@ -350,7 +359,7 @@ fn nodeToCompletion(
|
|||||||
else
|
else
|
||||||
null;
|
null;
|
||||||
|
|
||||||
if (node.tag == .ErrorSetDecl or node.tag == .Root or node.tag == .ContainerDecl) {
|
if (analysis.isContainer(node_tags[node])) {
|
||||||
const context = DeclToCompletionContext{
|
const context = DeclToCompletionContext{
|
||||||
.completions = list,
|
.completions = list,
|
||||||
.config = &config,
|
.config = &config,
|
||||||
@ -362,30 +371,39 @@ fn nodeToCompletion(
|
|||||||
|
|
||||||
if (is_type_val) return;
|
if (is_type_val) return;
|
||||||
|
|
||||||
switch (node.tag) {
|
switch (node_tags[node]) {
|
||||||
.FnProto => {
|
.fn_proto,
|
||||||
const func = node.cast(std.zig.ast.Node.FnProto).?;
|
.fn_proto_multi,
|
||||||
if (func.getNameToken()) |name_token| {
|
.fn_proto_one,
|
||||||
|
.fn_proto_simple,
|
||||||
|
.fn_decl,
|
||||||
|
=> {
|
||||||
|
var buf: [1]std.zig.ast.Node.Index = undefined;
|
||||||
|
const func = analysis.fnProto(tree, node, &buf).?;
|
||||||
|
if (func.name_token) |name_token| {
|
||||||
const use_snippets = config.enable_snippets and client_capabilities.supports_snippets;
|
const use_snippets = config.enable_snippets and client_capabilities.supports_snippets;
|
||||||
|
|
||||||
const insert_text = if (use_snippets) blk: {
|
const insert_text = if (use_snippets) blk: {
|
||||||
// TODO Also check if we are dot accessing from a type val and dont skip in that case.
|
// TODO Also check if we are dot accessing from a type val and dont skip in that case.
|
||||||
const skip_self_param = if (func.params_len > 0) param_check: {
|
const skip_self_param = if (func.ast.params.len > 0) param_check: {
|
||||||
const in_container = analysis.innermostContainer(handle, handle.tree.token_locs[func.firstToken()].start);
|
const in_container = analysis.innermostContainer(handle, tree.tokens.items(.start)[func.ast.fn_token]);
|
||||||
|
|
||||||
|
var it = func.iterate(tree);
|
||||||
|
const param = it.next().?;
|
||||||
|
|
||||||
|
if (param.type_expr == 0) break :param_check false;
|
||||||
|
|
||||||
switch (func.paramsConst()[0].param_type) {
|
|
||||||
.type_expr => |type_node| {
|
|
||||||
if (try analysis.resolveTypeOfNode(&document_store, arena, .{
|
if (try analysis.resolveTypeOfNode(&document_store, arena, .{
|
||||||
.node = type_node,
|
.node = param.type_expr,
|
||||||
.handle = handle,
|
.handle = handle,
|
||||||
})) |resolved_type| {
|
})) |resolved_type| {
|
||||||
if (std.meta.eql(in_container, resolved_type))
|
if (std.meta.eql(in_container, resolved_type))
|
||||||
break :param_check true;
|
break :param_check true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type_node.castTag(.PtrType)) |ptr_type| {
|
if (analysis.isPtrType(tree, param.type_expr)) {
|
||||||
if (try analysis.resolveTypeOfNode(&document_store, arena, .{
|
if (try analysis.resolveTypeOfNode(&document_store, arena, .{
|
||||||
.node = ptr_type.rhs,
|
.node = datas[param.type_expr].rhs,
|
||||||
.handle = handle,
|
.handle = handle,
|
||||||
})) |resolved_prefix_op| {
|
})) |resolved_prefix_op| {
|
||||||
if (std.meta.eql(in_container, resolved_prefix_op))
|
if (std.meta.eql(in_container, resolved_prefix_op))
|
||||||
@ -394,15 +412,10 @@ fn nodeToCompletion(
|
|||||||
}
|
}
|
||||||
|
|
||||||
break :param_check false;
|
break :param_check false;
|
||||||
},
|
} else false;
|
||||||
else => break :param_check false,
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
false;
|
|
||||||
|
|
||||||
break :blk try analysis.getFunctionSnippet(&arena.allocator, handle.tree, func, skip_self_param);
|
break :blk try analysis.getFunctionSnippet(&arena.allocator, tree, func, skip_self_param);
|
||||||
} else
|
} else null;
|
||||||
null;
|
|
||||||
|
|
||||||
const is_type_function = analysis.isTypeFunction(handle.tree, func);
|
const is_type_function = analysis.isTypeFunction(handle.tree, func);
|
||||||
|
|
||||||
@ -416,9 +429,13 @@ fn nodeToCompletion(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.VarDecl => {
|
.global_var_decl,
|
||||||
const var_decl = node.cast(std.zig.ast.Node.VarDecl).?;
|
.local_var_decl,
|
||||||
const is_const = handle.tree.token_ids[var_decl.mut_token] == .Keyword_const;
|
.aligned_var_decl,
|
||||||
|
.simple_var_decl,
|
||||||
|
=> {
|
||||||
|
const var_decl = analysis.varDecl(tree, node).?;
|
||||||
|
const is_const = token_tags[var_decl.ast.mut_token] == .keyword_const;
|
||||||
|
|
||||||
if (try analysis.resolveVarDeclAlias(&document_store, arena, node_handle)) |result| {
|
if (try analysis.resolveVarDeclAlias(&document_store, arena, node_handle)) |result| {
|
||||||
const context = DeclToCompletionContext{
|
const context = DeclToCompletionContext{
|
||||||
@ -431,57 +448,59 @@ fn nodeToCompletion(
|
|||||||
}
|
}
|
||||||
|
|
||||||
try list.append(.{
|
try list.append(.{
|
||||||
.label = handle.tree.tokenSlice(var_decl.name_token),
|
.label = handle.tree.tokenSlice(var_decl.ast.mut_token + 1),
|
||||||
.kind = if (is_const) .Constant else .Variable,
|
.kind = if (is_const) .Constant else .Variable,
|
||||||
.documentation = doc,
|
.documentation = doc,
|
||||||
.detail = analysis.getVariableSignature(handle.tree, var_decl),
|
.detail = analysis.getVariableSignature(tree, var_decl),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.ContainerField => {
|
.container_field,
|
||||||
const field = node.cast(std.zig.ast.Node.ContainerField).?;
|
.container_field_align,
|
||||||
|
.container_field_init,
|
||||||
|
=> {
|
||||||
|
const field = analysis.containerField(tree, node).?;
|
||||||
try list.append(.{
|
try list.append(.{
|
||||||
.label = handle.tree.tokenSlice(field.name_token),
|
.label = handle.tree.tokenSlice(field.ast.name_token),
|
||||||
.kind = .Field,
|
.kind = .Field,
|
||||||
.documentation = doc,
|
.documentation = doc,
|
||||||
.detail = analysis.getContainerFieldSignature(handle.tree, field),
|
.detail = analysis.getContainerFieldSignature(handle.tree, field),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.SliceType => {
|
.array_type,
|
||||||
try list.append(.{
|
.array_type_sentinel,
|
||||||
.label = "len",
|
=> {
|
||||||
.kind = .Field,
|
|
||||||
});
|
|
||||||
try list.append(.{
|
|
||||||
.label = "ptr",
|
|
||||||
.kind = .Field,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
.ArrayType => {
|
|
||||||
try list.append(.{
|
try list.append(.{
|
||||||
.label = "len",
|
.label = "len",
|
||||||
.kind = .Field,
|
.kind = .Field,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.PtrType => {
|
.ptr_type,
|
||||||
if (config.operator_completions) {
|
.ptr_type_aligned,
|
||||||
|
.ptr_type_bit_range,
|
||||||
|
.ptr_type_sentinel,
|
||||||
|
=> {
|
||||||
|
const ptr_type = analysis.ptrType(tree, node).?;
|
||||||
|
|
||||||
|
switch (ptr_type.size) {
|
||||||
|
.One, .C, .Many => if (config.operator_completions) {
|
||||||
try list.append(.{
|
try list.append(.{
|
||||||
.label = "*",
|
.label = "*",
|
||||||
.kind = .Operator,
|
.kind = .Operator,
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
.Slice => {
|
||||||
|
try list.append(.{ .label = "ptr", .kind = .Field });
|
||||||
|
try list.append(.{ .label = "len", .kind = .Field });
|
||||||
|
return;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const ptr_type = node.castTag(.PtrType).?;
|
if (unwrapped) |actual_type| {
|
||||||
if (ptr_type.rhs.castTag(.ArrayType) != null) {
|
|
||||||
try list.append(.{
|
|
||||||
.label = "len",
|
|
||||||
.kind = .Field,
|
|
||||||
});
|
|
||||||
} else if (unwrapped) |actual_type| {
|
|
||||||
try typeToCompletion(arena, list, .{ .original = actual_type }, orig_handle, config);
|
try typeToCompletion(arena, list, .{ .original = actual_type }, orig_handle, config);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
.OptionalType => {
|
.optional_type => {
|
||||||
if (config.operator_completions) {
|
if (config.operator_completions) {
|
||||||
try list.append(.{
|
try list.append(.{
|
||||||
.label = "?",
|
.label = "?",
|
||||||
@ -490,18 +509,18 @@ fn nodeToCompletion(
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
.StringLiteral => {
|
.string_literal => {
|
||||||
try list.append(.{
|
try list.append(.{
|
||||||
.label = "len",
|
.label = "len",
|
||||||
.kind = .Field,
|
.kind = .Field,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
else => if (analysis.nodeToString(handle.tree, node)) |string| {
|
else => if (analysis.nodeToString(tree, node)) |string| {
|
||||||
try list.append(.{
|
try list.append(.{
|
||||||
.label = string,
|
.label = string,
|
||||||
.kind = .Field,
|
.kind = .Field,
|
||||||
.documentation = doc,
|
.documentation = doc,
|
||||||
.detail = handle.tree.getNodeSource(node),
|
.detail = tree.getNodeSource(node),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -540,7 +559,7 @@ fn gotoDefinitionSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, de
|
|||||||
|
|
||||||
const name_token = analysis.getDeclNameToken(handle.tree, node) orelse
|
const name_token = analysis.getDeclNameToken(handle.tree, node) orelse
|
||||||
return try respondGeneric(id, null_result_response);
|
return try respondGeneric(id, null_result_response);
|
||||||
break :block offsets.tokenRelativeLocation(handle.tree, 0, name_token, offset_encoding) catch return;
|
break :block offsets.tokenRelativeLocation(handle.tree, 0, handle.tree.tokens.items(.start)[name_token], offset_encoding) catch return;
|
||||||
},
|
},
|
||||||
else => decl_handle.location(offset_encoding) catch return,
|
else => decl_handle.location(offset_encoding) catch return,
|
||||||
};
|
};
|
||||||
@ -565,8 +584,13 @@ fn gotoDefinitionSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, de
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hoverSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, decl_handle: analysis.DeclWithHandle) (std.os.WriteError || error{OutOfMemory})!void {
|
fn hoverSymbol(
|
||||||
|
id: types.RequestId,
|
||||||
|
arena: *std.heap.ArenaAllocator,
|
||||||
|
decl_handle: analysis.DeclWithHandle,
|
||||||
|
) (std.os.WriteError || error{OutOfMemory})!void {
|
||||||
const handle = decl_handle.handle;
|
const handle = decl_handle.handle;
|
||||||
|
const tree = handle.tree;
|
||||||
|
|
||||||
const hover_kind: types.MarkupContent.Kind = if (client_capabilities.hover_supports_md) .Markdown else .PlainText;
|
const hover_kind: types.MarkupContent.Kind = if (client_capabilities.hover_supports_md) .Markdown else .PlainText;
|
||||||
const md_string = switch (decl_handle.decl.*) {
|
const md_string = switch (decl_handle.decl.*) {
|
||||||
@ -575,26 +599,20 @@ fn hoverSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, decl_handle
|
|||||||
return try hoverSymbol(id, arena, result);
|
return try hoverSymbol(id, arena, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
const doc_str = if (try analysis.getDocComments(&arena.allocator, handle.tree, node, hover_kind)) |str|
|
const doc_str = if (try analysis.getDocComments(&arena.allocator, tree, node, hover_kind)) |str|
|
||||||
str
|
str
|
||||||
else
|
else
|
||||||
"";
|
"";
|
||||||
|
|
||||||
const signature_str = switch (node.tag) {
|
var buf: [1]std.zig.ast.Node.Index = undefined;
|
||||||
.VarDecl => blk: {
|
const signature_str = if (analysis.varDecl(tree, node)) |var_decl| blk: {
|
||||||
const var_decl = node.cast(std.zig.ast.Node.VarDecl).?;
|
break :blk analysis.getVariableSignature(tree, var_decl);
|
||||||
break :blk analysis.getVariableSignature(handle.tree, var_decl);
|
} else if (analysis.fnProto(tree, node, &buf)) |fn_proto| blk: {
|
||||||
},
|
break :blk analysis.getFunctionSignature(tree, fn_proto);
|
||||||
.FnProto => blk: {
|
} else if (analysis.containerField(tree, node)) |field| blk: {
|
||||||
const fn_decl = node.cast(std.zig.ast.Node.FnProto).?;
|
break :blk analysis.getContainerFieldSignature(tree, field);
|
||||||
break :blk analysis.getFunctionSignature(handle.tree, fn_decl);
|
} else analysis.nodeToString(tree, node) orelse
|
||||||
},
|
return try respondGeneric(id, null_result_response);
|
||||||
.ContainerField => blk: {
|
|
||||||
const field = node.cast(std.zig.ast.Node.ContainerField).?;
|
|
||||||
break :blk analysis.getContainerFieldSignature(handle.tree, field);
|
|
||||||
},
|
|
||||||
else => analysis.nodeToString(handle.tree, node) orelse return try respondGeneric(id, null_result_response),
|
|
||||||
};
|
|
||||||
|
|
||||||
break :ast_node if (hover_kind == .Markdown)
|
break :ast_node if (hover_kind == .Markdown)
|
||||||
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```\n{s}", .{ signature_str, doc_str })
|
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```\n{s}", .{ signature_str, doc_str })
|
||||||
@ -602,31 +620,43 @@ fn hoverSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, decl_handle
|
|||||||
try std.fmt.allocPrint(&arena.allocator, "{s}\n{s}", .{ signature_str, doc_str });
|
try std.fmt.allocPrint(&arena.allocator, "{s}\n{s}", .{ signature_str, doc_str });
|
||||||
},
|
},
|
||||||
.param_decl => |param| param_decl: {
|
.param_decl => |param| param_decl: {
|
||||||
const doc_str = if (param.doc_comments) |doc_comments|
|
const doc_str = if (param.first_doc_comment) |doc_comments|
|
||||||
try analysis.collectDocComments(&arena.allocator, handle.tree, doc_comments, hover_kind)
|
try analysis.collectDocComments(&arena.allocator, handle.tree, doc_comments, hover_kind)
|
||||||
else
|
else
|
||||||
"";
|
"";
|
||||||
|
|
||||||
const signature_str = handle.tree.source[handle.tree.token_locs[param.firstToken()].start..handle.tree.token_locs[param.lastToken()].end];
|
const first_token = param.first_doc_comment orelse
|
||||||
|
param.comptime_noalias orelse
|
||||||
|
param.name_token orelse
|
||||||
|
tree.firstToken(param.type_expr); // extern fn
|
||||||
|
const last_token = param.anytype_ellipsis3 orelse tree.lastToken(param.type_expr);
|
||||||
|
|
||||||
|
const start = offsets.tokenLocation(tree, first_token).start;
|
||||||
|
const end = offsets.tokenLocation(tree, last_token).end;
|
||||||
|
const signature_str = tree.source[start..end];
|
||||||
break :param_decl if (hover_kind == .Markdown)
|
break :param_decl if (hover_kind == .Markdown)
|
||||||
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```\n{s}", .{ signature_str, doc_str })
|
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```\n{s}", .{ signature_str, doc_str })
|
||||||
else
|
else
|
||||||
try std.fmt.allocPrint(&arena.allocator, "{s}\n{s}", .{ signature_str, doc_str });
|
try std.fmt.allocPrint(&arena.allocator, "{s}\n{s}", .{ signature_str, doc_str });
|
||||||
},
|
},
|
||||||
.pointer_payload => |payload| if (hover_kind == .Markdown)
|
.pointer_payload => |payload| if (hover_kind == .Markdown)
|
||||||
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{handle.tree.tokenSlice(payload.node.value_symbol.firstToken())})
|
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{tree.tokenSlice(payload.name)})
|
||||||
else
|
else
|
||||||
try std.fmt.allocPrint(&arena.allocator, "{s}", .{handle.tree.tokenSlice(payload.node.value_symbol.firstToken())}),
|
try std.fmt.allocPrint(&arena.allocator, "{s}", .{tree.tokenSlice(payload.name)}),
|
||||||
.array_payload => |payload| if (hover_kind == .Markdown)
|
.array_payload => |payload| if (hover_kind == .Markdown)
|
||||||
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{handle.tree.tokenSlice(payload.identifier.firstToken())})
|
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{handle.tree.tokenSlice(payload.identifier)})
|
||||||
else
|
else
|
||||||
try std.fmt.allocPrint(&arena.allocator, "{s}", .{handle.tree.tokenSlice(payload.identifier.firstToken())}),
|
try std.fmt.allocPrint(&arena.allocator, "{s}", .{handle.tree.tokenSlice(payload.identifier)}),
|
||||||
|
.array_index => |payload| if (hover_kind == .Markdown)
|
||||||
|
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{handle.tree.tokenSlice(payload)})
|
||||||
|
else
|
||||||
|
try std.fmt.allocPrint(&arena.allocator, "{s}", .{handle.tree.tokenSlice(payload)}),
|
||||||
.switch_payload => |payload| if (hover_kind == .Markdown)
|
.switch_payload => |payload| if (hover_kind == .Markdown)
|
||||||
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{handle.tree.tokenSlice(payload.node.value_symbol.firstToken())})
|
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{tree.tokenSlice(payload.node)})
|
||||||
else
|
else
|
||||||
try std.fmt.allocPrint(&arena.allocator, "{s}", .{handle.tree.tokenSlice(payload.node.value_symbol.firstToken())}),
|
try std.fmt.allocPrint(&arena.allocator, "{s}", .{tree.tokenSlice(payload.node)}),
|
||||||
.label_decl => |label_decl| block: {
|
.label_decl => |label_decl| block: {
|
||||||
const source = handle.tree.source[handle.tree.token_locs[label_decl.firstToken()].start..handle.tree.token_locs[label_decl.lastToken()].end];
|
const source = tree.tokenSlice(label_decl);
|
||||||
break :block if (hover_kind == .Markdown)
|
break :block if (hover_kind == .Markdown)
|
||||||
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{source})
|
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{source})
|
||||||
else
|
else
|
||||||
@ -752,7 +782,7 @@ fn hoverDefinitionFieldAccess(
|
|||||||
fn gotoDefinitionString(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: Config) !void {
|
fn gotoDefinitionString(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: Config) !void {
|
||||||
const tree = handle.tree;
|
const tree = handle.tree;
|
||||||
|
|
||||||
const import_str = analysis.getImportStr(tree, pos_index) orelse return try respondGeneric(id, null_result_response);
|
const import_str = analysis.getImportStr(tree, 0, pos_index) orelse return try respondGeneric(id, null_result_response);
|
||||||
const uri = (try document_store.uriFromImportStr(
|
const uri = (try document_store.uriFromImportStr(
|
||||||
&arena.allocator,
|
&arena.allocator,
|
||||||
handle.*,
|
handle.*,
|
||||||
@ -820,10 +850,26 @@ fn renameDefinitionLabel(arena: *std.heap.ArenaAllocator, id: types.RequestId, h
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn referencesDefinitionGlobal(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, pos_index: usize, include_decl: bool) !void {
|
fn referencesDefinitionGlobal(
|
||||||
|
arena: *std.heap.ArenaAllocator,
|
||||||
|
id: types.RequestId,
|
||||||
|
handle: *DocumentStore.Handle,
|
||||||
|
pos_index: usize,
|
||||||
|
include_decl: bool,
|
||||||
|
skip_std_references: bool,
|
||||||
|
) !void {
|
||||||
const decl = (try getSymbolGlobal(arena, pos_index, handle)) orelse return try respondGeneric(id, null_result_response);
|
const decl = (try getSymbolGlobal(arena, pos_index, handle)) orelse return try respondGeneric(id, null_result_response);
|
||||||
var locs = std.ArrayList(types.Location).init(&arena.allocator);
|
var locs = std.ArrayList(types.Location).init(&arena.allocator);
|
||||||
try references.symbolReferences(arena, &document_store, decl, offset_encoding, include_decl, &locs, std.ArrayList(types.Location).append);
|
try references.symbolReferences(
|
||||||
|
arena,
|
||||||
|
&document_store,
|
||||||
|
decl,
|
||||||
|
offset_encoding,
|
||||||
|
include_decl,
|
||||||
|
&locs,
|
||||||
|
std.ArrayList(types.Location).append,
|
||||||
|
skip_std_references,
|
||||||
|
);
|
||||||
try send(arena, types.Response{
|
try send(arena, types.Response{
|
||||||
.id = id,
|
.id = id,
|
||||||
.result = .{ .Locations = locs.items },
|
.result = .{ .Locations = locs.items },
|
||||||
@ -841,7 +887,7 @@ fn referencesDefinitionFieldAccess(
|
|||||||
) !void {
|
) !void {
|
||||||
const decl = (try getSymbolFieldAccess(handle, arena, position, range, config)) orelse return try respondGeneric(id, null_result_response);
|
const decl = (try getSymbolFieldAccess(handle, arena, position, range, config)) orelse return try respondGeneric(id, null_result_response);
|
||||||
var locs = std.ArrayList(types.Location).init(&arena.allocator);
|
var locs = std.ArrayList(types.Location).init(&arena.allocator);
|
||||||
try references.symbolReferences(arena, &document_store, decl, offset_encoding, include_decl, &locs, std.ArrayList(types.Location).append);
|
try references.symbolReferences(arena, &document_store, decl, offset_encoding, include_decl, &locs, std.ArrayList(types.Location).append, config.skip_std_references);
|
||||||
try send(arena, types.Response{
|
try send(arena, types.Response{
|
||||||
.id = id,
|
.id = id,
|
||||||
.result = .{ .Locations = locs.items },
|
.result = .{ .Locations = locs.items },
|
||||||
@ -865,14 +911,30 @@ const DeclToCompletionContext = struct {
|
|||||||
orig_handle: *DocumentStore.Handle,
|
orig_handle: *DocumentStore.Handle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn hasComment(tree: ast.Tree, start_token: ast.TokenIndex, end_token: ast.TokenIndex) bool {
|
||||||
|
const token_starts = tree.tokens.items(.start);
|
||||||
|
|
||||||
|
const start = token_starts[start_token];
|
||||||
|
const end = token_starts[end_token];
|
||||||
|
|
||||||
|
return std.mem.indexOf(u8, tree.source[start..end], "//") != null;
|
||||||
|
}
|
||||||
|
|
||||||
fn declToCompletion(context: DeclToCompletionContext, decl_handle: analysis.DeclWithHandle) !void {
|
fn declToCompletion(context: DeclToCompletionContext, decl_handle: analysis.DeclWithHandle) !void {
|
||||||
const tree = decl_handle.handle.tree;
|
const tree = decl_handle.handle.tree;
|
||||||
|
|
||||||
switch (decl_handle.decl.*) {
|
switch (decl_handle.decl.*) {
|
||||||
.ast_node => |node| try nodeToCompletion(context.arena, context.completions, .{ .node = node, .handle = decl_handle.handle }, null, context.orig_handle, false, context.config.*),
|
.ast_node => |node| try nodeToCompletion(
|
||||||
|
context.arena,
|
||||||
|
context.completions,
|
||||||
|
.{ .node = node, .handle = decl_handle.handle },
|
||||||
|
null,
|
||||||
|
context.orig_handle,
|
||||||
|
false,
|
||||||
|
context.config.*,
|
||||||
|
),
|
||||||
.param_decl => |param| {
|
.param_decl => |param| {
|
||||||
const doc_kind: types.MarkupContent.Kind = if (client_capabilities.completion_doc_supports_md) .Markdown else .PlainText;
|
const doc_kind: types.MarkupContent.Kind = if (client_capabilities.completion_doc_supports_md) .Markdown else .PlainText;
|
||||||
const doc = if (param.doc_comments) |doc_comments|
|
const doc = if (param.first_doc_comment) |doc_comments|
|
||||||
types.MarkupContent{
|
types.MarkupContent{
|
||||||
.kind = doc_kind,
|
.kind = doc_kind,
|
||||||
.value = try analysis.collectDocComments(&context.arena.allocator, tree, doc_comments, doc_kind),
|
.value = try analysis.collectDocComments(&context.arena.allocator, tree, doc_comments, doc_kind),
|
||||||
@ -880,34 +942,46 @@ fn declToCompletion(context: DeclToCompletionContext, decl_handle: analysis.Decl
|
|||||||
else
|
else
|
||||||
null;
|
null;
|
||||||
|
|
||||||
|
const first_token = param.first_doc_comment orelse
|
||||||
|
param.comptime_noalias orelse
|
||||||
|
param.name_token orelse
|
||||||
|
tree.firstToken(param.type_expr);
|
||||||
|
const last_token = param.anytype_ellipsis3 orelse tree.lastToken(param.type_expr);
|
||||||
|
|
||||||
try context.completions.append(.{
|
try context.completions.append(.{
|
||||||
.label = tree.tokenSlice(param.name_token.?),
|
.label = tree.tokenSlice(param.name_token.?),
|
||||||
.kind = .Constant,
|
.kind = .Constant,
|
||||||
.documentation = doc,
|
.documentation = doc,
|
||||||
.detail = tree.source[tree.token_locs[param.firstToken()].start..tree.token_locs[param.lastToken()].end],
|
.detail = tree.source[offsets.tokenLocation(tree, first_token).start..offsets.tokenLocation(tree, last_token).end],
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.pointer_payload => |payload| {
|
.pointer_payload => |payload| {
|
||||||
try context.completions.append(.{
|
try context.completions.append(.{
|
||||||
.label = tree.tokenSlice(payload.node.value_symbol.firstToken()),
|
.label = tree.tokenSlice(payload.name),
|
||||||
.kind = .Variable,
|
.kind = .Variable,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.array_payload => |payload| {
|
.array_payload => |payload| {
|
||||||
try context.completions.append(.{
|
try context.completions.append(.{
|
||||||
.label = tree.tokenSlice(payload.identifier.firstToken()),
|
.label = tree.tokenSlice(payload.identifier),
|
||||||
|
.kind = .Variable,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
.array_index => |payload| {
|
||||||
|
try context.completions.append(.{
|
||||||
|
.label = tree.tokenSlice(payload),
|
||||||
.kind = .Variable,
|
.kind = .Variable,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.switch_payload => |payload| {
|
.switch_payload => |payload| {
|
||||||
try context.completions.append(.{
|
try context.completions.append(.{
|
||||||
.label = tree.tokenSlice(payload.node.value_symbol.firstToken()),
|
.label = tree.tokenSlice(payload.node),
|
||||||
.kind = .Variable,
|
.kind = .Variable,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.label_decl => |label_decl| {
|
.label_decl => |label_decl| {
|
||||||
try context.completions.append(.{
|
try context.completions.append(.{
|
||||||
.label = tree.tokenSlice(label_decl.firstToken()),
|
.label = tree.tokenSlice(label_decl),
|
||||||
.kind = .Variable,
|
.kind = .Variable,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -1223,7 +1297,6 @@ fn completionHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req:
|
|||||||
if (req.params.position.character >= 0) {
|
if (req.params.position.character >= 0) {
|
||||||
const doc_position = try offsets.documentPosition(handle.document, req.params.position, offset_encoding);
|
const doc_position = try offsets.documentPosition(handle.document, req.params.position, offset_encoding);
|
||||||
const pos_context = try analysis.documentPositionContext(arena, handle.document, doc_position);
|
const pos_context = try analysis.documentPositionContext(arena, handle.document, doc_position);
|
||||||
|
|
||||||
const use_snippets = config.enable_snippets and client_capabilities.supports_snippets;
|
const use_snippets = config.enable_snippets and client_capabilities.supports_snippets;
|
||||||
switch (pos_context) {
|
switch (pos_context) {
|
||||||
.builtin => try completeBuiltin(arena, id, config),
|
.builtin => try completeBuiltin(arena, id, config),
|
||||||
@ -1301,7 +1374,6 @@ fn hoverHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: reque
|
|||||||
if (req.params.position.character >= 0) {
|
if (req.params.position.character >= 0) {
|
||||||
const doc_position = try offsets.documentPosition(handle.document, req.params.position, offset_encoding);
|
const doc_position = try offsets.documentPosition(handle.document, req.params.position, offset_encoding);
|
||||||
const pos_context = try analysis.documentPositionContext(arena, handle.document, doc_position);
|
const pos_context = try analysis.documentPositionContext(arena, handle.document, doc_position);
|
||||||
|
|
||||||
switch (pos_context) {
|
switch (pos_context) {
|
||||||
.builtin => try hoverDefinitionBuiltin(arena, id, doc_position.absolute_index, handle),
|
.builtin => try hoverDefinitionBuiltin(arena, id, doc_position.absolute_index, handle),
|
||||||
.var_access => try hoverDefinitionGlobal(arena, id, doc_position.absolute_index, handle, config),
|
.var_access => try hoverDefinitionGlobal(arena, id, doc_position.absolute_index, handle, config),
|
||||||
@ -1398,7 +1470,7 @@ fn referencesHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req:
|
|||||||
|
|
||||||
const include_decl = req.params.context.includeDeclaration;
|
const include_decl = req.params.context.includeDeclaration;
|
||||||
switch (pos_context) {
|
switch (pos_context) {
|
||||||
.var_access => try referencesDefinitionGlobal(arena, id, handle, doc_position.absolute_index, include_decl),
|
.var_access => try referencesDefinitionGlobal(arena, id, handle, doc_position.absolute_index, include_decl, config.skip_std_references),
|
||||||
.field_access => |range| try referencesDefinitionFieldAccess(arena, id, handle, doc_position, range, include_decl, config),
|
.field_access => |range| try referencesDefinitionFieldAccess(arena, id, handle, doc_position, range, include_decl, config),
|
||||||
.label => try referencesDefinitionLabel(arena, id, handle, doc_position.absolute_index, include_decl),
|
.label => try referencesDefinitionLabel(arena, id, handle, doc_position.absolute_index, include_decl),
|
||||||
else => try respondGeneric(id, null_result_response),
|
else => try respondGeneric(id, null_result_response),
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const types = @import("types.zig");
|
const types = @import("types.zig");
|
||||||
|
const ast = std.zig.ast;
|
||||||
|
|
||||||
pub const Encoding = enum {
|
pub const Encoding = enum {
|
||||||
utf8,
|
utf8,
|
||||||
@ -70,15 +71,15 @@ pub const TokenLocation = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn tokenRelativeLocation(tree: *std.zig.ast.Tree, start_index: usize, token: std.zig.ast.TokenIndex, encoding: Encoding) !TokenLocation {
|
pub fn tokenRelativeLocation(tree: ast.Tree, start_index: usize, next_token_index: usize, encoding: Encoding) !TokenLocation {
|
||||||
const token_loc = tree.token_locs[token];
|
const start = next_token_index;
|
||||||
|
|
||||||
var loc = TokenLocation{
|
var loc = TokenLocation{
|
||||||
.line = 0,
|
.line = 0,
|
||||||
.column = 0,
|
.column = 0,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
};
|
};
|
||||||
const token_start = token_loc.start;
|
const token_start = start;
|
||||||
const source = tree.source[start_index..];
|
const source = tree.source[start_index..];
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (i + start_index < token_start) {
|
while (i + start_index < token_start) {
|
||||||
@ -108,8 +109,8 @@ pub fn tokenRelativeLocation(tree: *std.zig.ast.Tree, start_index: usize, token:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Asserts the token is comprised of valid utf8
|
/// Asserts the token is comprised of valid utf8
|
||||||
pub fn tokenLength(tree: *std.zig.ast.Tree, token: std.zig.ast.TokenIndex, encoding: Encoding) usize {
|
pub fn tokenLength(tree: ast.Tree, token: ast.TokenIndex, encoding: Encoding) usize {
|
||||||
const token_loc = tree.token_locs[token];
|
const token_loc = tokenLocation(tree, token);
|
||||||
if (encoding == .utf8)
|
if (encoding == .utf8)
|
||||||
return token_loc.end - token_loc.start;
|
return token_loc.end - token_loc.start;
|
||||||
|
|
||||||
@ -128,6 +129,28 @@ pub fn tokenLength(tree: *std.zig.ast.Tree, token: std.zig.ast.TokenIndex, encod
|
|||||||
return utf16_len;
|
return utf16_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Token location inside source
|
||||||
|
pub const Loc = struct {
|
||||||
|
start: usize,
|
||||||
|
end: usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn tokenLocation(tree: ast.Tree, token_index: ast.TokenIndex) Loc {
|
||||||
|
const start = tree.tokens.items(.start)[token_index];
|
||||||
|
const tag = tree.tokens.items(.tag)[token_index];
|
||||||
|
|
||||||
|
// For some tokens, re-tokenization is needed to find the end.
|
||||||
|
var tokenizer: std.zig.Tokenizer = .{
|
||||||
|
.buffer = tree.source,
|
||||||
|
.index = start,
|
||||||
|
.pending_invalid_token = null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const token = tokenizer.next();
|
||||||
|
std.debug.assert(token.tag == tag);
|
||||||
|
return .{ .start = token.loc.start, .end = token.loc.end };
|
||||||
|
}
|
||||||
|
|
||||||
pub fn documentRange(doc: types.TextDocument, encoding: Encoding) !types.Range {
|
pub fn documentRange(doc: types.TextDocument, encoding: Encoding) !types.Range {
|
||||||
var line_idx: i64 = 0;
|
var line_idx: i64 = 0;
|
||||||
var curr_line: []const u8 = doc.text;
|
var curr_line: []const u8 = doc.text;
|
||||||
|
@ -14,7 +14,7 @@ fn tokenReference(
|
|||||||
context: anytype,
|
context: anytype,
|
||||||
comptime handler: anytype,
|
comptime handler: anytype,
|
||||||
) !void {
|
) !void {
|
||||||
const loc = offsets.tokenRelativeLocation(handle.tree, 0, tok, encoding) catch return;
|
const loc = offsets.tokenRelativeLocation(handle.tree, 0, handle.tree.tokens.items(.start)[tok], encoding) catch return;
|
||||||
try handler(context, types.Location{
|
try handler(context, types.Location{
|
||||||
.uri = handle.uri(),
|
.uri = handle.uri(),
|
||||||
.range = .{
|
.range = .{
|
||||||
@ -40,11 +40,13 @@ pub fn labelReferences(
|
|||||||
) !void {
|
) !void {
|
||||||
std.debug.assert(decl.decl.* == .label_decl);
|
std.debug.assert(decl.decl.* == .label_decl);
|
||||||
const handle = decl.handle;
|
const handle = decl.handle;
|
||||||
|
const tree = handle.tree;
|
||||||
|
const token_tags = tree.tokens.items(.tag);
|
||||||
|
|
||||||
// Find while / for / block from label -> iterate over children nodes, find break and continues, change their labels if they match.
|
// Find while / for / block from label -> iterate over children nodes, find break and continues, change their labels if they match.
|
||||||
// This case can be implemented just by scanning tokens.
|
// This case can be implemented just by scanning tokens.
|
||||||
const first_tok = decl.decl.label_decl.firstToken();
|
const first_tok = tree.firstToken(decl.decl.label_decl);
|
||||||
const last_tok = decl.decl.label_decl.lastToken();
|
const last_tok = tree.firstToken(decl.decl.label_decl);
|
||||||
|
|
||||||
if (include_decl) {
|
if (include_decl) {
|
||||||
// The first token is always going to be the label
|
// The first token is always going to be the label
|
||||||
@ -53,11 +55,11 @@ pub fn labelReferences(
|
|||||||
|
|
||||||
var curr_tok = first_tok + 1;
|
var curr_tok = first_tok + 1;
|
||||||
while (curr_tok < last_tok - 2) : (curr_tok += 1) {
|
while (curr_tok < last_tok - 2) : (curr_tok += 1) {
|
||||||
const curr_id = handle.tree.token_ids[curr_tok];
|
const curr_id = token_tags[curr_tok];
|
||||||
if ((curr_id == .Keyword_break or curr_id == .Keyword_continue) and handle.tree.token_ids[curr_tok + 1] == .Colon and
|
if ((curr_id == .keyword_break or curr_id == .keyword_continue) and token_tags[curr_tok + 1] == .colon and
|
||||||
handle.tree.token_ids[curr_tok + 2] == .Identifier)
|
token_tags[curr_tok + 2] == .identifier)
|
||||||
{
|
{
|
||||||
if (std.mem.eql(u8, handle.tree.tokenSlice(curr_tok + 2), handle.tree.tokenSlice(first_tok))) {
|
if (std.mem.eql(u8, tree.tokenSlice(curr_tok + 2), tree.tokenSlice(first_tok))) {
|
||||||
try tokenReference(handle, first_tok, encoding, context, handler);
|
try tokenReference(handle, first_tok, encoding, context, handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,263 +77,377 @@ fn symbolReferencesInternal(
|
|||||||
) error{OutOfMemory}!void {
|
) error{OutOfMemory}!void {
|
||||||
const node = node_handle.node;
|
const node = node_handle.node;
|
||||||
const handle = node_handle.handle;
|
const handle = node_handle.handle;
|
||||||
|
const tree = handle.tree;
|
||||||
|
if (node > tree.nodes.len) return;
|
||||||
|
const node_tags = tree.nodes.items(.tag);
|
||||||
|
const datas = tree.nodes.items(.data);
|
||||||
|
const main_tokens = tree.nodes.items(.main_token);
|
||||||
|
const starts = tree.tokens.items(.start);
|
||||||
|
|
||||||
switch (node.tag) {
|
switch (node_tags[node]) {
|
||||||
.ContainerDecl, .Root, .Block => {
|
.block, .block_semicolon, .block_two, .block_two_semicolon => {
|
||||||
var idx: usize = 0;
|
const statements: []const ast.Node.Index = switch (node_tags[node]) {
|
||||||
while (node.iterate(idx)) |child| : (idx += 1) {
|
.block, .block_semicolon => tree.extra_data[datas[node].lhs..datas[node].rhs],
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = child, .handle = handle }, decl, encoding, context, handler);
|
.block_two, .block_two_semicolon => blk: {
|
||||||
|
const statements = &[_]ast.Node.Index{ datas[node].lhs, datas[node].rhs };
|
||||||
|
const len: usize = if (datas[node].lhs == 0)
|
||||||
|
@as(usize, 0)
|
||||||
|
else if (datas[node].rhs == 0)
|
||||||
|
@as(usize, 1)
|
||||||
|
else
|
||||||
|
@as(usize, 2);
|
||||||
|
break :blk statements[0..len];
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
for (statements) |stmt|
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = stmt, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
},
|
||||||
|
.container_decl,
|
||||||
|
.container_decl_trailing,
|
||||||
|
.container_decl_arg,
|
||||||
|
.container_decl_arg_trailing,
|
||||||
|
.container_decl_two,
|
||||||
|
.container_decl_two_trailing,
|
||||||
|
.tagged_union,
|
||||||
|
.tagged_union_trailing,
|
||||||
|
.tagged_union_two,
|
||||||
|
.tagged_union_two_trailing,
|
||||||
|
.tagged_union_enum_tag,
|
||||||
|
.tagged_union_enum_tag_trailing,
|
||||||
|
.root,
|
||||||
|
.error_set_decl,
|
||||||
|
=> {
|
||||||
|
var buf: [2]ast.Node.Index = undefined;
|
||||||
|
for (analysis.declMembers(tree, node_tags[node], node, &buf)) |member|
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = member, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
},
|
||||||
|
.global_var_decl,
|
||||||
|
.local_var_decl,
|
||||||
|
.simple_var_decl,
|
||||||
|
.aligned_var_decl,
|
||||||
|
=> {
|
||||||
|
const var_decl = analysis.varDecl(tree, node).?;
|
||||||
|
if (var_decl.ast.type_node != 0) {
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = var_decl.ast.type_node, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
}
|
||||||
|
if (var_decl.ast.init_node != 0) {
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = var_decl.ast.init_node, .handle = handle }, decl, encoding, context, handler);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.VarDecl => {
|
.@"usingnamespace" => {
|
||||||
const var_decl = node.cast(ast.Node.VarDecl).?;
|
try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler);
|
||||||
if (var_decl.getTypeNode()) |type_node| {
|
},
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = type_node, .handle = handle }, decl, encoding, context, handler);
|
.container_field,
|
||||||
|
.container_field_align,
|
||||||
|
.container_field_init,
|
||||||
|
=> {
|
||||||
|
const field = analysis.containerField(tree, node).?;
|
||||||
|
if (field.ast.type_expr != 0) {
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = field.ast.type_expr, .handle = handle }, decl, encoding, context, handler);
|
||||||
}
|
}
|
||||||
if (var_decl.getInitNode()) |init_node| {
|
if (field.ast.value_expr != 0) {
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = init_node, .handle = handle }, decl, encoding, context, handler);
|
try symbolReferencesInternal(arena, store, .{ .node = field.ast.value_expr, .handle = handle }, decl, encoding, context, handler);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.Use => {
|
.identifier => {
|
||||||
const use = node.cast(ast.Node.Use).?;
|
if (try analysis.lookupSymbolGlobal(store, arena, handle, tree.getNodeSource(node), starts[main_tokens[node]])) |child| {
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = use.expr, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
},
|
|
||||||
.ContainerField => {
|
|
||||||
const field = node.cast(ast.Node.ContainerField).?;
|
|
||||||
if (field.type_expr) |type_node| {
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = type_node, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
}
|
|
||||||
if (field.value_expr) |init_node| {
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = init_node, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.Identifier => {
|
|
||||||
if (try analysis.lookupSymbolGlobal(store, arena, handle, handle.tree.getNodeSource(node), handle.tree.token_locs[node.firstToken()].start)) |child| {
|
|
||||||
if (std.meta.eql(decl, child)) {
|
if (std.meta.eql(decl, child)) {
|
||||||
try tokenReference(handle, node.firstToken(), encoding, context, handler);
|
try tokenReference(handle, main_tokens[node], encoding, context, handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.FnProto => {
|
.fn_proto,
|
||||||
const fn_proto = node.cast(ast.Node.FnProto).?;
|
.fn_proto_multi,
|
||||||
for (fn_proto.paramsConst()) |param| {
|
.fn_proto_one,
|
||||||
switch (param.param_type) {
|
.fn_proto_simple,
|
||||||
.type_expr => |type_node| {
|
.fn_decl,
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = type_node, .handle = handle }, decl, encoding, context, handler);
|
=> {
|
||||||
},
|
var buf: [1]ast.Node.Index = undefined;
|
||||||
else => {},
|
const fn_proto = analysis.fnProto(tree, node, &buf).?;
|
||||||
|
var it = fn_proto.iterate(tree);
|
||||||
|
while (it.next()) |param| {
|
||||||
|
if (param.type_expr != 0)
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = param.type_expr, .handle = handle }, decl, encoding, context, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fn_proto.ast.return_type != 0) {
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = fn_proto.ast.return_type, .handle = handle }, decl, encoding, context, handler);
|
||||||
}
|
}
|
||||||
switch (fn_proto.return_type) {
|
if (fn_proto.ast.align_expr != 0) {
|
||||||
.Explicit, .InferErrorSet => |type_node| {
|
try symbolReferencesInternal(arena, store, .{ .node = fn_proto.ast.align_expr, .handle = handle }, decl, encoding, context, handler);
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = type_node, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
},
|
|
||||||
else => {},
|
|
||||||
}
|
}
|
||||||
if (fn_proto.getAlignExpr()) |align_expr| {
|
if (fn_proto.ast.section_expr != 0) {
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = align_expr, .handle = handle }, decl, encoding, context, handler);
|
try symbolReferencesInternal(arena, store, .{ .node = fn_proto.ast.section_expr, .handle = handle }, decl, encoding, context, handler);
|
||||||
}
|
}
|
||||||
if (fn_proto.getSectionExpr()) |section_expr| {
|
if (fn_proto.ast.callconv_expr != 0) {
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = section_expr, .handle = handle }, decl, encoding, context, handler);
|
try symbolReferencesInternal(arena, store, .{ .node = fn_proto.ast.callconv_expr, .handle = handle }, decl, encoding, context, handler);
|
||||||
}
|
}
|
||||||
if (fn_proto.getCallconvExpr()) |callconv_expr| {
|
if (node_tags[node] == .fn_decl) {
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = callconv_expr, .handle = handle }, decl, encoding, context, handler);
|
try symbolReferencesInternal(arena, store, .{ .node = datas[node].rhs, .handle = handle }, decl, encoding, context, handler);
|
||||||
}
|
|
||||||
if (fn_proto.getBodyNode()) |body| {
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = body, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.AnyFrameType => {
|
.anyframe_type => {
|
||||||
const anyframe_type = node.cast(ast.Node.AnyFrameType).?;
|
try symbolReferencesInternal(arena, store, .{ .node = datas[node].rhs, .handle = handle }, decl, encoding, context, handler);
|
||||||
if (anyframe_type.result) |result| {
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = result.return_type, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
.Defer => {
|
.@"defer" => {
|
||||||
const defer_node = node.cast(ast.Node.Defer).?;
|
try symbolReferencesInternal(arena, store, .{ .node = datas[node].rhs, .handle = handle }, decl, encoding, context, handler);
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = defer_node.expr, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
},
|
},
|
||||||
.Comptime => {
|
.@"comptime" => {
|
||||||
const comptime_node = node.cast(ast.Node.Comptime).?;
|
try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler);
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = comptime_node.expr, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
},
|
},
|
||||||
.Nosuspend => {
|
.@"nosuspend" => {
|
||||||
const nosuspend_node = node.cast(ast.Node.Nosuspend).?;
|
try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler);
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = nosuspend_node.expr, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
},
|
},
|
||||||
.Switch => {
|
.@"switch",
|
||||||
|
.switch_comma,
|
||||||
|
=> {
|
||||||
// TODO When renaming a union(enum) field, also rename switch items that refer to it.
|
// TODO When renaming a union(enum) field, also rename switch items that refer to it.
|
||||||
const switch_node = node.cast(ast.Node.Switch).?;
|
try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler);
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = switch_node.expr, .handle = handle }, decl, encoding, context, handler);
|
const extra = tree.extraData(datas[node].rhs, ast.Node.SubRange);
|
||||||
for (switch_node.casesConst()) |case| {
|
const cases = tree.extra_data[extra.start..extra.end];
|
||||||
if (case.*.cast(ast.Node.SwitchCase)) |case_node| {
|
for (cases) |case| {
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = case_node.expr, .handle = handle }, decl, encoding, context, handler);
|
try symbolReferencesInternal(arena, store, .{ .node = case, .handle = handle }, decl, encoding, context, handler);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.While => {
|
.switch_case_one => {
|
||||||
const while_node = node.cast(ast.Node.While).?;
|
const case_one = tree.switchCaseOne(node);
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = while_node.condition, .handle = handle }, decl, encoding, context, handler);
|
if (case_one.ast.target_expr != 0)
|
||||||
if (while_node.continue_expr) |cont_expr| {
|
try symbolReferencesInternal(arena, store, .{ .node = case_one.ast.target_expr, .handle = handle }, decl, encoding, context, handler);
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = cont_expr, .handle = handle }, decl, encoding, context, handler);
|
for (case_one.ast.values) |val|
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = val, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
},
|
||||||
|
.switch_case => {
|
||||||
|
const case = tree.switchCase(node);
|
||||||
|
if (case.ast.target_expr != 0)
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = case.ast.target_expr, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
for (case.ast.values) |val|
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = val, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
},
|
||||||
|
.@"while",
|
||||||
|
.while_simple,
|
||||||
|
.while_cont,
|
||||||
|
.for_simple,
|
||||||
|
.@"for",
|
||||||
|
=> {
|
||||||
|
const loop: ast.full.While = switch (node_tags[node]) {
|
||||||
|
.@"while" => tree.whileFull(node),
|
||||||
|
.while_simple => tree.whileSimple(node),
|
||||||
|
.while_cont => tree.whileCont(node),
|
||||||
|
.for_simple => tree.forSimple(node),
|
||||||
|
.@"for" => tree.forFull(node),
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = loop.ast.cond_expr, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
if (loop.ast.cont_expr != 0) {
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = loop.ast.cont_expr, .handle = handle }, decl, encoding, context, handler);
|
||||||
}
|
}
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = while_node.body, .handle = handle }, decl, encoding, context, handler);
|
try symbolReferencesInternal(arena, store, .{ .node = loop.ast.then_expr, .handle = handle }, decl, encoding, context, handler);
|
||||||
if (while_node.@"else") |else_node| {
|
if (loop.ast.else_expr != 0) {
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = else_node.body, .handle = handle }, decl, encoding, context, handler);
|
try symbolReferencesInternal(arena, store, .{ .node = loop.ast.else_expr, .handle = handle }, decl, encoding, context, handler);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.For => {
|
.@"if",
|
||||||
const for_node = node.cast(ast.Node.For).?;
|
.if_simple,
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = for_node.array_expr, .handle = handle }, decl, encoding, context, handler);
|
=> {
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = for_node.body, .handle = handle }, decl, encoding, context, handler);
|
const if_node: ast.full.If = if (node_tags[node] == .@"if") tree.ifFull(node) else tree.ifSimple(node);
|
||||||
if (for_node.@"else") |else_node| {
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = else_node.body, .handle = handle }, decl, encoding, context, handler);
|
try symbolReferencesInternal(arena, store, .{ .node = if_node.ast.cond_expr, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = if_node.ast.then_expr, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
if (if_node.ast.else_expr != 0) {
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = if_node.ast.else_expr, .handle = handle }, decl, encoding, context, handler);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.If => {
|
.array_type,
|
||||||
const if_node = node.cast(ast.Node.If).?;
|
.array_type_sentinel,
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = if_node.condition, .handle = handle }, decl, encoding, context, handler);
|
=> {
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = if_node.body, .handle = handle }, decl, encoding, context, handler);
|
try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler);
|
||||||
if (if_node.@"else") |else_node| {
|
try symbolReferencesInternal(arena, store, .{ .node = datas[node].rhs, .handle = handle }, decl, encoding, context, handler);
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = else_node.body, .handle = handle }, decl, encoding, context, handler);
|
},
|
||||||
|
.ptr_type,
|
||||||
|
.ptr_type_aligned,
|
||||||
|
.ptr_type_bit_range,
|
||||||
|
.ptr_type_sentinel,
|
||||||
|
=> {
|
||||||
|
const ptr_type = analysis.ptrType(tree, node).?;
|
||||||
|
|
||||||
|
if (ptr_type.ast.align_node != 0) {
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = ptr_type.ast.align_node, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
if (node_tags[node] == .ptr_type_bit_range) {
|
||||||
|
try symbolReferencesInternal(arena, store, .{
|
||||||
|
.node = ptr_type.ast.bit_range_start,
|
||||||
|
.handle = handle,
|
||||||
|
}, decl, encoding, context, handler);
|
||||||
|
try symbolReferencesInternal(arena, store, .{
|
||||||
|
.node = ptr_type.ast.bit_range_end,
|
||||||
|
.handle = handle,
|
||||||
|
}, decl, encoding, context, handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ptr_type.ast.sentinel != 0) {
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = ptr_type.ast.sentinel, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = ptr_type.ast.child_type, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
},
|
||||||
|
.address_of, .@"await", .bit_not, .bool_not, .optional_type, .negation, .negation_wrap, .@"resume", .@"try" => {
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
},
|
||||||
|
.array_init,
|
||||||
|
.array_init_comma,
|
||||||
|
.array_init_dot,
|
||||||
|
.array_init_dot_comma,
|
||||||
|
.array_init_one,
|
||||||
|
.array_init_one_comma,
|
||||||
|
.array_init_dot_two,
|
||||||
|
.array_init_dot_two_comma,
|
||||||
|
=> |n| {
|
||||||
|
var buf: [2]ast.Node.Index = undefined;
|
||||||
|
const array_init = switch (n) {
|
||||||
|
.array_init, .array_init_comma => tree.arrayInit(node),
|
||||||
|
.array_init_dot, .array_init_dot_comma => tree.arrayInitDot(node),
|
||||||
|
.array_init_one, .array_init_one_comma => tree.arrayInitOne(buf[0..1], node),
|
||||||
|
.array_init_dot_two, .array_init_dot_two_comma => tree.arrayInitDotTwo(&buf, node),
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
if (array_init.ast.type_expr != 0)
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = array_init.ast.type_expr, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
for (array_init.ast.elements) |e|
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = e, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
},
|
||||||
|
.struct_init,
|
||||||
|
.struct_init_comma,
|
||||||
|
.struct_init_dot,
|
||||||
|
.struct_init_dot_comma,
|
||||||
|
.struct_init_dot_two,
|
||||||
|
.struct_init_dot_two_comma,
|
||||||
|
.struct_init_one,
|
||||||
|
.struct_init_one_comma,
|
||||||
|
=> |n| {
|
||||||
|
var buf: [2]ast.Node.Index = undefined;
|
||||||
|
const struct_init: ast.full.StructInit = switch (n) {
|
||||||
|
.struct_init, .struct_init_comma => tree.structInit(node),
|
||||||
|
.struct_init_dot, .struct_init_dot_comma => tree.structInitDot(node),
|
||||||
|
.struct_init_one, .struct_init_one_comma => tree.structInitOne(buf[0..1], node),
|
||||||
|
.struct_init_dot_two, .struct_init_dot_two_comma => tree.structInitDotTwo(&buf, node),
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
if (struct_init.ast.type_expr != 0)
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = struct_init.ast.type_expr, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
for (struct_init.ast.fields) |field|
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = field, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
},
|
||||||
|
.call,
|
||||||
|
.call_comma,
|
||||||
|
.call_one,
|
||||||
|
.call_one_comma,
|
||||||
|
.async_call,
|
||||||
|
.async_call_comma,
|
||||||
|
.async_call_one,
|
||||||
|
.async_call_one_comma,
|
||||||
|
=> |c| {
|
||||||
|
var buf: [1]ast.Node.Index = undefined;
|
||||||
|
const call: ast.full.Call = switch (c) {
|
||||||
|
.call, .call_comma, .async_call, .async_call_comma => tree.callFull(node),
|
||||||
|
.call_one, .call_one_comma, .async_call_one, .async_call_one_comma => tree.callOne(&buf, node),
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
if (call.ast.fn_expr != 0)
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = call.ast.fn_expr, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
|
||||||
|
for (call.ast.params) |param| {
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = param, .handle = handle }, decl, encoding, context, handler);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.ArrayType => {
|
.slice,
|
||||||
const info = node.castTag(.ArrayType).?;
|
.slice_sentinel,
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = info.len_expr, .handle = handle }, decl, encoding, context, handler);
|
.slice_open,
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = info.rhs, .handle = handle }, decl, encoding, context, handler);
|
=> |s| {
|
||||||
},
|
const slice: ast.full.Slice = switch (s) {
|
||||||
.ArrayTypeSentinel => {
|
.slice => tree.slice(node),
|
||||||
const info = node.castTag(.ArrayTypeSentinel).?;
|
.slice_open => tree.sliceOpen(node),
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = info.len_expr, .handle = handle }, decl, encoding, context, handler);
|
.slice_sentinel => tree.sliceSentinel(node),
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = info.sentinel, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = info.rhs, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
},
|
|
||||||
.PtrType, .SliceType => {
|
|
||||||
const info = switch (node.tag) {
|
|
||||||
.PtrType => node.castTag(.PtrType).?.ptr_info,
|
|
||||||
.SliceType => node.castTag(.SliceType).?.ptr_info,
|
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (info.align_info) |align_info| {
|
try symbolReferencesInternal(arena, store, .{ .node = slice.ast.sliced, .handle = handle }, decl, encoding, context, handler);
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = align_info.node, .handle = handle }, decl, encoding, context, handler);
|
try symbolReferencesInternal(arena, store, .{ .node = slice.ast.start, .handle = handle }, decl, encoding, context, handler);
|
||||||
if (align_info.bit_range) |range| {
|
if (slice.ast.end != 0)
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = range.start, .handle = handle }, decl, encoding, context, handler);
|
try symbolReferencesInternal(arena, store, .{ .node = slice.ast.end, .handle = handle }, decl, encoding, context, handler);
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = range.end, .handle = handle }, decl, encoding, context, handler);
|
if (slice.ast.sentinel != 0)
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = slice.ast.sentinel, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
},
|
||||||
|
.array_access => {
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = datas[node].rhs, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
},
|
||||||
|
.deref,
|
||||||
|
.unwrap_optional,
|
||||||
|
=> {
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
},
|
||||||
|
.grouped_expression => {
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
},
|
||||||
|
.@"return",
|
||||||
|
.@"break",
|
||||||
|
.@"continue",
|
||||||
|
=> {
|
||||||
|
if (datas[node].lhs != 0) {
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
.@"suspend" => {
|
||||||
|
if (datas[node].lhs != 0) {
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler);
|
||||||
}
|
}
|
||||||
if (info.sentinel) |sentinel| {
|
},
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = sentinel, .handle = handle }, decl, encoding, context, handler);
|
.builtin_call,
|
||||||
}
|
.builtin_call_comma,
|
||||||
switch (node.tag) {
|
.builtin_call_two,
|
||||||
.PtrType => try symbolReferencesInternal(arena, store, .{ .node = node.castTag(.PtrType).?.rhs, .handle = handle }, decl, encoding, context, handler),
|
.builtin_call_two_comma,
|
||||||
.SliceType => try symbolReferencesInternal(arena, store, .{ .node = node.castTag(.SliceType).?.rhs, .handle = handle }, decl, encoding, context, handler),
|
=> |builtin_tag| {
|
||||||
|
const data = datas[node];
|
||||||
|
const params = switch (builtin_tag) {
|
||||||
|
.builtin_call, .builtin_call_comma => tree.extra_data[data.lhs..data.rhs],
|
||||||
|
.builtin_call_two, .builtin_call_two_comma => if (data.lhs == 0)
|
||||||
|
&[_]ast.Node.Index{}
|
||||||
|
else if (data.rhs == 0)
|
||||||
|
&[_]ast.Node.Index{data.lhs}
|
||||||
|
else
|
||||||
|
&[_]ast.Node.Index{ data.lhs, data.rhs },
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
};
|
||||||
},
|
|
||||||
.AddressOf, .Await, .BitNot, .BoolNot, .OptionalType, .Negation, .NegationWrap, .Resume, .Try => {
|
|
||||||
const prefix_op = node.cast(ast.Node.SimplePrefixOp).?;
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = prefix_op.rhs, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
},
|
|
||||||
.FieldInitializer => {
|
|
||||||
// TODO Rename field initializer names when needed
|
|
||||||
const field_init = node.cast(ast.Node.FieldInitializer).?;
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = field_init.expr, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
},
|
|
||||||
.ArrayInitializer => {
|
|
||||||
const array_init = node.cast(ast.Node.ArrayInitializer).?;
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = array_init.lhs, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
for (array_init.listConst()) |child| {
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = child, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.ArrayInitializerDot => {
|
|
||||||
const array_init = node.cast(ast.Node.ArrayInitializerDot).?;
|
|
||||||
for (array_init.listConst()) |child| {
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = child, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.StructInitializer => {
|
|
||||||
// TODO Rename field initializer names when needed
|
|
||||||
const struct_init = node.cast(ast.Node.StructInitializer).?;
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = struct_init.lhs, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
for (struct_init.listConst()) |child| {
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = child, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.StructInitializerDot => {
|
|
||||||
const struct_init = node.cast(ast.Node.StructInitializerDot).?;
|
|
||||||
for (struct_init.listConst()) |child| {
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = child, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.Call => {
|
|
||||||
const call = node.cast(ast.Node.Call).?;
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = call.lhs, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
for (call.paramsConst()) |param| {
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = param, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.Slice => {
|
|
||||||
const slice = node.castTag(.Slice).?;
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = slice.lhs, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = slice.start, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
if (slice.end) |end| {
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = end, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
}
|
|
||||||
if (slice.sentinel) |sentinel| {
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = sentinel, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.ArrayAccess => {
|
|
||||||
const arr_acc = node.castTag(.ArrayAccess).?;
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = arr_acc.lhs, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = arr_acc.index_expr, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
},
|
|
||||||
.Deref, .UnwrapOptional => {
|
|
||||||
const suffix = node.cast(ast.Node.SimpleSuffixOp).?;
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = suffix.lhs, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
},
|
|
||||||
.GroupedExpression => {
|
|
||||||
const grouped = node.cast(ast.Node.GroupedExpression).?;
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = grouped.expr, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
},
|
|
||||||
.Return, .Break, .Continue => {
|
|
||||||
const cfe = node.cast(ast.Node.ControlFlowExpression).?;
|
|
||||||
if (cfe.getRHS()) |rhs| {
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = rhs, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.Suspend => {
|
|
||||||
const suspend_node = node.cast(ast.Node.Suspend).?;
|
|
||||||
if (suspend_node.body) |body| {
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = body, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.BuiltinCall => {
|
|
||||||
const builtin_call = node.cast(ast.Node.BuiltinCall).?;
|
|
||||||
for (builtin_call.paramsConst()) |param| {
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = param, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// TODO Inline asm expr
|
|
||||||
.TestDecl => {
|
|
||||||
const test_decl = node.cast(ast.Node.TestDecl).?;
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = test_decl.body_node, .handle = handle }, decl, encoding, context, handler);
|
|
||||||
},
|
|
||||||
.Period => {
|
|
||||||
const infix_op = node.cast(ast.Node.SimpleInfixOp).?;
|
|
||||||
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = infix_op.lhs, .handle = handle }, decl, encoding, context, handler);
|
for (params) |param|
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = param, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
},
|
||||||
|
.@"asm",
|
||||||
|
.asm_simple,
|
||||||
|
=> |a| {
|
||||||
|
const _asm: ast.full.Asm = if (a == .@"asm") tree.asmFull(node) else tree.asmSimple(node);
|
||||||
|
if (_asm.ast.items.len == 0)
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = _asm.ast.template, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
|
||||||
const rhs_str = analysis.nodeToString(handle.tree, infix_op.rhs) orelse return;
|
for (_asm.inputs) |input|
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = input, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
|
||||||
|
for (_asm.outputs) |output|
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = output, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
},
|
||||||
|
.test_decl => {
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = datas[node].rhs, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
},
|
||||||
|
.field_access => {
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
|
||||||
|
const rhs_str = tree.tokenSlice(datas[node].rhs);
|
||||||
var bound_type_params = analysis.BoundTypeParams.init(&arena.allocator);
|
var bound_type_params = analysis.BoundTypeParams.init(&arena.allocator);
|
||||||
const left_type = try analysis.resolveFieldAccessLhsType(
|
const left_type = try analysis.resolveFieldAccessLhsType(
|
||||||
store,
|
store,
|
||||||
arena,
|
arena,
|
||||||
(try analysis.resolveTypeOfNodeInternal(store, arena, .{
|
(try analysis.resolveTypeOfNodeInternal(store, arena, .{
|
||||||
.node = infix_op.lhs,
|
.node = datas[node].lhs,
|
||||||
.handle = handle,
|
.handle = handle,
|
||||||
}, &bound_type_params)) orelse return,
|
}, &bound_type_params)) orelse return,
|
||||||
&bound_type_params,
|
&bound_type_params,
|
||||||
@ -350,15 +466,53 @@ fn symbolReferencesInternal(
|
|||||||
!left_type.type.is_type_val,
|
!left_type.type.is_type_val,
|
||||||
)) |child| {
|
)) |child| {
|
||||||
if (std.meta.eql(child, decl)) {
|
if (std.meta.eql(child, decl)) {
|
||||||
try tokenReference(handle, infix_op.rhs.firstToken(), encoding, context, handler);
|
try tokenReference(handle, datas[node].rhs, encoding, context, handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.Add, .AddWrap, .ArrayCat, .ArrayMult, .Assign, .AssignBitAnd, .AssignBitOr, .AssignBitShiftLeft, .AssignBitShiftRight, .AssignBitXor, .AssignDiv, .AssignSub, .AssignSubWrap, .AssignMod, .AssignAdd, .AssignAddWrap, .AssignMul, .AssignMulWrap, .BangEqual, .BitAnd, .BitOr, .BitShiftLeft, .BitShiftRight, .BitXor, .BoolOr, .Div, .EqualEqual, .ErrorUnion, .GreaterOrEqual, .GreaterThan, .LessOrEqual, .LessThan, .MergeErrorSets, .Mod, .Mul, .MulWrap, .Range, .Sub, .SubWrap, .OrElse => {
|
.add,
|
||||||
const infix_op = node.cast(ast.Node.SimpleInfixOp).?;
|
.add_wrap,
|
||||||
|
.array_cat,
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = infix_op.lhs, .handle = handle }, decl, encoding, context, handler);
|
.array_mult,
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = infix_op.rhs, .handle = handle }, decl, encoding, context, handler);
|
.assign,
|
||||||
|
.assign_bit_and,
|
||||||
|
.assign_bit_or,
|
||||||
|
.assign_bit_shift_left,
|
||||||
|
.assign_bit_shift_right,
|
||||||
|
.assign_bit_xor,
|
||||||
|
.assign_div,
|
||||||
|
.assign_sub,
|
||||||
|
.assign_sub_wrap,
|
||||||
|
.assign_mod,
|
||||||
|
.assign_add,
|
||||||
|
.assign_add_wrap,
|
||||||
|
.assign_mul,
|
||||||
|
.assign_mul_wrap,
|
||||||
|
.bang_equal,
|
||||||
|
.bit_and,
|
||||||
|
.bit_or,
|
||||||
|
.bit_shift_left,
|
||||||
|
.bit_shift_right,
|
||||||
|
.bit_xor,
|
||||||
|
.bool_or,
|
||||||
|
.div,
|
||||||
|
.equal_equal,
|
||||||
|
.error_union,
|
||||||
|
.greater_or_equal,
|
||||||
|
.greater_than,
|
||||||
|
.less_or_equal,
|
||||||
|
.less_than,
|
||||||
|
.merge_error_sets,
|
||||||
|
.mod,
|
||||||
|
.mul,
|
||||||
|
.mul_wrap,
|
||||||
|
.switch_range,
|
||||||
|
.sub,
|
||||||
|
.sub_wrap,
|
||||||
|
.@"orelse",
|
||||||
|
=> {
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler);
|
||||||
|
try symbolReferencesInternal(arena, store, .{ .node = datas[node].rhs, .handle = handle }, decl, encoding, context, handler);
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
@ -372,6 +526,7 @@ pub fn symbolReferences(
|
|||||||
include_decl: bool,
|
include_decl: bool,
|
||||||
context: anytype,
|
context: anytype,
|
||||||
comptime handler: anytype,
|
comptime handler: anytype,
|
||||||
|
skip_std_references: bool,
|
||||||
) !void {
|
) !void {
|
||||||
std.debug.assert(decl_handle.decl.* != .label_decl);
|
std.debug.assert(decl_handle.decl.* != .label_decl);
|
||||||
const curr_handle = decl_handle.handle;
|
const curr_handle = decl_handle.handle;
|
||||||
@ -381,6 +536,10 @@ pub fn symbolReferences(
|
|||||||
var handles = std.ArrayList(*DocumentStore.Handle).init(&arena.allocator);
|
var handles = std.ArrayList(*DocumentStore.Handle).init(&arena.allocator);
|
||||||
var handle_it = store.handles.iterator();
|
var handle_it = store.handles.iterator();
|
||||||
while (handle_it.next()) |entry| {
|
while (handle_it.next()) |entry| {
|
||||||
|
if (skip_std_references and std.mem.indexOf(u8, entry.key, "std") != null) {
|
||||||
|
if (!include_decl or entry.value != curr_handle)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
try handles.append(entry.value);
|
try handles.append(entry.value);
|
||||||
}
|
}
|
||||||
for (handles.items) |handle| {
|
for (handles.items) |handle| {
|
||||||
@ -388,7 +547,7 @@ pub fn symbolReferences(
|
|||||||
try tokenReference(curr_handle, decl_handle.nameToken(), encoding, context, handler);
|
try tokenReference(curr_handle, decl_handle.nameToken(), encoding, context, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = &handle.tree.root_node.base, .handle = handle }, decl_handle, encoding, context, handler);
|
try symbolReferencesInternal(arena, store, .{ .node = 0, .handle = handle }, decl_handle, encoding, context, handler);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.param_decl => |param| {
|
.param_decl => |param| {
|
||||||
@ -396,14 +555,28 @@ pub fn symbolReferences(
|
|||||||
if (include_decl) {
|
if (include_decl) {
|
||||||
try tokenReference(curr_handle, decl_handle.nameToken(), encoding, context, handler);
|
try tokenReference(curr_handle, decl_handle.nameToken(), encoding, context, handler);
|
||||||
}
|
}
|
||||||
const fn_node = loop: for (curr_handle.document_scope.scopes) |scope| {
|
const fn_node: ast.full.FnProto = loop: for (curr_handle.document_scope.scopes) |scope| {
|
||||||
switch (scope.data) {
|
switch (scope.data) {
|
||||||
.function => |proto| {
|
.function => |proto| {
|
||||||
const fn_proto = proto.cast(std.zig.ast.Node.FnProto).?;
|
var buf: [1]ast.Node.Index = undefined;
|
||||||
for (fn_proto.paramsConst()) |*candidate| {
|
const fn_proto = analysis.fnProto(curr_handle.tree, proto, &buf).?;
|
||||||
if (candidate == param)
|
var it = fn_proto.iterate(curr_handle.tree);
|
||||||
|
while (it.next()) |candidate| {
|
||||||
|
if (std.meta.eql(candidate, param)) {
|
||||||
|
if (curr_handle.tree.nodes.items(.tag)[proto] == .fn_decl) {
|
||||||
|
try symbolReferencesInternal(
|
||||||
|
arena,
|
||||||
|
store,
|
||||||
|
.{ .node = curr_handle.tree.nodes.items(.data)[proto].rhs, .handle = curr_handle },
|
||||||
|
decl_handle,
|
||||||
|
encoding,
|
||||||
|
context,
|
||||||
|
handler,
|
||||||
|
);
|
||||||
|
}
|
||||||
break :loop fn_proto;
|
break :loop fn_proto;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
@ -411,15 +584,12 @@ pub fn symbolReferences(
|
|||||||
log.warn("Could not find param decl's function", .{});
|
log.warn("Could not find param decl's function", .{});
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if (fn_node.getBodyNode()) |body| {
|
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = body, .handle = curr_handle }, decl_handle, encoding, context, handler);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
.pointer_payload, .array_payload, .switch_payload => {
|
.pointer_payload, .switch_payload, .array_payload, .array_index => {
|
||||||
if (include_decl) {
|
if (include_decl) {
|
||||||
try tokenReference(curr_handle, decl_handle.nameToken(), encoding, context, handler);
|
try tokenReference(curr_handle, decl_handle.nameToken(), encoding, context, handler);
|
||||||
}
|
}
|
||||||
try symbolReferencesInternal(arena, store, .{ .node = &curr_handle.tree.root_node.base, .handle = curr_handle }, decl_handle, encoding, context, handler);
|
try symbolReferencesInternal(arena, store, .{ .node = 0, .handle = curr_handle }, decl_handle, encoding, context, handler);
|
||||||
},
|
},
|
||||||
.label_decl => unreachable,
|
.label_decl => unreachable,
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ pub fn renameSymbol(
|
|||||||
.edits = edits,
|
.edits = edits,
|
||||||
.allocator = &arena.allocator,
|
.allocator = &arena.allocator,
|
||||||
.new_name = new_name,
|
.new_name = new_name,
|
||||||
}, refHandler);
|
}, refHandler, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn renameLabel(
|
pub fn renameLabel(
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -4,13 +4,16 @@ const headerPkg = @import("header");
|
|||||||
const suffix = if (std.builtin.os.tag == .windows) ".exe" else "";
|
const suffix = if (std.builtin.os.tag == .windows) ".exe" else "";
|
||||||
const allocator = std.heap.page_allocator;
|
const allocator = std.heap.page_allocator;
|
||||||
|
|
||||||
const initialize_message = \\{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":6896,"clientInfo":{"name":"vscode","version":"1.46.1"},"rootPath":null,"rootUri":null,"capabilities":{"workspace":{"applyEdit":true,"workspaceEdit":{"documentChanges":true,"resourceOperations":["create","rename","delete"],"failureHandling":"textOnlyTransactional"},"didChangeConfiguration":{"dynamicRegistration":true},"didChangeWatchedFiles":{"dynamicRegistration":true},"symbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]},"tagSupport":{"valueSet":[1]}},"executeCommand":{"dynamicRegistration":true},"configuration":true,"workspaceFolders":true},"textDocument":{"publishDiagnostics":{"relatedInformation":true,"versionSupport":false,"tagSupport":{"valueSet":[1,2]},"complexDiagnosticCodeSupport":true},"synchronization":{"dynamicRegistration":true,"willSave":true,"willSaveWaitUntil":true,"didSave":true},"completion":{"dynamicRegistration":true,"contextSupport":true,"completionItem":{"snippetSupport":true,"commitCharactersSupport":true,"documentationFormat":["markdown","plaintext"],"deprecatedSupport":true,"preselectSupport":true,"tagSupport":{"valueSet":[1]},"insertReplaceSupport":true},"completionItemKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]}},"hover":{"dynamicRegistration":true,"contentFormat":["markdown","plaintext"]},"signatureHelp":{"dynamicRegistration":true,"signatureInformation":{"documentationFormat":["markdown","plaintext"],"parameterInformation":{"labelOffsetSupport":true}},"contextSupport":true},"definition":{"dynamicRegistration":true,"linkSupport":true},"references":{"dynamicRegistration":true},"documentHighlight":{"dynamicRegistration":true},"documentSymbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]},"hierarchicalDocumentSymbolSupport":true,"tagSupport":{"valueSet":[1]}},"codeAction":{"dynamicRegistration":true,"isPreferredSupport":true,"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["","quickfix","refactor","refactor.extract","refactor.inline","refactor.rewrite","source","source.organizeImports"]}}},"codeLens":{"dynamicRegistration":true},"formatting":{"dynamicRegistration":true},"rangeFormatting":{"dynamicRegistration":true},"onTypeFormatting":{"dynamicRegistration":true},"rename":{"dynamicRegistration":true,"prepareSupport":true},"documentLink":{"dynamicRegistration":true,"tooltipSupport":true},"typeDefinition":{"dynamicRegistration":true,"linkSupport":true},"implementation":{"dynamicRegistration":true,"linkSupport":true},"colorProvider":{"dynamicRegistration":true},"foldingRange":{"dynamicRegistration":true,"rangeLimit":5000,"lineFoldingOnly":true},"declaration":{"dynamicRegistration":true,"linkSupport":true},"selectionRange":{"dynamicRegistration":true},"semanticTokens":{"dynamicRegistration":true,"tokenTypes":["comment","keyword","number","regexp","operator","namespace","type","struct","class","interface","enum","typeParameter","function","member","macro","variable","parameter","property","label"],"tokenModifiers":["declaration","documentation","static","abstract","deprecated","readonly"]}},"window":{"workDoneProgress":true}},"trace":"off","workspaceFolders":[{"uri":"file://./tests", "name":"root"}]}}
|
const initialize_message =
|
||||||
|
\\{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":6896,"clientInfo":{"name":"vscode","version":"1.46.1"},"rootPath":null,"rootUri":null,"capabilities":{"workspace":{"applyEdit":true,"workspaceEdit":{"documentChanges":true,"resourceOperations":["create","rename","delete"],"failureHandling":"textOnlyTransactional"},"didChangeConfiguration":{"dynamicRegistration":true},"didChangeWatchedFiles":{"dynamicRegistration":true},"symbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]},"tagSupport":{"valueSet":[1]}},"executeCommand":{"dynamicRegistration":true},"configuration":true,"workspaceFolders":true},"textDocument":{"publishDiagnostics":{"relatedInformation":true,"versionSupport":false,"tagSupport":{"valueSet":[1,2]},"complexDiagnosticCodeSupport":true},"synchronization":{"dynamicRegistration":true,"willSave":true,"willSaveWaitUntil":true,"didSave":true},"completion":{"dynamicRegistration":true,"contextSupport":true,"completionItem":{"snippetSupport":true,"commitCharactersSupport":true,"documentationFormat":["markdown","plaintext"],"deprecatedSupport":true,"preselectSupport":true,"tagSupport":{"valueSet":[1]},"insertReplaceSupport":true},"completionItemKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]}},"hover":{"dynamicRegistration":true,"contentFormat":["markdown","plaintext"]},"signatureHelp":{"dynamicRegistration":true,"signatureInformation":{"documentationFormat":["markdown","plaintext"],"parameterInformation":{"labelOffsetSupport":true}},"contextSupport":true},"definition":{"dynamicRegistration":true,"linkSupport":true},"references":{"dynamicRegistration":true},"documentHighlight":{"dynamicRegistration":true},"documentSymbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]},"hierarchicalDocumentSymbolSupport":true,"tagSupport":{"valueSet":[1]}},"codeAction":{"dynamicRegistration":true,"isPreferredSupport":true,"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["","quickfix","refactor","refactor.extract","refactor.inline","refactor.rewrite","source","source.organizeImports"]}}},"codeLens":{"dynamicRegistration":true},"formatting":{"dynamicRegistration":true},"rangeFormatting":{"dynamicRegistration":true},"onTypeFormatting":{"dynamicRegistration":true},"rename":{"dynamicRegistration":true,"prepareSupport":true},"documentLink":{"dynamicRegistration":true,"tooltipSupport":true},"typeDefinition":{"dynamicRegistration":true,"linkSupport":true},"implementation":{"dynamicRegistration":true,"linkSupport":true},"colorProvider":{"dynamicRegistration":true},"foldingRange":{"dynamicRegistration":true,"rangeLimit":5000,"lineFoldingOnly":true},"declaration":{"dynamicRegistration":true,"linkSupport":true},"selectionRange":{"dynamicRegistration":true},"semanticTokens":{"dynamicRegistration":true,"tokenTypes":["comment","keyword","number","regexp","operator","namespace","type","struct","class","interface","enum","typeParameter","function","member","macro","variable","parameter","property","label"],"tokenModifiers":["declaration","documentation","static","abstract","deprecated","readonly"]}},"window":{"workDoneProgress":true}},"trace":"off","workspaceFolders":[{"uri":"file://./tests", "name":"root"}]}}
|
||||||
;
|
;
|
||||||
|
|
||||||
const initialized_message = \\{"jsonrpc":"2.0","method":"initialized","params":{}}
|
const initialized_message =
|
||||||
|
\\{"jsonrpc":"2.0","method":"initialized","params":{}}
|
||||||
;
|
;
|
||||||
|
|
||||||
const shutdown_message = \\{"jsonrpc":"2.0", "id":"STDWN", "method":"shutdown","params":{}}
|
const shutdown_message =
|
||||||
|
\\{"jsonrpc":"2.0", "id":"STDWN", "method":"shutdown","params":{}}
|
||||||
;
|
;
|
||||||
|
|
||||||
fn sendRequest(req: []const u8, process: *std.ChildProcess) !void {
|
fn sendRequest(req: []const u8, process: *std.ChildProcess) !void {
|
||||||
@ -22,7 +25,7 @@ fn readResponses(process: *std.ChildProcess, expected_responses: anytype) !void
|
|||||||
var seen = std.mem.zeroes([expected_responses.len]bool);
|
var seen = std.mem.zeroes([expected_responses.len]bool);
|
||||||
while (true) {
|
while (true) {
|
||||||
const header = headerPkg.readRequestHeader(allocator, process.stdout.?.reader()) catch |err| {
|
const header = headerPkg.readRequestHeader(allocator, process.stdout.?.reader()) catch |err| {
|
||||||
switch(err) {
|
switch (err) {
|
||||||
error.EndOfStream => break,
|
error.EndOfStream => break,
|
||||||
else => return err,
|
else => return err,
|
||||||
}
|
}
|
||||||
@ -52,7 +55,7 @@ fn readResponses(process: *std.ChildProcess, expected_responses: anytype) !void
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn startZls() !*std.ChildProcess {
|
fn startZls() !*std.ChildProcess {
|
||||||
var process = try std.ChildProcess.init(&[_][]const u8{ "zig-cache/bin/zls" ++ suffix }, allocator);
|
var process = try std.ChildProcess.init(&[_][]const u8{"zig-cache/bin/zls" ++ suffix}, allocator);
|
||||||
process.stdin_behavior = .Pipe;
|
process.stdin_behavior = .Pipe;
|
||||||
process.stdout_behavior = .Pipe;
|
process.stdout_behavior = .Pipe;
|
||||||
process.stderr_behavior = std.ChildProcess.StdIo.Inherit;
|
process.stderr_behavior = std.ChildProcess.StdIo.Inherit;
|
||||||
@ -89,10 +92,12 @@ test "Open file, ask for semantic tokens" {
|
|||||||
try sendRequest(initialize_message, process);
|
try sendRequest(initialize_message, process);
|
||||||
try sendRequest(initialized_message, process);
|
try sendRequest(initialized_message, process);
|
||||||
|
|
||||||
const new_file_req = \\{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file://./tests/test.zig","languageId":"zig","version":420,"text":"const std = @import(\"std\");"}}}
|
const new_file_req =
|
||||||
|
\\{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file://./tests/test.zig","languageId":"zig","version":420,"text":"const std = @import(\"std\");"}}}
|
||||||
;
|
;
|
||||||
try sendRequest(new_file_req, process);
|
try sendRequest(new_file_req, process);
|
||||||
const sem_toks_req = \\{"jsonrpc":"2.0","id":2,"method":"textDocument/semanticTokens/full","params":{"textDocument":{"uri":"file://./tests/test.zig"}}}
|
const sem_toks_req =
|
||||||
|
\\{"jsonrpc":"2.0","id":2,"method":"textDocument/semanticTokens/full","params":{"textDocument":{"uri":"file://./tests/test.zig"}}}
|
||||||
;
|
;
|
||||||
try sendRequest(sem_toks_req, process);
|
try sendRequest(sem_toks_req, process);
|
||||||
try sendRequest(shutdown_message, process);
|
try sendRequest(shutdown_message, process);
|
||||||
@ -106,10 +111,12 @@ test "Requesting a completion in an empty file" {
|
|||||||
try sendRequest(initialize_message, process);
|
try sendRequest(initialize_message, process);
|
||||||
try sendRequest(initialized_message, process);
|
try sendRequest(initialized_message, process);
|
||||||
|
|
||||||
const new_file_req = \\{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///test.zig","languageId":"zig","version":420,"text":""}}}
|
const new_file_req =
|
||||||
|
\\{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///test.zig","languageId":"zig","version":420,"text":""}}}
|
||||||
;
|
;
|
||||||
try sendRequest(new_file_req, process);
|
try sendRequest(new_file_req, process);
|
||||||
const completion_req = \\{"jsonrpc":"2.0","id":2,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///test.zig"}, "position":{"line":0,"character":0}}}
|
const completion_req =
|
||||||
|
\\{"jsonrpc":"2.0","id":2,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///test.zig"}, "position":{"line":0,"character":0}}}
|
||||||
;
|
;
|
||||||
try sendRequest(completion_req, process);
|
try sendRequest(completion_req, process);
|
||||||
try sendRequest(shutdown_message, process);
|
try sendRequest(shutdown_message, process);
|
||||||
@ -121,19 +128,22 @@ test "Requesting a completion with no trailing whitespace" {
|
|||||||
try sendRequest(initialize_message, process);
|
try sendRequest(initialize_message, process);
|
||||||
try sendRequest(initialized_message, process);
|
try sendRequest(initialized_message, process);
|
||||||
|
|
||||||
const new_file_req = \\{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///test.zig","languageId":"zig","version":420,"text":"const std = @import(\"std\");\nc"}}}
|
const new_file_req =
|
||||||
|
\\{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///test.zig","languageId":"zig","version":420,"text":"const std = @import(\"std\");\nc"}}}
|
||||||
;
|
;
|
||||||
try sendRequest(new_file_req, process);
|
try sendRequest(new_file_req, process);
|
||||||
const completion_req = \\{"jsonrpc":"2.0","id":2,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///test.zig"}, "position":{"line":1,"character":1}}}
|
const completion_req =
|
||||||
|
\\{"jsonrpc":"2.0","id":2,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///test.zig"}, "position":{"line":1,"character":1}}}
|
||||||
;
|
;
|
||||||
try sendRequest(completion_req, process);
|
try sendRequest(completion_req, process);
|
||||||
try sendRequest(shutdown_message, process);
|
try sendRequest(shutdown_message, process);
|
||||||
try consumeOutputAndWait(process, .{
|
try consumeOutputAndWait(process, .{
|
||||||
\\{"jsonrpc":"2.0","id":2,"result":{"isIncomplete":false,"items":[]}}
|
\\{"jsonrpc":"2.0","id":2,"result":{"isIncomplete":false,"items":[{"label":"std","kind":21,"textEdit":null,"filterText":null,"insertText":null,"insertTextFormat":1,"detail":"const std = @import(\"std\")","documentation":null}]}}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialize_message_offs = \\{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":6896,"clientInfo":{"name":"vscode","version":"1.46.1"},"rootPath":null,"rootUri":null,"capabilities":{"offsetEncoding":["utf-16", "utf-8"],"workspace":{"applyEdit":true,"workspaceEdit":{"documentChanges":true,"resourceOperations":["create","rename","delete"],"failureHandling":"textOnlyTransactional"},"didChangeConfiguration":{"dynamicRegistration":true},"didChangeWatchedFiles":{"dynamicRegistration":true},"symbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]},"tagSupport":{"valueSet":[1]}},"executeCommand":{"dynamicRegistration":true},"configuration":true,"workspaceFolders":true},"textDocument":{"publishDiagnostics":{"relatedInformation":true,"versionSupport":false,"tagSupport":{"valueSet":[1,2]},"complexDiagnosticCodeSupport":true},"synchronization":{"dynamicRegistration":true,"willSave":true,"willSaveWaitUntil":true,"didSave":true},"completion":{"dynamicRegistration":true,"contextSupport":true,"completionItem":{"snippetSupport":true,"commitCharactersSupport":true,"documentationFormat":["markdown","plaintext"],"deprecatedSupport":true,"preselectSupport":true,"tagSupport":{"valueSet":[1]},"insertReplaceSupport":true},"completionItemKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]}},"hover":{"dynamicRegistration":true,"contentFormat":["markdown","plaintext"]},"signatureHelp":{"dynamicRegistration":true,"signatureInformation":{"documentationFormat":["markdown","plaintext"],"parameterInformation":{"labelOffsetSupport":true}},"contextSupport":true},"definition":{"dynamicRegistration":true,"linkSupport":true},"references":{"dynamicRegistration":true},"documentHighlight":{"dynamicRegistration":true},"documentSymbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]},"hierarchicalDocumentSymbolSupport":true,"tagSupport":{"valueSet":[1]}},"codeAction":{"dynamicRegistration":true,"isPreferredSupport":true,"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["","quickfix","refactor","refactor.extract","refactor.inline","refactor.rewrite","source","source.organizeImports"]}}},"codeLens":{"dynamicRegistration":true},"formatting":{"dynamicRegistration":true},"rangeFormatting":{"dynamicRegistration":true},"onTypeFormatting":{"dynamicRegistration":true},"rename":{"dynamicRegistration":true,"prepareSupport":true},"documentLink":{"dynamicRegistration":true,"tooltipSupport":true},"typeDefinition":{"dynamicRegistration":true,"linkSupport":true},"implementation":{"dynamicRegistration":true,"linkSupport":true},"colorProvider":{"dynamicRegistration":true},"foldingRange":{"dynamicRegistration":true,"rangeLimit":5000,"lineFoldingOnly":true},"declaration":{"dynamicRegistration":true,"linkSupport":true},"selectionRange":{"dynamicRegistration":true},"semanticTokens":{"dynamicRegistration":true,"tokenTypes":["comment","keyword","number","regexp","operator","namespace","type","struct","class","interface","enum","typeParameter","function","member","macro","variable","parameter","property","label"],"tokenModifiers":["declaration","documentation","static","abstract","deprecated","readonly"]}},"window":{"workDoneProgress":true}},"trace":"off","workspaceFolders":null}}
|
const initialize_message_offs =
|
||||||
|
\\{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":6896,"clientInfo":{"name":"vscode","version":"1.46.1"},"rootPath":null,"rootUri":null,"capabilities":{"offsetEncoding":["utf-16", "utf-8"],"workspace":{"applyEdit":true,"workspaceEdit":{"documentChanges":true,"resourceOperations":["create","rename","delete"],"failureHandling":"textOnlyTransactional"},"didChangeConfiguration":{"dynamicRegistration":true},"didChangeWatchedFiles":{"dynamicRegistration":true},"symbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]},"tagSupport":{"valueSet":[1]}},"executeCommand":{"dynamicRegistration":true},"configuration":true,"workspaceFolders":true},"textDocument":{"publishDiagnostics":{"relatedInformation":true,"versionSupport":false,"tagSupport":{"valueSet":[1,2]},"complexDiagnosticCodeSupport":true},"synchronization":{"dynamicRegistration":true,"willSave":true,"willSaveWaitUntil":true,"didSave":true},"completion":{"dynamicRegistration":true,"contextSupport":true,"completionItem":{"snippetSupport":true,"commitCharactersSupport":true,"documentationFormat":["markdown","plaintext"],"deprecatedSupport":true,"preselectSupport":true,"tagSupport":{"valueSet":[1]},"insertReplaceSupport":true},"completionItemKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]}},"hover":{"dynamicRegistration":true,"contentFormat":["markdown","plaintext"]},"signatureHelp":{"dynamicRegistration":true,"signatureInformation":{"documentationFormat":["markdown","plaintext"],"parameterInformation":{"labelOffsetSupport":true}},"contextSupport":true},"definition":{"dynamicRegistration":true,"linkSupport":true},"references":{"dynamicRegistration":true},"documentHighlight":{"dynamicRegistration":true},"documentSymbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]},"hierarchicalDocumentSymbolSupport":true,"tagSupport":{"valueSet":[1]}},"codeAction":{"dynamicRegistration":true,"isPreferredSupport":true,"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["","quickfix","refactor","refactor.extract","refactor.inline","refactor.rewrite","source","source.organizeImports"]}}},"codeLens":{"dynamicRegistration":true},"formatting":{"dynamicRegistration":true},"rangeFormatting":{"dynamicRegistration":true},"onTypeFormatting":{"dynamicRegistration":true},"rename":{"dynamicRegistration":true,"prepareSupport":true},"documentLink":{"dynamicRegistration":true,"tooltipSupport":true},"typeDefinition":{"dynamicRegistration":true,"linkSupport":true},"implementation":{"dynamicRegistration":true,"linkSupport":true},"colorProvider":{"dynamicRegistration":true},"foldingRange":{"dynamicRegistration":true,"rangeLimit":5000,"lineFoldingOnly":true},"declaration":{"dynamicRegistration":true,"linkSupport":true},"selectionRange":{"dynamicRegistration":true},"semanticTokens":{"dynamicRegistration":true,"tokenTypes":["comment","keyword","number","regexp","operator","namespace","type","struct","class","interface","enum","typeParameter","function","member","macro","variable","parameter","property","label"],"tokenModifiers":["declaration","documentation","static","abstract","deprecated","readonly"]}},"window":{"workDoneProgress":true}},"trace":"off","workspaceFolders":null}}
|
||||||
;
|
;
|
||||||
|
|
||||||
test "Requesting utf-8 offset encoding" {
|
test "Requesting utf-8 offset encoding" {
|
||||||
|
Loading…
Reference in New Issue
Block a user