diff --git a/src/features/completions.zig b/src/features/completions.zig index 3d512e8be..7e40e31d6 100644 --- a/src/features/completions.zig +++ b/src/features/completions.zig @@ -1770,7 +1770,7 @@ fn collectFieldAccessTypes( dot_context: EnumLiteralContext, ty: Analyser.Type, types_with_handles: *Analyser.Type.ArraySet, -) error{OutOfMemory}!void { +) error{ OutOfMemory, Canceled }!void { const analyser = builder.analyser; var node_type = ty; @@ -1791,9 +1791,26 @@ fn collectFieldAccessTypes( _ = try node_type.getAllTypesWithHandlesArraySet(analyser, types_with_handles); return; } - const has_self_param = try analyser.hasSelfParam(node_type); + + const param_offset: usize = offs: { + const tree = &builder.orig_handle.tree; + const idx = switch (dot_context.type_info) { + .identifier_token_index => |idx| idx, + .expr_node_index => break :offs 0, + }; + + if (tree.tokenTag(idx - 1) != .period) break :offs 0; + const nodes = try ast.nodesOverlappingIndexIncludingParseErrors(analyser.arena, tree, tree.tokenStart(idx - 2)); + defer analyser.arena.free(nodes); + + const node = nodes[0]; + const typ = try analyser.resolveTypeOfNode(.of(node, builder.orig_handle)) orelse break :offs 0; + if (typ.is_type_val) break :offs 0; + break :offs @intFromBool(analyser.firstParamIs(node_type, try typ.typeOf(analyser))); + }; + const params = info.parameters; - const param_index = dot_context.fn_arg_index + @intFromBool(has_self_param); + const param_index = dot_context.fn_arg_index + param_offset; if (param_index >= params.len) return; const param_type = params[param_index].type; _ = try param_type.getAllTypesWithHandlesArraySet(analyser, types_with_handles); diff --git a/tests/lsp_features/completion.zig b/tests/lsp_features/completion.zig index 2254f1fcb..c6ce95fff 100644 --- a/tests/lsp_features/completion.zig +++ b/tests/lsp_features/completion.zig @@ -325,6 +325,30 @@ test "function alias" { .detail = "u32", }, }); + try testCompletion( + \\const S = struct { + \\ fn foo(_: S, _: enum{ alpha, beta }) void {} + \\ const bar = foo; + \\}; + \\const s: S = undefined; + \\const baz = s.bar(.); + , &.{ + .{ .label = "alpha", .kind = .EnumMember }, + .{ .label = "beta", .kind = .EnumMember }, + }); + try testCompletion( + \\const other_cont = struct { + \\ fn testFn(_: Test, _: enum { alpha, beta }) void {} + \\}; + \\const Test = struct { + \\ pub const testFn = other_cont.testFn; + \\}; + \\const idk: Test = undefined; + \\idk.testFn(.); + , &.{ + .{ .label = "alpha", .kind = .EnumMember }, + .{ .label = "beta", .kind = .EnumMember }, + }); } test "generic function" {