Reworked tag stores, fixed memory leak
This commit is contained in:
parent
62ab67f751
commit
62774d065b
137
src/analysis.zig
137
src/analysis.zig
@ -673,11 +673,6 @@ pub fn resolveTypeOfNodeInternal(
|
|||||||
)) orelse return null).instanceTypeVal();
|
)) orelse return null).instanceTypeVal();
|
||||||
},
|
},
|
||||||
.ErrorSetDecl => {
|
.ErrorSetDecl => {
|
||||||
const set = node.cast(ast.Node.ErrorSetDecl).?;
|
|
||||||
var i: usize = 0;
|
|
||||||
while (set.iterate(i)) |decl| : (i += 1) {
|
|
||||||
try store.error_completions.add(handle.tree, decl);
|
|
||||||
}
|
|
||||||
return TypeWithHandle.typeVal(node_handle);
|
return TypeWithHandle.typeVal(node_handle);
|
||||||
},
|
},
|
||||||
.SuffixOp => {
|
.SuffixOp => {
|
||||||
@ -821,16 +816,6 @@ pub fn resolveTypeOfNodeInternal(
|
|||||||
.ContainerDecl => {
|
.ContainerDecl => {
|
||||||
const container = node.cast(ast.Node.ContainerDecl).?;
|
const container = node.cast(ast.Node.ContainerDecl).?;
|
||||||
const kind = handle.tree.token_ids[container.kind_token];
|
const kind = handle.tree.token_ids[container.kind_token];
|
||||||
|
|
||||||
if (kind == .Keyword_struct or (kind == .Keyword_union and container.init_arg_expr == .None)) {
|
|
||||||
return TypeWithHandle.typeVal(node_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
var i: usize = 0;
|
|
||||||
while (container.iterate(i)) |decl| : (i += 1) {
|
|
||||||
if (decl.id != .ContainerField) continue;
|
|
||||||
try store.enum_completions.add(handle.tree, decl);
|
|
||||||
}
|
|
||||||
return TypeWithHandle.typeVal(node_handle);
|
return TypeWithHandle.typeVal(node_handle);
|
||||||
},
|
},
|
||||||
.FnProto => {
|
.FnProto => {
|
||||||
@ -1907,6 +1892,8 @@ pub fn lookupSymbolContainer(
|
|||||||
|
|
||||||
pub const DocumentScope = struct {
|
pub const DocumentScope = struct {
|
||||||
scopes: []Scope,
|
scopes: []Scope,
|
||||||
|
error_completions: []types.CompletionItem,
|
||||||
|
enum_completions: []types.CompletionItem,
|
||||||
|
|
||||||
pub fn debugPrint(self: DocumentScope) void {
|
pub fn debugPrint(self: DocumentScope) void {
|
||||||
for (self.scopes) |scope| {
|
for (self.scopes) |scope| {
|
||||||
@ -1939,6 +1926,10 @@ pub const DocumentScope = struct {
|
|||||||
allocator.free(scope.tests);
|
allocator.free(scope.tests);
|
||||||
}
|
}
|
||||||
allocator.free(self.scopes);
|
allocator.free(self.scopes);
|
||||||
|
for (self.error_completions) |item| if (item.documentation) |doc| allocator.free(doc.value);
|
||||||
|
allocator.free(self.error_completions);
|
||||||
|
for (self.enum_completions) |item| if (item.documentation) |doc| allocator.free(doc.value);
|
||||||
|
allocator.free(self.enum_completions);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1959,12 +1950,23 @@ pub const Scope = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn makeDocumentScope(allocator: *std.mem.Allocator, tree: *ast.Tree) !DocumentScope {
|
pub fn makeDocumentScope(allocator: *std.mem.Allocator, tree: *ast.Tree) !DocumentScope {
|
||||||
var scopes = std.ArrayList(Scope).init(allocator);
|
var scopes = std.ArrayListUnmanaged(Scope){};
|
||||||
errdefer scopes.deinit();
|
var error_completions = std.ArrayListUnmanaged(types.CompletionItem){};
|
||||||
|
var enum_completions = std.ArrayListUnmanaged(types.CompletionItem){};
|
||||||
|
|
||||||
try makeScopeInternal(allocator, &scopes, tree, &tree.root_node.base);
|
errdefer {
|
||||||
|
scopes.deinit(allocator);
|
||||||
|
for (error_completions.items) |item| if (item.documentation) |doc| allocator.free(doc.value);
|
||||||
|
error_completions.deinit(allocator);
|
||||||
|
for (enum_completions.items) |item| if (item.documentation) |doc| allocator.free(doc.value);
|
||||||
|
enum_completions.deinit(allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
try makeScopeInternal(allocator, &scopes, &error_completions, &enum_completions, tree, &tree.root_node.base);
|
||||||
return DocumentScope{
|
return DocumentScope{
|
||||||
.scopes = scopes.toOwnedSlice(),
|
.scopes = scopes.toOwnedSlice(allocator),
|
||||||
|
.error_completions = error_completions.toOwnedSlice(allocator),
|
||||||
|
.enum_completions = enum_completions.toOwnedSlice(allocator),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1975,14 +1977,13 @@ fn nodeSourceRange(tree: *ast.Tree, node: *ast.Node) SourceRange {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Make enum and error stores per-document
|
|
||||||
// CLear the doc ones before calling this and
|
|
||||||
// rebuild them here.
|
|
||||||
// TODO Possibly collect all imports to diff them on changes
|
// TODO Possibly collect all imports to diff them on changes
|
||||||
// as well
|
// as well
|
||||||
fn makeScopeInternal(
|
fn makeScopeInternal(
|
||||||
allocator: *std.mem.Allocator,
|
allocator: *std.mem.Allocator,
|
||||||
scopes: *std.ArrayList(Scope),
|
scopes: *std.ArrayListUnmanaged(Scope),
|
||||||
|
error_completions: *std.ArrayListUnmanaged(types.CompletionItem),
|
||||||
|
enum_completions: *std.ArrayListUnmanaged(types.CompletionItem),
|
||||||
tree: *ast.Tree,
|
tree: *ast.Tree,
|
||||||
node: *ast.Node,
|
node: *ast.Node,
|
||||||
) error{OutOfMemory}!void {
|
) error{OutOfMemory}!void {
|
||||||
@ -1994,7 +1995,7 @@ fn makeScopeInternal(
|
|||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
|
|
||||||
(try scopes.addOne()).* = .{
|
(try scopes.addOne(allocator)).* = .{
|
||||||
.range = nodeSourceRange(tree, node),
|
.range = nodeSourceRange(tree, node),
|
||||||
.decls = std.StringHashMap(Declaration).init(allocator),
|
.decls = std.StringHashMap(Declaration).init(allocator),
|
||||||
.uses = &[0]*ast.Node.Use{},
|
.uses = &[0]*ast.Node.Use{},
|
||||||
@ -2017,22 +2018,44 @@ fn makeScopeInternal(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try makeScopeInternal(allocator, scopes, tree, decl);
|
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, decl);
|
||||||
const name = getDeclName(tree, decl) orelse continue;
|
const name = getDeclName(tree, decl) orelse continue;
|
||||||
if (decl.id == .TestDecl) {
|
if (decl.id == .TestDecl) {
|
||||||
try tests.append(decl);
|
try tests.append(decl);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node.id == .ErrorSetDecl) {
|
||||||
|
(try error_completions.addOne(allocator)).* = .{
|
||||||
|
.label = name,
|
||||||
|
.kind = .Constant,
|
||||||
|
.documentation = if (try getDocComments(allocator, tree, decl, .Markdown)) |docs|
|
||||||
|
.{ .kind = .Markdown, .value = docs }
|
||||||
|
else
|
||||||
|
null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (decl.cast(ast.Node.ContainerField)) |field| {
|
if (decl.cast(ast.Node.ContainerField)) |field| {
|
||||||
if (field.type_expr == null and field.value_expr == null) {
|
const empty_field = field.type_expr == null and field.value_expr == null;
|
||||||
if (node.id == .Root) continue;
|
if (empty_field and node.id == .Root) {
|
||||||
if (node.cast(ast.Node.ContainerDecl)) |container| {
|
continue;
|
||||||
const kind = tree.token_ids[container.kind_token];
|
}
|
||||||
if (kind == .Keyword_struct or (kind == .Keyword_union and container.init_arg_expr == .None)) {
|
|
||||||
continue;
|
if (node.cast(ast.Node.ContainerDecl)) |container| {
|
||||||
}
|
const kind = tree.token_ids[container.kind_token];
|
||||||
|
if (empty_field and (kind == .Keyword_struct or (kind == .Keyword_union and container.init_arg_expr == .None))) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(try enum_completions.addOne(allocator)).* = .{
|
||||||
|
.label = name,
|
||||||
|
.kind = .Constant,
|
||||||
|
.documentation = if (try getDocComments(allocator, tree, decl, .Markdown)) |docs|
|
||||||
|
.{ .kind = .Markdown, .value = docs }
|
||||||
|
else
|
||||||
|
null,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2050,7 +2073,7 @@ fn makeScopeInternal(
|
|||||||
.FnProto => {
|
.FnProto => {
|
||||||
const func = node.cast(ast.Node.FnProto).?;
|
const func = node.cast(ast.Node.FnProto).?;
|
||||||
|
|
||||||
(try scopes.addOne()).* = .{
|
(try scopes.addOne(allocator)).* = .{
|
||||||
.range = nodeSourceRange(tree, node),
|
.range = nodeSourceRange(tree, node),
|
||||||
.decls = std.StringHashMap(Declaration).init(allocator),
|
.decls = std.StringHashMap(Declaration).init(allocator),
|
||||||
.uses = &[0]*ast.Node.Use{},
|
.uses = &[0]*ast.Node.Use{},
|
||||||
@ -2069,19 +2092,19 @@ fn makeScopeInternal(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (func.body_node) |body| {
|
if (func.body_node) |body| {
|
||||||
try makeScopeInternal(allocator, scopes, tree, body);
|
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
.TestDecl => {
|
.TestDecl => {
|
||||||
return try makeScopeInternal(allocator, scopes, tree, node.cast(ast.Node.TestDecl).?.body_node);
|
return try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, node.cast(ast.Node.TestDecl).?.body_node);
|
||||||
},
|
},
|
||||||
.Block => {
|
.Block => {
|
||||||
const block = node.cast(ast.Node.Block).?;
|
const block = node.cast(ast.Node.Block).?;
|
||||||
if (block.label) |label| {
|
if (block.label) |label| {
|
||||||
std.debug.assert(tree.token_ids[label] == .Identifier);
|
std.debug.assert(tree.token_ids[label] == .Identifier);
|
||||||
var scope = try scopes.addOne();
|
var scope = try scopes.addOne(allocator);
|
||||||
scope.* = .{
|
scope.* = .{
|
||||||
.range = .{
|
.range = .{
|
||||||
.start = tree.token_locs[block.lbrace].start,
|
.start = tree.token_locs[block.lbrace].start,
|
||||||
@ -2099,7 +2122,7 @@ fn makeScopeInternal(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
(try scopes.addOne()).* = .{
|
(try scopes.addOne(allocator)).* = .{
|
||||||
.range = nodeSourceRange(tree, node),
|
.range = nodeSourceRange(tree, node),
|
||||||
.decls = std.StringHashMap(Declaration).init(allocator),
|
.decls = std.StringHashMap(Declaration).init(allocator),
|
||||||
.uses = &[0]*ast.Node.Use{},
|
.uses = &[0]*ast.Node.Use{},
|
||||||
@ -2121,7 +2144,7 @@ fn makeScopeInternal(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try makeScopeInternal(allocator, scopes, tree, child_node);
|
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, child_node);
|
||||||
if (child_node.cast(ast.Node.VarDecl)) |var_decl| {
|
if (child_node.cast(ast.Node.VarDecl)) |var_decl| {
|
||||||
const name = tree.tokenSlice(var_decl.name_token);
|
const name = tree.tokenSlice(var_decl.name_token);
|
||||||
if (try scopes.items[scope_idx].decls.fetchPut(name, .{ .ast_node = child_node })) |existing| {
|
if (try scopes.items[scope_idx].decls.fetchPut(name, .{ .ast_node = child_node })) |existing| {
|
||||||
@ -2134,14 +2157,14 @@ fn makeScopeInternal(
|
|||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
.Comptime => {
|
.Comptime => {
|
||||||
return try makeScopeInternal(allocator, scopes, tree, node.cast(ast.Node.Comptime).?.expr);
|
return try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, node.cast(ast.Node.Comptime).?.expr);
|
||||||
},
|
},
|
||||||
.If => {
|
.If => {
|
||||||
const if_node = node.cast(ast.Node.If).?;
|
const if_node = node.cast(ast.Node.If).?;
|
||||||
|
|
||||||
if (if_node.payload) |payload| {
|
if (if_node.payload) |payload| {
|
||||||
std.debug.assert(payload.id == .PointerPayload);
|
std.debug.assert(payload.id == .PointerPayload);
|
||||||
var scope = try scopes.addOne();
|
var scope = try scopes.addOne(allocator);
|
||||||
scope.* = .{
|
scope.* = .{
|
||||||
.range = .{
|
.range = .{
|
||||||
.start = tree.token_locs[payload.firstToken()].start,
|
.start = tree.token_locs[payload.firstToken()].start,
|
||||||
@ -2164,12 +2187,12 @@ fn makeScopeInternal(
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
try makeScopeInternal(allocator, scopes, tree, if_node.body);
|
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, if_node.body);
|
||||||
|
|
||||||
if (if_node.@"else") |else_node| {
|
if (if_node.@"else") |else_node| {
|
||||||
if (else_node.payload) |payload| {
|
if (else_node.payload) |payload| {
|
||||||
std.debug.assert(payload.id == .Payload);
|
std.debug.assert(payload.id == .Payload);
|
||||||
var scope = try scopes.addOne();
|
var scope = try scopes.addOne(allocator);
|
||||||
scope.* = .{
|
scope.* = .{
|
||||||
.range = .{
|
.range = .{
|
||||||
.start = tree.token_locs[payload.firstToken()].start,
|
.start = tree.token_locs[payload.firstToken()].start,
|
||||||
@ -2187,14 +2210,14 @@ fn makeScopeInternal(
|
|||||||
const name = tree.tokenSlice(err_payload.error_symbol.firstToken());
|
const name = tree.tokenSlice(err_payload.error_symbol.firstToken());
|
||||||
try scope.decls.putNoClobber(name, .{ .ast_node = payload });
|
try scope.decls.putNoClobber(name, .{ .ast_node = payload });
|
||||||
}
|
}
|
||||||
try makeScopeInternal(allocator, scopes, tree, else_node.body);
|
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, else_node.body);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.While => {
|
.While => {
|
||||||
const while_node = node.cast(ast.Node.While).?;
|
const while_node = node.cast(ast.Node.While).?;
|
||||||
if (while_node.label) |label| {
|
if (while_node.label) |label| {
|
||||||
std.debug.assert(tree.token_ids[label] == .Identifier);
|
std.debug.assert(tree.token_ids[label] == .Identifier);
|
||||||
var scope = try scopes.addOne();
|
var scope = try scopes.addOne(allocator);
|
||||||
scope.* = .{
|
scope.* = .{
|
||||||
.range = .{
|
.range = .{
|
||||||
.start = tree.token_locs[while_node.while_token].start,
|
.start = tree.token_locs[while_node.while_token].start,
|
||||||
@ -2214,7 +2237,7 @@ fn makeScopeInternal(
|
|||||||
|
|
||||||
if (while_node.payload) |payload| {
|
if (while_node.payload) |payload| {
|
||||||
std.debug.assert(payload.id == .PointerPayload);
|
std.debug.assert(payload.id == .PointerPayload);
|
||||||
var scope = try scopes.addOne();
|
var scope = try scopes.addOne(allocator);
|
||||||
scope.* = .{
|
scope.* = .{
|
||||||
.range = .{
|
.range = .{
|
||||||
.start = tree.token_locs[payload.firstToken()].start,
|
.start = tree.token_locs[payload.firstToken()].start,
|
||||||
@ -2237,12 +2260,12 @@ fn makeScopeInternal(
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
try makeScopeInternal(allocator, scopes, tree, while_node.body);
|
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, while_node.body);
|
||||||
|
|
||||||
if (while_node.@"else") |else_node| {
|
if (while_node.@"else") |else_node| {
|
||||||
if (else_node.payload) |payload| {
|
if (else_node.payload) |payload| {
|
||||||
std.debug.assert(payload.id == .Payload);
|
std.debug.assert(payload.id == .Payload);
|
||||||
var scope = try scopes.addOne();
|
var scope = try scopes.addOne(allocator);
|
||||||
scope.* = .{
|
scope.* = .{
|
||||||
.range = .{
|
.range = .{
|
||||||
.start = tree.token_locs[payload.firstToken()].start,
|
.start = tree.token_locs[payload.firstToken()].start,
|
||||||
@ -2260,14 +2283,14 @@ fn makeScopeInternal(
|
|||||||
const name = tree.tokenSlice(err_payload.error_symbol.firstToken());
|
const name = tree.tokenSlice(err_payload.error_symbol.firstToken());
|
||||||
try scope.decls.putNoClobber(name, .{ .ast_node = payload });
|
try scope.decls.putNoClobber(name, .{ .ast_node = payload });
|
||||||
}
|
}
|
||||||
try makeScopeInternal(allocator, scopes, tree, else_node.body);
|
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, else_node.body);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.For => {
|
.For => {
|
||||||
const for_node = node.cast(ast.Node.For).?;
|
const for_node = node.cast(ast.Node.For).?;
|
||||||
if (for_node.label) |label| {
|
if (for_node.label) |label| {
|
||||||
std.debug.assert(tree.token_ids[label] == .Identifier);
|
std.debug.assert(tree.token_ids[label] == .Identifier);
|
||||||
var scope = try scopes.addOne();
|
var scope = try scopes.addOne(allocator);
|
||||||
scope.* = .{
|
scope.* = .{
|
||||||
.range = .{
|
.range = .{
|
||||||
.start = tree.token_locs[for_node.for_token].start,
|
.start = tree.token_locs[for_node.for_token].start,
|
||||||
@ -2289,7 +2312,7 @@ fn makeScopeInternal(
|
|||||||
const ptr_idx_payload = for_node.payload.cast(ast.Node.PointerIndexPayload).?;
|
const ptr_idx_payload = for_node.payload.cast(ast.Node.PointerIndexPayload).?;
|
||||||
std.debug.assert(ptr_idx_payload.value_symbol.id == .Identifier);
|
std.debug.assert(ptr_idx_payload.value_symbol.id == .Identifier);
|
||||||
|
|
||||||
var scope = try scopes.addOne();
|
var scope = try scopes.addOne(allocator);
|
||||||
scope.* = .{
|
scope.* = .{
|
||||||
.range = .{
|
.range = .{
|
||||||
.start = tree.token_locs[ptr_idx_payload.firstToken()].start,
|
.start = tree.token_locs[ptr_idx_payload.firstToken()].start,
|
||||||
@ -2318,10 +2341,10 @@ fn makeScopeInternal(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try makeScopeInternal(allocator, scopes, tree, for_node.body);
|
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, for_node.body);
|
||||||
if (for_node.@"else") |else_node| {
|
if (for_node.@"else") |else_node| {
|
||||||
std.debug.assert(else_node.payload == null);
|
std.debug.assert(else_node.payload == null);
|
||||||
try makeScopeInternal(allocator, scopes, tree, else_node.body);
|
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, else_node.body);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.Switch => {
|
.Switch => {
|
||||||
@ -2330,7 +2353,7 @@ fn makeScopeInternal(
|
|||||||
if (case.*.cast(ast.Node.SwitchCase)) |case_node| {
|
if (case.*.cast(ast.Node.SwitchCase)) |case_node| {
|
||||||
if (case_node.payload) |payload| {
|
if (case_node.payload) |payload| {
|
||||||
std.debug.assert(payload.id == .PointerPayload);
|
std.debug.assert(payload.id == .PointerPayload);
|
||||||
var scope = try scopes.addOne();
|
var scope = try scopes.addOne(allocator);
|
||||||
scope.* = .{
|
scope.* = .{
|
||||||
.range = .{
|
.range = .{
|
||||||
.start = tree.token_locs[payload.firstToken()].start,
|
.start = tree.token_locs[payload.firstToken()].start,
|
||||||
@ -2354,23 +2377,23 @@ fn makeScopeInternal(
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
try makeScopeInternal(allocator, scopes, tree, case_node.expr);
|
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, case_node.expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.VarDecl => {
|
.VarDecl => {
|
||||||
const var_decl = node.cast(ast.Node.VarDecl).?;
|
const var_decl = node.cast(ast.Node.VarDecl).?;
|
||||||
if (var_decl.type_node) |type_node| {
|
if (var_decl.type_node) |type_node| {
|
||||||
try makeScopeInternal(allocator, scopes, tree, type_node);
|
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, type_node);
|
||||||
}
|
}
|
||||||
if (var_decl.init_node) |init_node| {
|
if (var_decl.init_node) |init_node| {
|
||||||
try makeScopeInternal(allocator, scopes, tree, init_node);
|
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, init_node);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
var child_idx: usize = 0;
|
var child_idx: usize = 0;
|
||||||
while (node.iterate(child_idx)) |child_node| : (child_idx += 1) {
|
while (node.iterate(child_idx)) |child_node| : (child_idx += 1) {
|
||||||
try makeScopeInternal(allocator, scopes, tree, child_node);
|
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, child_node);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -32,48 +32,6 @@ pub const Handle = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const TagStore = struct {
|
|
||||||
values: std.StringHashMap(void),
|
|
||||||
completions: std.ArrayListUnmanaged(types.CompletionItem),
|
|
||||||
|
|
||||||
pub fn init(allocator: *std.mem.Allocator) TagStore {
|
|
||||||
return .{
|
|
||||||
.values = std.StringHashMap(void).init(allocator),
|
|
||||||
.completions = .{},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *TagStore) void {
|
|
||||||
const alloc = self.values.allocator;
|
|
||||||
for (self.completions.items) |item| {
|
|
||||||
alloc.free(item.label);
|
|
||||||
if (item.documentation) |some| alloc.free(some.value);
|
|
||||||
}
|
|
||||||
self.values.deinit();
|
|
||||||
self.completions.deinit(self.values.allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add(self: *TagStore, tree: *std.zig.ast.Tree, tag: *std.zig.ast.Node) !void {
|
|
||||||
const name = analysis.nodeToString(tree, tag).?;
|
|
||||||
if (self.values.contains(name)) return;
|
|
||||||
const alloc = self.values.allocator;
|
|
||||||
const item = types.CompletionItem{
|
|
||||||
.label = try std.mem.dupe(alloc, u8, name),
|
|
||||||
.kind = .Constant,
|
|
||||||
.documentation = if (try analysis.getDocComments(alloc, tree, tag, .Markdown)) |docs|
|
|
||||||
.{
|
|
||||||
.kind = .Markdown,
|
|
||||||
.value = docs,
|
|
||||||
}
|
|
||||||
else
|
|
||||||
null,
|
|
||||||
};
|
|
||||||
|
|
||||||
try self.values.putNoClobber(item.label, {});
|
|
||||||
try self.completions.append(self.values.allocator, item);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
allocator: *std.mem.Allocator,
|
allocator: *std.mem.Allocator,
|
||||||
handles: std.StringHashMap(*Handle),
|
handles: std.StringHashMap(*Handle),
|
||||||
zig_exe_path: ?[]const u8,
|
zig_exe_path: ?[]const u8,
|
||||||
@ -81,9 +39,6 @@ build_files: std.ArrayListUnmanaged(*BuildFile),
|
|||||||
build_runner_path: []const u8,
|
build_runner_path: []const u8,
|
||||||
std_uri: ?[]const u8,
|
std_uri: ?[]const u8,
|
||||||
|
|
||||||
error_completions: TagStore,
|
|
||||||
enum_completions: TagStore,
|
|
||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
self: *DocumentStore,
|
self: *DocumentStore,
|
||||||
allocator: *std.mem.Allocator,
|
allocator: *std.mem.Allocator,
|
||||||
@ -97,8 +52,6 @@ pub fn init(
|
|||||||
self.build_files = .{};
|
self.build_files = .{};
|
||||||
self.build_runner_path = build_runner_path;
|
self.build_runner_path = build_runner_path;
|
||||||
self.std_uri = try stdUriFromLibPath(allocator, zig_lib_path);
|
self.std_uri = try stdUriFromLibPath(allocator, zig_lib_path);
|
||||||
self.error_completions = TagStore.init(allocator);
|
|
||||||
self.enum_completions = TagStore.init(allocator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const LoadPackagesContext = struct {
|
const LoadPackagesContext = struct {
|
||||||
@ -265,7 +218,7 @@ fn newDocument(self: *DocumentStore, uri: []const u8, text: []u8) anyerror!*Hand
|
|||||||
// This includes the last separator
|
// This includes the last separator
|
||||||
curr_path = curr_path[0 .. idx + 1];
|
curr_path = curr_path[0 .. idx + 1];
|
||||||
|
|
||||||
var folder = std.fs.cwd().openDir(curr_path, .{}) catch |err| switch(err) {
|
var folder = std.fs.cwd().openDir(curr_path, .{}) catch |err| switch (err) {
|
||||||
error.FileNotFound => continue,
|
error.FileNotFound => continue,
|
||||||
else => return err,
|
else => return err,
|
||||||
};
|
};
|
||||||
@ -365,6 +318,7 @@ fn decrementCount(self: *DocumentStore, uri: []const u8) void {
|
|||||||
self.allocator.free(import_uri);
|
self.allocator.free(import_uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entry.value.document_scope.deinit(self.allocator);
|
||||||
entry.value.import_uris.deinit();
|
entry.value.import_uris.deinit();
|
||||||
self.allocator.destroy(entry.value);
|
self.allocator.destroy(entry.value);
|
||||||
const uri_key = entry.key;
|
const uri_key = entry.key;
|
||||||
@ -650,7 +604,6 @@ pub fn deinit(self: *DocumentStore) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.handles.deinit();
|
self.handles.deinit();
|
||||||
|
|
||||||
for (self.build_files.items) |build_file| {
|
for (self.build_files.items) |build_file| {
|
||||||
for (build_file.packages.items) |pkg| {
|
for (build_file.packages.items) |pkg| {
|
||||||
self.allocator.free(pkg.name);
|
self.allocator.free(pkg.name);
|
||||||
@ -659,13 +612,38 @@ pub fn deinit(self: *DocumentStore) void {
|
|||||||
self.allocator.free(build_file.uri);
|
self.allocator.free(build_file.uri);
|
||||||
self.allocator.destroy(build_file);
|
self.allocator.destroy(build_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.std_uri) |std_uri| {
|
if (self.std_uri) |std_uri| {
|
||||||
self.allocator.free(std_uri);
|
self.allocator.free(std_uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.allocator.free(self.build_runner_path);
|
self.allocator.free(self.build_runner_path);
|
||||||
self.build_files.deinit(self.allocator);
|
self.build_files.deinit(self.allocator);
|
||||||
self.error_completions.deinit();
|
}
|
||||||
self.enum_completions.deinit();
|
|
||||||
|
fn tagStoreCompletionItems(self: DocumentStore, arena: *std.heap.ArenaAllocator, base: *DocumentStore.Handle, comptime name: []const u8) ![]types.CompletionItem {
|
||||||
|
// TODO Better solution for deciding what tags to include
|
||||||
|
var handle_arr = try arena.allocator.alloc(*DocumentStore.Handle, base.import_uris.items.len + 1);
|
||||||
|
handle_arr[0] = base;
|
||||||
|
var len: usize = @field(base.document_scope, name).len;
|
||||||
|
for (base.import_uris.items) |uri, idx| {
|
||||||
|
handle_arr[idx + 1] = self.handles.get(uri).?;
|
||||||
|
len += @field(handle_arr[idx + 1].document_scope, name).len;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = try arena.allocator.alloc(types.CompletionItem, len);
|
||||||
|
var res_idx: usize = 0;
|
||||||
|
for (handle_arr) |handle| {
|
||||||
|
for (@field(handle.document_scope, name)) |item| {
|
||||||
|
result[res_idx] = item;
|
||||||
|
res_idx += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn errorCompletionItems(self: DocumentStore, arena: *std.heap.ArenaAllocator, base: *DocumentStore.Handle) ![]types.CompletionItem {
|
||||||
|
return try self.tagStoreCompletionItems(arena, base, "error_completions");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enumCompletionItems(self: DocumentStore, arena: *std.heap.ArenaAllocator, base: *DocumentStore.Handle) ![]types.CompletionItem {
|
||||||
|
return try self.tagStoreCompletionItems(arena, base, "enum_completions");
|
||||||
}
|
}
|
||||||
|
@ -1203,7 +1203,7 @@ fn completionHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req:
|
|||||||
.result = .{
|
.result = .{
|
||||||
.CompletionList = .{
|
.CompletionList = .{
|
||||||
.isIncomplete = false,
|
.isIncomplete = false,
|
||||||
.items = document_store.error_completions.completions.items,
|
.items = try document_store.errorCompletionItems(arena, handle),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@ -1212,7 +1212,7 @@ fn completionHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req:
|
|||||||
.result = .{
|
.result = .{
|
||||||
.CompletionList = .{
|
.CompletionList = .{
|
||||||
.isIncomplete = false,
|
.isIncomplete = false,
|
||||||
.items = document_store.enum_completions.completions.items,
|
.items = try document_store.enumCompletionItems(arena, handle),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@ -1640,7 +1640,7 @@ pub fn main() anyerror!void {
|
|||||||
try processJsonRpc(&arena, &json_parser, buf, config);
|
try processJsonRpc(&arena, &json_parser, buf, config);
|
||||||
json_parser.reset();
|
json_parser.reset();
|
||||||
arena.deinit();
|
arena.deinit();
|
||||||
arena.state.buffer_list = .{};
|
arena.state = .{};
|
||||||
|
|
||||||
if (debug_alloc) |dbg| {
|
if (debug_alloc) |dbg| {
|
||||||
std.log.debug(.main, "\n{}\n", .{dbg.info});
|
std.log.debug(.main, "\n{}\n", .{dbg.info});
|
||||||
|
@ -269,7 +269,14 @@ pub const InsertTextFormat = enum(Integer) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const CompletionItem = struct {
|
pub const CompletionItem = struct {
|
||||||
label: String, kind: CompletionItemKind, textEdit: ?TextEdit = null, filterText: ?String = null, insertText: ?String = null, insertTextFormat: ?InsertTextFormat = InsertTextFormat.PlainText, detail: ?String = null, documentation: ?MarkupContent = null
|
label: String,
|
||||||
|
kind: CompletionItemKind,
|
||||||
|
textEdit: ?TextEdit = null,
|
||||||
|
filterText: ?String = null,
|
||||||
|
insertText: ?String = null,
|
||||||
|
insertTextFormat: ?InsertTextFormat = InsertTextFormat.PlainText,
|
||||||
|
detail: ?String = null,
|
||||||
|
documentation: ?MarkupContent = null,
|
||||||
// filterText: String = .NotDefined,
|
// filterText: String = .NotDefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user