More type resolving

This commit is contained in:
Luuk de Gram 2021-03-01 14:32:19 +01:00
parent b651a79380
commit 1c9da7053c
No known key found for this signature in database
GPG Key ID: A002B174963DBB7D
3 changed files with 163 additions and 122 deletions

View File

@ -252,20 +252,35 @@ fn resolveVarDeclAliasInternal(
root: bool,
) error{OutOfMemory}!?DeclWithHandle {
const handle = node_handle.handle;
if (node_handle.node.castTag(.Identifier)) |ident| {
return try lookupSymbolGlobal(store, arena, handle, handle.tree.tokenSlice(ident.token), handle.tree.token_locs[ident.token].start);
const tree = handle.tree;
const node_tags = tree.nodes.items(.tag);
const main_tokens = tree.nodes.items(.main_token);
const datas = tree.nodes.items(.data);
if (node_tags[node_handle.node] == .identifier) {
const token = main_tokens[node_handle.node];
return try lookupSymbolGlobal(
store,
arena,
handle,
tree.tokenSlice(token),
tree.tokenLocation(0, token).line_start,
);
}
if (node_handle.node.cast(ast.Node.SimpleInfixOp)) |infix_op| {
if (node_handle.node.tag != .Period) return null;
if (node_tags[node_handle.node] == .field_access) {
const lhs = datas[node_handle.node].lhs;
const container_node = if (infix_op.lhs.castTag(.BuiltinCall)) |builtin_call| block: {
if (!std.mem.eql(u8, handle.tree.tokenSlice(builtin_call.builtin_token), "@import"))
const container_node = if (isBuiltinCall(tree, lhs)) block: {
const builtin = builtinCallParams(tree, lhs);
if (!std.mem.eql(u8, tree.tokenSlice(main_tokens[lhs]), "@import"))
return null;
const inner_node = (try resolveTypeOfNode(store, arena, .{ .node = infix_op.lhs, .handle = handle })) orelse return null;
std.debug.assert(inner_node.type.data.other.tag == .Root);
const inner_node = (try resolveTypeOfNode(store, arena, .{ .node = lhs, .handle = handle })) orelse return null;
// assert root node
std.debug.assert(inner_node.type.data.other == 0);
break :block NodeWithHandle{ .node = inner_node.type.data.other, .handle = inner_node.handle };
} else if (try resolveVarDeclAliasInternal(store, arena, .{ .node = infix_op.lhs, .handle = handle }, false)) |decl_handle| block: {
} else if (try resolveVarDeclAliasInternal(store, arena, .{ .node = lhs, .handle = handle }, false)) |decl_handle| block: {
if (decl_handle.decl.* != .ast_node) return null;
const resolved = (try resolveTypeOfNode(store, arena, .{ .node = decl_handle.decl.ast_node, .handle = decl_handle.handle })) orelse return null;
const resolved_node = switch (resolved.type.data) {
@ -273,11 +288,11 @@ fn resolveVarDeclAliasInternal(
else => return null,
};
if (resolved_node.tag != .ContainerDecl and resolved_node.tag != .Root) return null;
if (!isContainer(node_tags[resolved_node])) return null;
break :block NodeWithHandle{ .node = resolved_node, .handle = resolved.handle };
} else return null;
if (try lookupSymbolContainer(store, arena, container_node, handle.tree.tokenSlice(infix_op.rhs.firstToken()), false)) |inner_decl| {
if (try lookupSymbolContainer(store, arena, container_node, tree.tokenSlice(tree.firstToken(datas[lhs].rhs)), false)) |inner_decl| {
if (root) return inner_decl;
return inner_decl;
}
@ -294,18 +309,22 @@ fn resolveVarDeclAliasInternal(
pub fn resolveVarDeclAlias(store: *DocumentStore, arena: *std.heap.ArenaAllocator, decl_handle: NodeWithHandle) !?DeclWithHandle {
const decl = decl_handle.node;
const handle = decl_handle.handle;
const tree = handle.tree;
const token_tags = tree.tokens.items(.tag);
const main_tokes = tree.nodes.items(.main_token);
const node_tags = tree.nodes.items(.tag);
if (decl.castTag(.VarDecl)) |var_decl| {
const base_expr = var_decl.getInitNode() orelse return null;
if (handle.tree.token_ids[var_decl.mut_token] != .Keyword_const) return null;
if (varDecl(handle.tree, decl)) |var_decl| {
if (var_decl.ast.init_node == 0) return null;
const base_exp = var_decl.ast.init_node;
if (token_tags[main_tokes[base_exp]] != .keyword_const) return null;
if (base_expr.cast(ast.Node.SimpleInfixOp)) |infix_op| {
if (base_expr.tag != .Period) return null;
const name = handle.tree.tokenSlice(infix_op.rhs.firstToken());
if (!std.mem.eql(u8, handle.tree.tokenSlice(var_decl.name_token), name))
if (node_tags[base_exp] == .field_access) {
const name = tree.tokenSlice(tree.firstToken(tree.nodes.items(.data)[base_exp].rhs));
if (!std.mem.eql(u8, tree.tokenSlice(var_decl.ast.mut_token + 1), name))
return null;
return try resolveVarDeclAliasInternal(store, arena, .{ .node = base_expr, .handle = handle }, true);
return try resolveVarDeclAliasInternal(store, arena, .{ .node = base_exp, .handle = handle }, true);
}
}
@ -320,6 +339,7 @@ fn findReturnStatementInternal(
) ?*ast.Node.ControlFlowExpression {
var result: ?*ast.Node.ControlFlowExpression = null;
var child_idx: usize = 0;
while (base_node.iterate(child_idx)) |child_node| : (child_idx += 1) {
if (child_node.castTag(.Return)) |cfe| {
// If we are calling ourselves recursively, ignore this return.
@ -464,9 +484,10 @@ fn resolveBracketAccessType(
else => return null,
};
const tags = lhs.handle.tree.nodes.items(.tag);
const tree = lhs.handle.tree;
const tags = tree.nodes.items(.tag);
const tag = tags[lhs_node];
const data = lhs.handle.tree.nodes.items(.data)[lhs_node];
const data = tree.nodes.items(.data)[lhs_node];
if (tag == .array_type or tag == .array_type_sentinel) {
if (rhs == .Single)
return ((try resolveTypeOfNodeInternal(store, arena, .{
@ -481,7 +502,7 @@ fn resolveBracketAccessType(
if (tags[data.rhs] == .array_type or tags[data.rhs] == .array_type_sentinel) {
if (rhs == .Single) {
return ((try resolveTypeOfNodeInternal(store, arena, .{
.node = lhs.handle.tree.nodes.items(.data)[data.rhs].rhs,
.node = tree.nodes.items(.data)[data.rhs].rhs,
.handle = lhs.handle,
}, bound_type_params)) orelse return null).instanceTypeVal();
}
@ -635,25 +656,19 @@ pub fn resolveTypeOfNodeInternal(
};
var buf: [1]ast.Node.Index = undefined;
const func_maybe: ?ast.full.FnProto = switch (node_tags[decl_node]) {
.fn_proto => tree.fnProto(decl_node),
.fn_proto_one => tree.fnProtoOne(&buf, decl_node),
.fn_proto_multi => tree.fnProtoMulti(decl_node),
.fn_proto_simple => tree.fnProtoSimple(&buf, decl_node),
else => null,
};
const func_maybe = fnProto(tree, decl_node, &buf);
if (func_maybe) |fn_decl| {
// check for x.y(..). if '.' is found, it means first param should be skipped
const has_self_param = token_tags[call.ast.lparen - 2] == .period;
var it = fn_decl.iterate();
var it = fn_decl.iterate(tree);
// Bind type params to the expressions passed in the calls.
const param_len = std.math.min(call.ast.params.len + @boolToInt(has_self_param), fn_decl.ast.params.len);
while (it.next()) |decl_param| {
if (it.param_i == 0 and has_self_param) continue;
if (it.param_i >= param_len) break;
if (!typeIsType(decl_param.type_expr)) continue;
if (!typeIsType(tree, decl_param.type_expr)) continue;
const call_param_type = (try resolveTypeOfNodeInternal(store, arena, .{
.node = call.ast.params[it.param_i - @boolToInt(has_self_param)],
@ -661,7 +676,7 @@ pub fn resolveTypeOfNodeInternal(
}, bound_type_params)) orelse continue;
if (!call_param_type.type.is_type_val) continue;
_ = try bound_type_params.put(decl_param, call_param_type);
_ = try bound_type_params.put(&decl_param, call_param_type);
}
return try resolveReturnType(store, arena, fn_decl, decl.handle, bound_type_params);
@ -675,7 +690,6 @@ pub fn resolveTypeOfNodeInternal(
return try resolveTypeOfNodeInternal(store, arena, .{ .node = datas[node].lhs, .handle = handle }, bound_type_params);
},
.struct_init, .struct_init_comma, .struct_init_one, .struct_init_one_comma => {
const struct_init = node.castTag(.StructInitializer).?;
return ((try resolveTypeOfNodeInternal(
store,
arena,
@ -688,14 +702,14 @@ pub fn resolveTypeOfNodeInternal(
},
.slice, .slice_sentinel, .slice_open => {
const left_type = (try resolveTypeOfNodeInternal(store, arena, .{
.node = dates[node].lhs,
.node = datas[node].lhs,
.handle = handle,
}, bound_type_params)) orelse return null;
return try resolveBracketAccessType(store, arena, left_type, .Range, bound_type_params);
},
.deref, .unwrap_optional => {
const left_type = (try resolveTypeOfNodeInternal(store, arena, .{
.node = dates[node].lhs,
.node = datas[node].lhs,
.handle = handle,
}, bound_type_params)) orelse return null;
return switch (node_tags[node]) {
@ -758,7 +772,6 @@ pub fn resolveTypeOfNodeInternal(
.array_type_sentinel,
.optional_type,
.ptr_type_aligned,
.ptr_type.aligned,
.ptr_type,
.ptr_type_bit_range,
=> return TypeWithHandle.typeVal(node_handle),
@ -855,13 +868,7 @@ pub fn resolveTypeOfNodeInternal(
},
.fn_proto, .fn_proto_multi, .fn_proto_one, .fn_proto_simple => {
var buf: [1]ast.Node.Index = undefined;
const fn_proto: ast.full.FnProto = switch (node_tags[node]) {
.fn_proto => tree.fnProto(node),
.fn_proto_multi => tree.fnProtoMulti(node),
.fn_proto_one => tree.fnProtoOne(&buf, node),
.fn_proto_simple => tree.fnProtoSimple(&buf, node),
else => unreachable,
};
const fn_proto = fnProto(tree, node, &buf).?;
// This is a function type
if (fn_proto.name_token == null) {
@ -965,10 +972,11 @@ pub const TypeWithHandle = struct {
var buf: [1]ast.Node.Index = undefined;
switch (self.type.data) {
.other => |n| return switch (tree.nodes.items(.tag)[n]) {
.fn_proto => isTypeFunction(tree, tree.fnProto(n)),
.fn_proto_multi => isTypeFunction(tree, tree.fnProtoMulti(n)),
.fn_proto_one => isTypeFunction(tree, tree.fnProtoOne(&buf, n)),
.fn_proto_simple => isTypeFunction(tree, tree.fnProtoSimple(&buf, n)),
.fn_proto,
.fn_proto_multi,
.fn_proto_one,
.fn_proto_simple,
=> isTypeFunction(fnProto(tree, n, &buf).?),
else => false,
},
else => return false,
@ -979,10 +987,11 @@ pub const TypeWithHandle = struct {
var buf: [1]ast.Node.Index = undefined;
switch (self.type.data) {
.other => |n| return switch (tree.nodes.items(.tag)[n]) {
.fn_proto => isGenericFunction(tree, tree.fnProto(n)),
.fn_proto_multi => isGenericFunction(tree, tree.fnProtoMulti(n)),
.fn_proto_one => isGenericFunction(tree, tree.fnProtoOne(&buf, n)),
.fn_proto_simple => isGenericFunction(tree, tree.fnProtoSimple(&buf, n)),
.fn_proto,
.fn_proto_multi,
.fn_proto_one,
.fn_proto_simple,
=> isGenericFunction(fnProto(tree, n, &buf).?),
else => false,
},
else => return false,
@ -1082,6 +1091,7 @@ pub fn getFieldAccessType(
// TODO Actually bind params here when calling functions instead of just skipping args.
var bound_type_params = BoundTypeParams.init(&arena.allocator);
const tree = handle.tree;
while (true) {
const tok = tokenizer.next();
@ -1098,11 +1108,11 @@ pub fn getFieldAccessType(
.period => {
const after_period = tokenizer.next();
switch (after_period.tag) {
.Eof => return FieldAccessReturn{
.eof => return FieldAccessReturn{
.original = current_type,
.unwrapped = try resolveDerefType(store, arena, current_type, &bound_type_params),
},
.Identifier => {
.identifier => {
if (after_period.loc.end == tokenizer.buffer.len) {
return FieldAccessReturn{
.original = current_type,
@ -1126,7 +1136,7 @@ pub fn getFieldAccessType(
current_type = (try child.resolveType(store, arena, &bound_type_params)) orelse return null;
} else return null;
},
.QuestionMark => {
.question_mark => {
current_type = (try resolveUnwrapOptionalType(store, arena, current_type, &bound_type_params)) orelse return null;
},
else => {
@ -1146,17 +1156,18 @@ pub fn getFieldAccessType(
// Can't call a function type, we need a function type instance.
if (current_type.type.is_type_val) return null;
if (current_type_node.castTag(.FnProto)) |func| {
var buf: [1]ast.Node.Index = undefined;
if (fnProto(tree, current_type_node, &buf)) |func| {
if (try resolveReturnType(store, arena, func, current_type.handle, &bound_type_params)) |ret| {
current_type = ret;
// Skip to the right paren
var paren_count: usize = 1;
var next = tokenizer.next();
while (next.tag != .Eof) : (next = tokenizer.next()) {
if (next.tag == .RParen) {
while (next.tag != .eof) : (next = tokenizer.next()) {
if (next.tag == .r_paren) {
paren_count -= 1;
if (paren_count == 0) break;
} else if (next.tag == .LParen) {
} else if (next.tag == .l_paren) {
paren_count += 1;
}
} else return null;
@ -1167,13 +1178,13 @@ pub fn getFieldAccessType(
var brack_count: usize = 1;
var next = tokenizer.next();
var is_range = false;
while (next.tag != .Eof) : (next = tokenizer.next()) {
if (next.tag == .RBracket) {
while (next.tag != .eof) : (next = tokenizer.next()) {
if (next.tag == .r_bracket) {
brack_count -= 1;
if (brack_count == 0) break;
} else if (next.tag == .LBracket) {
} else if (next.tag == .l_bracket) {
brack_count += 1;
} else if (next.tag == .Ellipsis2 and brack_count == 1) {
} else if (next.tag == .ellipsis2 and brack_count == 1) {
is_range = true;
}
} else return null;
@ -1272,14 +1283,25 @@ fn builtinCallParams(tree: ast.Tree, node: ast.Node.Index) []const ast.Node.Inde
};
}
pub fn fnProto(tree: ast.Tree, node: ast.Node.Index, buf: *[1]ast.Node.Index) ?ast.full.FnProto {
return switch (tree.nodes.items(.tag)[node]) {
.fn_proto => tree.fnProto(node),
.fn_proto_multi => tree.fnProtoMulti(node),
.fn_proto_one => tree.fnProtoOne(buf, node),
.fn_proto_simple => tree.fnProtoSimple(buf, node),
.fn_decl => tree.fnProto(tree.nodes.items(.data)[node].lhs),
else => null,
};
}
pub fn getImportStr(tree: ast.Tree, node: ast.Node.Index, source_index: usize) ?[]const u8 {
const node_tags = tree.nodes.items(.tag);
var buf: [2]ast.Node.Index = undefined;
const decls = switch (node_tags[node]) {
.root => tree.rootDecls(),
.container_decl => tree.containerDecl(node).ast.members,
.container_decl => tree.containerDeclArg(node).ast.members,
.container_decl => tree.containerDeclTwo(&buf, node).ast.members,
.container_decl, .container_decl_trailing => tree.containerDecl(node).ast.members,
.container_decl_arg, .container_decl_arg_trailing => tree.containerDeclArg(node).ast.members,
.container_decl_two, .container_decl_two_trailing => tree.containerDeclTwo(&buf, node).ast.members,
else => return null,
};
@ -1679,13 +1701,14 @@ pub const DeclWithHandle = struct {
pub fn nameToken(self: DeclWithHandle) ast.TokenIndex {
const tree = self.handle.tree;
const token_tags = tree.tokens.items(.tag);
return switch (self.decl.*) {
.ast_node => |n| getDeclNameToken(tree, n).?,
.param_decl => |p| p.name_token.?,
.pointer_payload => |pp| pp.node.value_symbol.firstToken(),
.pointer_payload => |pp| pp.name,
// .array_payload => |ap| ap.identifier.firstToken(),
.switch_payload => |sp| sp.node.value_symbol.firstToken(),
.label_decl => |ld| ld.firstToken(),
.switch_payload => |sp| sp.node + @boolToInt(token_tags[sp.node] == .asterisk),
.label_decl => |ld| ld,
};
}
@ -1797,22 +1820,18 @@ fn findContainerScope(container_handle: NodeWithHandle) ?*Scope {
const container = container_handle.node;
const handle = container_handle.handle;
if (container.tag != .ContainerDecl and container.tag != .Root and container.tag != .ErrorSetDecl) {
return null;
}
if (!isContainer(handle.tree.nodes.items(.tag)[container])) return null;
// Find the container scope.
var container_scope: ?*Scope = null;
for (handle.document_scope.scopes) |*scope| {
return for (handle.document_scope.scopes) |*scope| {
switch (scope.*.data) {
.container => |node| if (node == container) {
container_scope = scope;
break;
break container_scope;
},
else => {},
}
}
return container_scope;
} else null;
}
fn iterateSymbolsContainerInternal(
@ -1907,7 +1926,7 @@ fn iterateSymbolsGlobalInternal(
source_index: usize,
comptime callback: anytype,
context: anytype,
use_trail: *std.ArrayList(*ast.Node.Use),
use_trail: *std.ArrayList(ast.Node.Index),
) error{OutOfMemory}!void {
for (handle.document_scope.scopes) |scope| {
if (source_index >= scope.range.start and source_index < scope.range.end) {
@ -1943,7 +1962,7 @@ pub fn iterateSymbolsGlobal(
comptime callback: anytype,
context: anytype,
) error{OutOfMemory}!void {
var use_trail = std.ArrayList(*ast.Node.Use).init(&arena.allocator);
var use_trail = std.ArrayList(ast.Node.Index).init(&arena.allocator);
return try iterateSymbolsGlobalInternal(store, arena, handle, source_index, callback, context, &use_trail);
}
@ -2019,7 +2038,7 @@ fn lookupSymbolGlobalInternal(
handle: *DocumentStore.Handle,
symbol: []const u8,
source_index: usize,
use_trail: *std.ArrayList(*ast.Node.Use),
use_trail: *std.ArrayList(ast.Node.Index),
) error{OutOfMemory}!?DeclWithHandle {
for (handle.document_scope.scopes) |scope| {
if (source_index >= scope.range.start and source_index < scope.range.end) {
@ -2053,7 +2072,7 @@ pub fn lookupSymbolGlobal(
symbol: []const u8,
source_index: usize,
) error{OutOfMemory}!?DeclWithHandle {
var use_trail = std.ArrayList(*ast.Node.Use).init(&arena.allocator);
var use_trail = std.ArrayList(ast.Node.Index).init(&arena.allocator);
return try lookupSymbolGlobalInternal(store, arena, handle, symbol, source_index, &use_trail);
}
@ -2065,7 +2084,7 @@ fn lookupSymbolContainerInternal(
/// If true, we are looking up the symbol like we are accessing through a field access
/// of an instance of the type, otherwise as a field access of the type value itself.
instance_access: bool,
use_trail: *std.ArrayList(*ast.Node.Use),
use_trail: *std.ArrayList(ast.Node.Index),
) error{OutOfMemory}!?DeclWithHandle {
const container = container_handle.node;
const handle = container_handle.handle;
@ -2106,7 +2125,7 @@ pub fn lookupSymbolContainer(
/// of an instance of the type, otherwise as a field access of the type value itself.
instance_access: bool,
) error{OutOfMemory}!?DeclWithHandle {
var use_trail = std.ArrayList(*ast.Node.Use).init(&arena.allocator);
var use_trail = std.ArrayList(ast.Node.Index).init(&arena.allocator);
return try lookupSymbolContainerInternal(store, arena, container_handle, symbol, instance_access, &use_trail);
}
@ -2380,14 +2399,7 @@ fn makeScopeInternal(
switch (node) {
.fn_proto, .fn_proto_one, .fn_proto_simple, .fn_proto_multi, .fn_decl => {
var buf: [1]ast.Node.Index = undefined;
const func: ast.full.FnProto = switch (node) {
.fn_proto => tree.fnProto(node_idx),
.fn_proto_one => tree.fnProtoOne(&buf, node_idx),
.fn_proto_simple => tree.fnProtoSimple(&buf, node_idx),
.fn_proto_multi => tree.fnProtoMulti(node_idx),
.fn_decl => tree.fnProto(data[node_idx].lhs),
else => unreachable,
};
const func = fnProto(tree, node_idx, &buf).?;
(try scopes.addOne(allocator)).* = .{
.range = nodeSourceRange(tree, node_idx),

View File

@ -616,10 +616,10 @@ fn hoverSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, decl_handle
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{handle.tree.tokenSlice(payload.node.value_symbol.firstToken())})
else
try std.fmt.allocPrint(&arena.allocator, "{s}", .{handle.tree.tokenSlice(payload.node.value_symbol.firstToken())}),
.array_payload => |payload| if (hover_kind == .Markdown)
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{handle.tree.tokenSlice(payload.identifier.firstToken())})
else
try std.fmt.allocPrint(&arena.allocator, "{s}", .{handle.tree.tokenSlice(payload.identifier.firstToken())}),
// .array_payload => |payload| if (hover_kind == .Markdown)
// try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{handle.tree.tokenSlice(payload.identifier.firstToken())})
// else
// try std.fmt.allocPrint(&arena.allocator, "{s}", .{handle.tree.tokenSlice(payload.identifier.firstToken())}),
.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())})
else
@ -751,7 +751,7 @@ fn hoverDefinitionFieldAccess(
fn gotoDefinitionString(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: Config) !void {
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(
&arena.allocator,
handle.*,
@ -864,6 +864,15 @@ const DeclToCompletionContext = struct {
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 {
const tree = decl_handle.handle.tree;
@ -871,7 +880,7 @@ fn declToCompletion(context: DeclToCompletionContext, decl_handle: analysis.Decl
.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| {
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{
.kind = doc_kind,
.value = try analysis.collectDocComments(&context.arena.allocator, tree, doc_comments, doc_kind),
@ -879,34 +888,41 @@ fn declToCompletion(context: DeclToCompletionContext, decl_handle: analysis.Decl
else
null;
const first_token = param.first_doc_comment orelse
param.comptime_noalias orelse
param.name_token orelse
param.anytype_ellipsis3 orelse
tree.firstToken(param.type_expr);
const last_token = tree.lastToken(param.type_expr);
try context.completions.append(.{
.label = tree.tokenSlice(param.name_token.?),
.kind = .Constant,
.documentation = doc,
.detail = tree.source[tree.token_locs[param.firstToken()].start..tree.token_locs[param.lastToken()].end],
.detail = tree.source[tree.tokenLocation(0, first_token).line_start..tree.tokenLocation(0, last_token).line_end],
});
},
.pointer_payload => |payload| {
try context.completions.append(.{
.label = tree.tokenSlice(payload.node.value_symbol.firstToken()),
.kind = .Variable,
});
},
.array_payload => |payload| {
try context.completions.append(.{
.label = tree.tokenSlice(payload.identifier.firstToken()),
.label = tree.tokenSlice(payload.name),
.kind = .Variable,
});
},
// .array_payload => |payload| {
// try context.completions.append(.{
// .label = tree.tokenSlice(payload.identifier.firstToken()),
// .kind = .Variable,
// });
// },
.switch_payload => |payload| {
try context.completions.append(.{
.label = tree.tokenSlice(payload.node.value_symbol.firstToken()),
.label = tree.tokenSlice(tree.firstToken(payload.node)),
.kind = .Variable,
});
},
.label_decl => |label_decl| {
try context.completions.append(.{
.label = tree.tokenSlice(label_decl.firstToken()),
.label = tree.tokenSlice(label_decl),
.kind = .Variable,
});
},

View File

@ -40,11 +40,13 @@ pub fn labelReferences(
) !void {
std.debug.assert(decl.decl.* == .label_decl);
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.
// This case can be implemented just by scanning tokens.
const first_tok = decl.decl.label_decl.firstToken();
const last_tok = decl.decl.label_decl.lastToken();
const first_tok = tree.firstToken(decl.decl.label_decl);
const last_tok = tree.firstToken(decl.decl.label_decl);
if (include_decl) {
// The first token is always going to be the label
@ -53,11 +55,11 @@ pub fn labelReferences(
var curr_tok = first_tok + 1;
while (curr_tok < last_tok - 2) : (curr_tok += 1) {
const curr_id = handle.tree.token_ids[curr_tok];
if ((curr_id == .Keyword_break or curr_id == .Keyword_continue) and handle.tree.token_ids[curr_tok + 1] == .Colon and
handle.tree.token_ids[curr_tok + 2] == .Identifier)
const curr_id = token_tags[curr_tok];
if ((curr_id == .keyword_break or curr_id == .keyword_continue) and token_tags[curr_tok + 1] == .colon and
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);
}
}
@ -388,7 +390,7 @@ pub fn symbolReferences(
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| {
@ -396,14 +398,28 @@ pub fn symbolReferences(
if (include_decl) {
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) {
.function => |proto| {
const fn_proto = proto.cast(std.zig.ast.Node.FnProto).?;
for (fn_proto.paramsConst()) |*candidate| {
if (candidate == param)
var buf: [1]ast.Node.Index = undefined;
const fn_proto = analysis.fnProto(curr_handle.tree, proto, &buf).?;
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;
}
}
},
else => {},
}
@ -411,15 +427,12 @@ pub fn symbolReferences(
log.warn("Could not find param decl's function", .{});
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 => {
if (include_decl) {
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,
}