Skip to content

Commit

Permalink
functions inside namespaces can't have self parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
Techatrix committed Jul 28, 2024
1 parent 8513557 commit eba1489
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 9 deletions.
1 change: 1 addition & 0 deletions src/analysis.zig
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ pub fn hasSelfParam(analyser: *Analyser, func_ty: Type) error{OutOfMemory}!bool
const fn_token = func_node.handle.tree.nodes.items(.main_token)[func_node.node];
const in_container = try innermostContainer(func_node.handle, func_node.handle.tree.tokens.items(.start)[fn_token]);
std.debug.assert(in_container.is_type_val);
if (in_container.isNamespace()) return false;
return analyser.firstParamIs(func_ty, in_container);
}

Expand Down
9 changes: 5 additions & 4 deletions src/features/completions.zig
Original file line number Diff line number Diff line change
Expand Up @@ -321,10 +321,11 @@ fn functionTypeCompletion(

const use_snippets = builder.server.config.enable_snippets and builder.server.client_capabilities.supports_snippets;

const has_self_param = if (parent_container_ty) |container_ty|
if (container_ty.is_type_val) false else try builder.analyser.firstParamIs(func_ty, container_ty.typeOf(builder.analyser))
else
false;
const has_self_param = if (parent_container_ty) |container_ty| blk: {
if (container_ty.is_type_val) break :blk false;
if (container_ty.isNamespace()) break :blk false;
break :blk try builder.analyser.firstParamIs(func_ty, container_ty.typeOf(builder.analyser));
} else false;

const insert_range, const replace_range, const new_text_format = prepareFunctionCompletion(builder);

Expand Down
88 changes: 88 additions & 0 deletions tests/lsp_features/completion.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,50 @@ test "switch capture by ref" {
});
}

test "namespace" {
try testCompletion(
\\const namespace = struct {};
\\const bar = namespace.<cursor>
, &.{});
try testCompletion(
\\const namespace = struct {
\\ fn alpha() void {}
\\ fn beta(_: anytype) void {}
\\ fn gamma(_: @This()) void {}
\\};
\\const bar = namespace.<cursor>
, &.{
.{ .label = "alpha", .kind = .Function, .detail = "fn () void" },
.{ .label = "beta", .kind = .Function, .detail = "fn (_: anytype) void" },
.{ .label = "gamma", .kind = .Function, .detail = "fn (_: @This()) void" },
});
try testCompletion(
\\const namespace = struct {
\\ fn alpha() void {}
\\ fn beta(_: anytype) void {}
\\ fn gamma(_: @This()) void {}
\\};
\\const instance: namespace = undefined;
\\const bar = instance.<cursor>
, &.{
.{ .label = "alpha", .kind = .Function, .detail = "fn () void" },
.{ .label = "beta", .kind = .Function, .detail = "fn (_: anytype) void" },
.{ .label = "gamma", .kind = .Function, .detail = "fn (_: @This()) void" },
});
try testCompletion(
\\fn alpha() void {}
\\fn beta(_: anytype) void {}
\\fn gamma(_: @This()) void {}
\\
\\const foo: @This() = undefined;
\\const bar = foo.<cursor>;
, &.{
.{ .label = "alpha", .kind = .Function, .detail = "fn () void" },
.{ .label = "beta", .kind = .Function, .detail = "fn (_: anytype) void" },
.{ .label = "gamma", .kind = .Function, .detail = "fn (_: @This()) void" },
});
}

test "struct" {
try testCompletion(
\\const S = struct {
Expand Down Expand Up @@ -1103,6 +1147,7 @@ test "struct" {

try testCompletion(
\\const Foo = struct {
\\ alpha: u32,
\\ fn add(foo: Foo) Foo {}
\\};
\\test {
Expand All @@ -1113,6 +1158,7 @@ test "struct" {
\\ .<cursor>
\\}
, &.{
.{ .label = "alpha", .kind = .Field, .detail = "u32" },
.{ .label = "add", .kind = .Method, .detail = "fn (foo: Foo) Foo" },
});

Expand Down Expand Up @@ -1146,16 +1192,34 @@ test "struct" {
\\fn barImpl(_: *const Foo) void {}
\\fn bazImpl(_: u32) void {}
\\const Foo = struct {
\\ alpha: u32,
\\ pub const foo = fooImpl;
\\ pub const bar = barImpl;
\\ pub const baz = bazImpl;
\\};
\\const foo = Foo{};
\\const baz = foo.<cursor>;
, &.{
.{ .label = "alpha", .kind = .Field, .detail = "u32" },
.{ .label = "foo", .kind = .Method, .detail = "fn (_: Foo) void" },
.{ .label = "bar", .kind = .Method, .detail = "fn (_: *const Foo) void" },
});
try testCompletion(
\\alpha: u32,
\\
\\fn alpha() void {}
\\fn beta(_: anytype) void {}
\\fn gamma(_: @This()) void {}
\\
\\const Self = @This();
\\const bar = Self.<cursor>;
, &.{
.{ .label = "alpha", .kind = .Function, .detail = "fn () void" },
.{ .label = "beta", .kind = .Function, .detail = "fn (_: anytype) void" },
.{ .label = "gamma", .kind = .Function, .detail = "fn (_: @This()) void" },
.{ .label = "Self", .kind = .Struct },
.{ .label = "bar", .kind = .Struct },
});
}

test "union" {
Expand Down Expand Up @@ -1364,6 +1428,7 @@ test "enum" {
\\ sef2,
\\};
\\const S = struct {
\\ alpha: u32,
\\ const Self = @This();
\\ pub fn f(_: *Self, _: SomeEnum) void {}
\\};
Expand All @@ -1387,6 +1452,7 @@ test "enum" {
\\ se: SomeEnum,
\\};
\\const S = struct {
\\ alpha: u32,
\\ const Self = @This();
\\ pub fn f(_: *Self, _: SCE) void {}
\\};
Expand Down Expand Up @@ -2226,12 +2292,14 @@ test "usingnamespace" {
\\ };
\\}
\\const Foo = struct {
\\ alpha: u32,
\\ pub usingnamespace Bar(Foo);
\\ fn deinit(self: Foo) void { _ = self; }
\\};
\\const foo: Foo = undefined;
\\const bar = foo.<cursor>
, &.{
.{ .label = "alpha", .kind = .Field, .detail = "u32" },
.{ .label = "inner", .kind = .Method, .detail = "fn (self: Self) void" },
.{ .label = "deinit", .kind = .Method, .detail = "fn (self: Foo) void" },
});
Expand Down Expand Up @@ -2404,11 +2472,13 @@ test "either" {
\\ fn alpha() void {}
\\};
\\const Beta = struct {
\\ field: u32,
\\ fn beta(_: @This()) void {}
\\};
\\const foo: if (undefined) Alpha else Beta = undefined;
\\const bar = foo.<cursor>
, &.{
.{ .label = "field", .kind = .Field, .detail = "u32" },
.{ .label = "alpha", .kind = .Function, .detail = "fn () void" },
.{ .label = "beta", .kind = .Method, .detail = "fn (_: @This()) void" },
});
Expand All @@ -2417,13 +2487,15 @@ test "either" {
\\ fn alpha() void {}
\\};
\\const Beta = struct {
\\ field: u32,
\\ fn beta(_: @This()) void {}
\\};
\\const alpha: Alpha = undefined;
\\const beta: Beta = undefined;
\\const gamma = if (undefined) alpha else beta;
\\const foo = gamma.<cursor>
, &.{
.{ .label = "field", .kind = .Field, .detail = "u32" },
.{ .label = "alpha", .kind = .Function, .detail = "fn () void" },
.{ .label = "beta", .kind = .Method, .detail = "fn (_: @This()) void" },
});
Expand Down Expand Up @@ -2537,11 +2609,13 @@ test "filesystem" {
test "label details disabled" {
try testCompletionWithOptions(
\\const S = struct {
\\ alpha: u32,
\\ fn f(self: S) void {}
\\};
\\const s = S{};
\\s.<cursor>
, &.{
.{ .label = "alpha", .kind = .Field, .detail = "u32" },
.{
.label = "f",
.labelDetails = .{
Expand All @@ -2556,11 +2630,13 @@ test "label details disabled" {
});
try testCompletionWithOptions(
\\const S = struct {
\\ alpha: u32,
\\ fn f(self: S, value: u32) !void {}
\\};
\\const s = S{};
\\s.<cursor>
, &.{
.{ .label = "alpha", .kind = .Field, .detail = "u32" },
.{
.label = "f",
.labelDetails = .{
Expand Down Expand Up @@ -2825,6 +2901,7 @@ test "insert replace behaviour - function 'self parameter' detection" {
try testCompletionTextEdit(.{
.source =
\\const S = struct {
\\ alpha: u32,
\\ fn f(self: S) void {}
\\};
\\const s = S{};
Expand All @@ -2837,6 +2914,7 @@ test "insert replace behaviour - function 'self parameter' detection" {
try testCompletionTextEdit(.{
.source =
\\const S = struct {
\\ alpha: u32,
\\ fn f(self: S) void {}
\\};
\\S.<cursor>
Expand All @@ -2848,6 +2926,7 @@ test "insert replace behaviour - function 'self parameter' detection" {
try testCompletionTextEdit(.{
.source =
\\const S = struct {
\\ alpha: u32,
\\ fn f() void {}
\\};
\\S.<cursor>
Expand All @@ -2859,6 +2938,7 @@ test "insert replace behaviour - function 'self parameter' detection" {
try testCompletionTextEdit(.{
.source =
\\const S = struct {
\\ alpha: u32,
\\ fn f(self: S) void {}
\\};
\\const s = S{};
Expand All @@ -2871,6 +2951,7 @@ test "insert replace behaviour - function 'self parameter' detection" {
try testCompletionTextEdit(.{
.source =
\\const S = struct {
\\ alpha: u32,
\\ fn f(self: @This()) void {}
\\};
\\const s = S{};
Expand All @@ -2883,6 +2964,7 @@ test "insert replace behaviour - function 'self parameter' detection" {
try testCompletionTextEdit(.{
.source =
\\const S = struct {
\\ alpha: u32,
\\ fn f(self: anytype) void {}
\\};
\\const s = S{};
Expand All @@ -2895,6 +2977,7 @@ test "insert replace behaviour - function 'self parameter' detection" {
try testCompletionTextEdit(.{
.source =
\\const S = struct {
\\ alpha: u32,
\\ fn f(self: S) void {}
\\};
\\const s = S{};
Expand All @@ -2907,6 +2990,7 @@ test "insert replace behaviour - function 'self parameter' detection" {
try testCompletionTextEdit(.{
.source =
\\const S = struct {
\\ alpha: u32,
\\ fn f(self: S, number: u32) void {}
\\};
\\const s = S{};
Expand Down Expand Up @@ -2955,6 +3039,7 @@ test "insert replace behaviour - function with snippets" {
try testCompletionTextEdit(.{
.source =
\\const S = struct {
\\ alpha: u32,
\\ fn f(self: S) void {}
\\};
\\S.<cursor>
Expand All @@ -2968,6 +3053,7 @@ test "insert replace behaviour - function with snippets" {
try testCompletionTextEdit(.{
.source =
\\const S = struct {
\\ alpha: u32,
\\ fn f(self: S, number: u32) void {}
\\};
\\var s = S{};
Expand All @@ -2982,6 +3068,7 @@ test "insert replace behaviour - function with snippets" {
try testCompletionTextEdit(.{
.source =
\\const S = struct {
\\ alpha: u32,
\\ fn f(self: S) void {}
\\};
\\const s = S{};
Expand All @@ -2996,6 +3083,7 @@ test "insert replace behaviour - function with snippets" {
try testCompletionTextEdit(.{
.source =
\\const S = struct {
\\ alpha: u32,
\\ fn f(self: S) void {}
\\};
\\S.<cursor>
Expand Down
14 changes: 9 additions & 5 deletions tests/lsp_features/semantic_tokens.zig
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ test "call" {
\\const alpha = foo(0);
, &.{
.{ "fn", .keyword, .{} },
.{ "foo", .method, .{ .declaration = true, .generic = true } },
.{ "foo", .function, .{ .declaration = true, .generic = true } },
.{ "a", .parameter, .{ .declaration = true } },
.{ "anytype", .type, .{} },
.{ "void", .type, .{} },
Expand All @@ -430,7 +430,7 @@ test "call" {
.{ "const", .keyword, .{} },
.{ "alpha", .variable, .{ .declaration = true } },
.{ "=", .operator, .{} },
.{ "foo", .method, .{ .generic = true } },
.{ "foo", .function, .{ .generic = true } },
.{ "0", .number, .{} },
});
}
Expand Down Expand Up @@ -1233,23 +1233,27 @@ test "function" {
test "method" {
try testSemanticTokens(
\\const S = struct {
\\ alpha: u32,
\\ fn create() S {}
\\ fn doTheThing(self: S) void {}
\\};
, &.{
.{ "const", .keyword, .{} },
.{ "S", .namespace, .{ .declaration = true } },
.{ "S", .@"struct", .{ .declaration = true } },
.{ "=", .operator, .{} },
.{ "struct", .keyword, .{} },

.{ "alpha", .property, .{ .declaration = true } },
.{ "u32", .type, .{} },

.{ "fn", .keyword, .{} },
.{ "create", .function, .{ .declaration = true } },
.{ "S", .namespace, .{} },
.{ "S", .@"struct", .{} },

.{ "fn", .keyword, .{} },
.{ "doTheThing", .method, .{ .declaration = true } },
.{ "self", .parameter, .{ .declaration = true } },
.{ "S", .namespace, .{} },
.{ "S", .@"struct", .{} },
.{ "void", .type, .{} },
});
}
Expand Down
Loading

0 comments on commit eba1489

Please sign in to comment.