diff --git a/src/analysis.zig b/src/analysis.zig index 5fa25ef..c442dfc 100644 --- a/src/analysis.zig +++ b/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), diff --git a/src/main.zig b/src/main.zig index 350f472..c38b06c 100644 --- a/src/main.zig +++ b/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, }); }, diff --git a/src/references.zig b/src/references.zig index c2dd82c..6bef4f5 100644 --- a/src/references.zig +++ b/src/references.zig @@ -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,13 +398,27 @@ 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, }