2022-08-26 15:53:02 +01:00
|
|
|
const std = @import("std");
|
|
|
|
const zls = @import("zls");
|
|
|
|
|
2022-09-18 23:47:06 +01:00
|
|
|
const helper = @import("../helper.zig");
|
|
|
|
const Context = @import("../context.zig").Context;
|
|
|
|
const ErrorBuilder = @import("../ErrorBuilder.zig");
|
2022-08-26 15:53:02 +01:00
|
|
|
|
|
|
|
const types = zls.types;
|
2022-09-16 01:33:49 +01:00
|
|
|
const offsets = zls.offsets;
|
2022-08-26 15:53:02 +01:00
|
|
|
const requests = zls.requests;
|
|
|
|
|
|
|
|
const allocator: std.mem.Allocator = std.testing.allocator;
|
|
|
|
|
|
|
|
test "inlayhints - empty" {
|
|
|
|
try testInlayHints("");
|
|
|
|
}
|
|
|
|
|
|
|
|
test "inlayhints - function call" {
|
|
|
|
try testInlayHints(
|
|
|
|
\\fn foo(alpha: u32) void {}
|
|
|
|
\\const _ = foo(<alpha>5);
|
|
|
|
);
|
|
|
|
try testInlayHints(
|
|
|
|
\\fn foo(alpha: u32, beta: u64) void {}
|
|
|
|
\\const _ = foo(<alpha>5,<beta>4);
|
|
|
|
);
|
|
|
|
try testInlayHints(
|
|
|
|
\\fn foo(alpha: u32, beta: u64) void {}
|
|
|
|
\\const _ = foo( <alpha>3 + 2 , <beta>(3 - 2));
|
|
|
|
);
|
|
|
|
try testInlayHints(
|
|
|
|
\\fn foo(alpha: u32, beta: u64) void {}
|
|
|
|
\\const _ = foo(
|
|
|
|
\\ <alpha>3 + 2,
|
|
|
|
\\ <beta>(3 - 2),
|
|
|
|
\\);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
test "inlayhints - function self parameter" {
|
|
|
|
try testInlayHints(
|
|
|
|
\\const Foo = struct { pub fn bar(self: *Foo, alpha: u32) void {} };
|
|
|
|
\\const foo: Foo = .{};
|
|
|
|
\\const _ = foo.bar(<alpha>5);
|
|
|
|
);
|
|
|
|
try testInlayHints(
|
|
|
|
\\const Foo = struct { pub fn bar(_: Foo, alpha: u32, beta: []const u8) void {} };
|
|
|
|
\\const foo: Foo = .{};
|
|
|
|
\\const _ = foo.bar(<alpha>5,<beta>"");
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
test "inlayhints - builtin call" {
|
|
|
|
try testInlayHints(
|
|
|
|
\\const _ = @intCast(<DestType>u32,<int>5);
|
|
|
|
);
|
|
|
|
try testInlayHints(
|
|
|
|
\\const _ = @memcpy(<dest>null,<source>null,<byte_count>0);
|
|
|
|
);
|
|
|
|
|
|
|
|
try testInlayHints(
|
|
|
|
\\const _ = @sizeOf(u32);
|
|
|
|
);
|
|
|
|
try testInlayHints(
|
|
|
|
\\const _ = @TypeOf(5);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn testInlayHints(source: []const u8) !void {
|
2022-09-18 23:47:06 +01:00
|
|
|
var phr = try helper.collectClearPlaceholders(allocator, source);
|
2022-08-26 15:53:02 +01:00
|
|
|
defer phr.deinit(allocator);
|
|
|
|
|
|
|
|
var ctx = try Context.init();
|
|
|
|
defer ctx.deinit();
|
|
|
|
|
2022-09-18 23:47:06 +01:00
|
|
|
try ctx.requestDidOpen("file:///test.zig", phr.new_source);
|
2022-08-26 15:53:02 +01:00
|
|
|
|
|
|
|
const range = types.Range{
|
|
|
|
.start = types.Position{ .line = 0, .character = 0 },
|
2022-09-18 23:47:06 +01:00
|
|
|
.end = offsets.indexToPosition(phr.new_source, phr.new_source.len, .utf16),
|
2022-08-26 15:53:02 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
const InlayHint = struct {
|
|
|
|
position: types.Position,
|
|
|
|
label: []const u8,
|
|
|
|
kind: types.InlayHintKind,
|
|
|
|
};
|
|
|
|
|
2022-09-18 23:47:06 +01:00
|
|
|
const request = requests.InlayHint{
|
|
|
|
.params = .{
|
|
|
|
.textDocument = .{ .uri = "file:///test.zig" },
|
|
|
|
.range = range,
|
|
|
|
},
|
2022-08-26 15:53:02 +01:00
|
|
|
};
|
|
|
|
|
2022-09-18 23:47:06 +01:00
|
|
|
const response = try ctx.requestGetResponse(?[]InlayHint, "textDocument/inlayHint", request);
|
|
|
|
defer response.deinit();
|
|
|
|
|
|
|
|
const hints: []InlayHint = response.result orelse {
|
|
|
|
std.debug.print("Server returned `null` as the result\n", .{});
|
|
|
|
return error.InvalidResponse;
|
2022-08-26 15:53:02 +01:00
|
|
|
};
|
|
|
|
|
2022-09-18 23:47:06 +01:00
|
|
|
var error_builder = ErrorBuilder.init(allocator, phr.new_source);
|
|
|
|
defer error_builder.deinit();
|
|
|
|
errdefer error_builder.writeDebug();
|
2022-08-26 15:53:02 +01:00
|
|
|
|
2022-09-18 23:47:06 +01:00
|
|
|
var i: usize = 0;
|
|
|
|
outer: while (i < phr.locations.len) : (i += 1) {
|
|
|
|
const old_loc = phr.locations.items(.old)[i];
|
|
|
|
const new_loc = phr.locations.items(.new)[i];
|
2022-08-26 15:53:02 +01:00
|
|
|
|
2022-09-18 23:47:06 +01:00
|
|
|
const expected_name = offsets.locToSlice(source, old_loc);
|
|
|
|
const expected_label = expected_name[1 .. expected_name.len - 1]; // convert <name> to name
|
2022-08-26 15:53:02 +01:00
|
|
|
|
2022-09-18 23:47:06 +01:00
|
|
|
const position = offsets.indexToPosition(phr.new_source, new_loc.start, ctx.server.offset_encoding);
|
2022-08-26 15:53:02 +01:00
|
|
|
|
|
|
|
for (hints) |hint| {
|
|
|
|
if (position.line != hint.position.line or position.character != hint.position.character) continue;
|
2022-09-18 23:47:06 +01:00
|
|
|
|
|
|
|
const actual_label = hint.label[0 .. hint.label.len - 1]; // exclude :
|
2022-08-26 15:53:02 +01:00
|
|
|
|
2022-09-18 23:47:06 +01:00
|
|
|
if (!std.mem.eql(u8, expected_label, actual_label)) {
|
|
|
|
try error_builder.msgAtLoc("expected label `{s}` here but got `{s}`!", new_loc, .err, .{ expected_label, actual_label });
|
|
|
|
}
|
|
|
|
if (hint.kind != types.InlayHintKind.Parameter) {
|
|
|
|
try error_builder.msgAtLoc("hint kind should be `{s}` but got `{s}`!", new_loc, .err, .{ @tagName(types.InlayHintKind.Parameter), @tagName(hint.kind) });
|
|
|
|
}
|
2022-08-26 15:53:02 +01:00
|
|
|
|
|
|
|
continue :outer;
|
|
|
|
}
|
2022-09-18 23:47:06 +01:00
|
|
|
try error_builder.msgAtLoc("expected hint `{s}` here", new_loc, .err, .{expected_label});
|
2022-08-26 15:53:02 +01:00
|
|
|
}
|
2022-09-18 23:47:06 +01:00
|
|
|
|
|
|
|
if (error_builder.hasMessages()) return error.InvalidResponse;
|
2022-08-26 15:53:02 +01:00
|
|
|
}
|