More type resolving
This commit is contained in:
parent
b651a79380
commit
1c9da7053c
192
src/analysis.zig
192
src/analysis.zig
@ -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),
|
||||
|
48
src/main.zig
48
src/main.zig
@ -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,
|
||||
});
|
||||
},
|
||||
|
@ -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,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user