Usingnamespace support
This commit is contained in:
parent
323b05856e
commit
80dd19dd8b
157
src/analysis.zig
157
src/analysis.zig
@ -265,6 +265,16 @@ fn resolveUnwrapOptionalType(store: *DocumentStore, arena: *std.heap.ArenaAlloca
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolveUnwrapErrorType(store: *DocumentStore, arena: *std.heap.ArenaAllocator, rhs: NodeWithHandle) !?NodeWithHandle {
|
||||||
|
if (rhs.node.cast(ast.Node.InfixOp)) |infix_op| {
|
||||||
|
if (infix_op.op == .ErrorUnion) {
|
||||||
|
return try resolveTypeOfNode(store, arena, .{ .node = infix_op.rhs, .handle = rhs.handle });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// Resolves the child type of a defer type
|
/// Resolves the child type of a defer type
|
||||||
fn resolveDerefType(store: *DocumentStore, arena: *std.heap.ArenaAllocator, deref: NodeWithHandle) !?NodeWithHandle {
|
fn resolveDerefType(store: *DocumentStore, arena: *std.heap.ArenaAllocator, deref: NodeWithHandle) !?NodeWithHandle {
|
||||||
if (deref.node.cast(ast.Node.PrefixOp)) |pop| {
|
if (deref.node.cast(ast.Node.PrefixOp)) |pop| {
|
||||||
@ -352,7 +362,7 @@ pub fn resolveTypeOfNode(store: *DocumentStore, arena: *std.heap.ArenaAllocator,
|
|||||||
return try resolveTypeOfNode(store, arena, .{ .node = vari.type_node orelse vari.init_node.?, .handle = handle });
|
return try resolveTypeOfNode(store, arena, .{ .node = vari.type_node orelse vari.init_node.?, .handle = handle });
|
||||||
},
|
},
|
||||||
.Identifier => {
|
.Identifier => {
|
||||||
if (try lookupSymbolGlobal(store, handle, handle.tree.getNodeSource(node), handle.tree.token_locs[node.firstToken()].start)) |child| {
|
if (try lookupSymbolGlobal(store, arena, handle, handle.tree.getNodeSource(node), handle.tree.token_locs[node.firstToken()].start)) |child| {
|
||||||
return try child.resolveType(store, arena);
|
return try child.resolveType(store, arena);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -409,7 +419,7 @@ pub fn resolveTypeOfNode(store: *DocumentStore, arena: *std.heap.ArenaAllocator,
|
|||||||
})) orelse return null,
|
})) orelse return null,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (try lookupSymbolContainer(store, left_type, rhs_str, true)) |child| {
|
if (try lookupSymbolContainer(store, arena, left_type, rhs_str, true)) |child| {
|
||||||
return try child.resolveType(store, arena);
|
return try child.resolveType(store, arena);
|
||||||
} else return null;
|
} else return null;
|
||||||
},
|
},
|
||||||
@ -420,6 +430,7 @@ pub fn resolveTypeOfNode(store: *DocumentStore, arena: *std.heap.ArenaAllocator,
|
|||||||
})) orelse return null;
|
})) orelse return null;
|
||||||
return try resolveUnwrapOptionalType(store, arena, left_type);
|
return try resolveUnwrapOptionalType(store, arena, left_type);
|
||||||
},
|
},
|
||||||
|
.ErrorUnion => return node_handle,
|
||||||
else => return null,
|
else => return null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -433,17 +444,7 @@ pub fn resolveTypeOfNode(store: *DocumentStore, arena: *std.heap.ArenaAllocator,
|
|||||||
=> return node_handle,
|
=> return node_handle,
|
||||||
.Try => {
|
.Try => {
|
||||||
const rhs_type = (try resolveTypeOfNode(store, arena, .{ .node = prefix_op.rhs, .handle = handle })) orelse return null;
|
const rhs_type = (try resolveTypeOfNode(store, arena, .{ .node = prefix_op.rhs, .handle = handle })) orelse return null;
|
||||||
switch (rhs_type.node.id) {
|
return try resolveUnwrapErrorType(store, arena, rhs_type);
|
||||||
.InfixOp => {
|
|
||||||
const infix_op = rhs_type.node.cast(ast.Node.InfixOp).?;
|
|
||||||
if (infix_op.op == .ErrorUnion) return NodeWithHandle{
|
|
||||||
.node = infix_op.rhs,
|
|
||||||
.handle = rhs_type.handle,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
return rhs_type;
|
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
@ -572,7 +573,7 @@ pub fn getFieldAccessTypeNode(
|
|||||||
switch (tok.id) {
|
switch (tok.id) {
|
||||||
.Eof => return try resolveFieldAccessLhsType(store, arena, current_node),
|
.Eof => return try resolveFieldAccessLhsType(store, arena, current_node),
|
||||||
.Identifier => {
|
.Identifier => {
|
||||||
if (try lookupSymbolGlobal(store, current_node.handle, tokenizer.buffer[tok.loc.start..tok.loc.end], source_index)) |child| {
|
if (try lookupSymbolGlobal(store, arena, current_node.handle, tokenizer.buffer[tok.loc.start..tok.loc.end], source_index)) |child| {
|
||||||
current_node = (try child.resolveType(store, arena)) orelse return null;
|
current_node = (try child.resolveType(store, arena)) orelse return null;
|
||||||
} else return null;
|
} else return null;
|
||||||
},
|
},
|
||||||
@ -584,7 +585,7 @@ pub fn getFieldAccessTypeNode(
|
|||||||
if (after_period.loc.end == tokenizer.buffer.len) return try resolveFieldAccessLhsType(store, arena, current_node);
|
if (after_period.loc.end == tokenizer.buffer.len) return try resolveFieldAccessLhsType(store, arena, current_node);
|
||||||
|
|
||||||
current_node = try resolveFieldAccessLhsType(store, arena, current_node);
|
current_node = try resolveFieldAccessLhsType(store, arena, current_node);
|
||||||
if (try lookupSymbolContainer(store, current_node, tokenizer.buffer[after_period.loc.start..after_period.loc.end], true)) |child| {
|
if (try lookupSymbolContainer(store, arena, current_node, tokenizer.buffer[after_period.loc.start..after_period.loc.end], true)) |child| {
|
||||||
current_node = (try child.resolveType(store, arena)) orelse return null;
|
current_node = (try child.resolveType(store, arena)) orelse return null;
|
||||||
} else return null;
|
} else return null;
|
||||||
},
|
},
|
||||||
@ -976,6 +977,13 @@ pub const DeclWithHandle = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn isPublic(self: DeclWithHandle) bool {
|
||||||
|
return switch (self.decl.*) {
|
||||||
|
.ast_node => |node| isNodePublic(self.handle.tree, node),
|
||||||
|
else => true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn resolveType(self: DeclWithHandle, store: *DocumentStore, arena: *std.heap.ArenaAllocator) !?NodeWithHandle {
|
fn resolveType(self: DeclWithHandle, store: *DocumentStore, arena: *std.heap.ArenaAllocator) !?NodeWithHandle {
|
||||||
return switch (self.decl.*) {
|
return switch (self.decl.*) {
|
||||||
.ast_node => |node| try resolveTypeOfNode(store, arena, .{ .node = node, .handle = self.handle }),
|
.ast_node => |node| try resolveTypeOfNode(store, arena, .{ .node = node, .handle = self.handle }),
|
||||||
@ -1006,13 +1014,65 @@ pub const DeclWithHandle = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn findContainerScope(container_handle: NodeWithHandle) ?*Scope {
|
||||||
|
const container = container_handle.node;
|
||||||
|
const handle = container_handle.handle;
|
||||||
|
|
||||||
|
if (container.id != .ContainerDecl and container.id != .Root and container.id != .ErrorSetDecl) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the container scope.
|
||||||
|
var container_scope: ?*Scope = null;
|
||||||
|
for (handle.document_scope.scopes) |*scope| {
|
||||||
|
switch (scope.*.data) {
|
||||||
|
.container => |node| if (node == container) {
|
||||||
|
container_scope = scope;
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return container_scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iterateSymbolsContainer(
|
||||||
|
store: *DocumentStore,
|
||||||
|
arena: *std.heap.ArenaAllocator,
|
||||||
|
container_handle: NodeWithHandle,
|
||||||
|
orig_handle: *DocumentStore.Handle,
|
||||||
|
comptime callback: var,
|
||||||
|
context: var,
|
||||||
|
) error{OutOfMemory}!void {
|
||||||
|
const container = container_handle.node;
|
||||||
|
const handle = container_handle.handle;
|
||||||
|
|
||||||
|
if (findContainerScope(container_handle)) |container_scope| {
|
||||||
|
var decl_it = container_scope.decls.iterator();
|
||||||
|
while (decl_it.next()) |entry| {
|
||||||
|
const decl = DeclWithHandle{ .decl = &entry.value, .handle = handle };
|
||||||
|
if (handle != orig_handle and !decl.isPublic()) continue;
|
||||||
|
try callback(context, decl);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (container_scope.uses) |use| {
|
||||||
|
if (handle != orig_handle and use.visib_token == null) continue;
|
||||||
|
const use_expr = (try resolveTypeOfNode(store, arena, .{ .node = use.expr, .handle = handle })) orelse continue;
|
||||||
|
try iterateSymbolsContainer(store, arena, use_expr, orig_handle, callback, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std.debug.warn("Did not find container scope when iterating container {} (name: {})\n", .{ container, getDeclName(handle.tree, container) });
|
||||||
|
}
|
||||||
|
|
||||||
pub fn iterateSymbolsGlobal(
|
pub fn iterateSymbolsGlobal(
|
||||||
store: *DocumentStore,
|
store: *DocumentStore,
|
||||||
|
arena: *std.heap.ArenaAllocator,
|
||||||
handle: *DocumentStore.Handle,
|
handle: *DocumentStore.Handle,
|
||||||
source_index: usize,
|
source_index: usize,
|
||||||
comptime callback: var,
|
comptime callback: var,
|
||||||
context: var,
|
context: var,
|
||||||
) !void {
|
) error{OutOfMemory}!void {
|
||||||
for (handle.document_scope.scopes) |scope| {
|
for (handle.document_scope.scopes) |scope| {
|
||||||
if (source_index >= scope.range.start and source_index < scope.range.end) {
|
if (source_index >= scope.range.start and source_index < scope.range.end) {
|
||||||
var decl_it = scope.decls.iterator();
|
var decl_it = scope.decls.iterator();
|
||||||
@ -1022,6 +1082,8 @@ pub fn iterateSymbolsGlobal(
|
|||||||
|
|
||||||
for (scope.uses) |use| {
|
for (scope.uses) |use| {
|
||||||
// @TODO Resolve uses, iterate over their symbols.
|
// @TODO Resolve uses, iterate over their symbols.
|
||||||
|
const use_expr = (try resolveTypeOfNode(store, arena, .{ .node = use.expr, .handle = handle })) orelse continue;
|
||||||
|
try iterateSymbolsContainer(store, arena, use_expr, handle, callback, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1045,7 +1107,32 @@ pub fn innermostContainer(handle: *DocumentStore.Handle, source_index: usize) No
|
|||||||
return .{ .node = current, .handle = handle };
|
return .{ .node = current, .handle = handle };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookupSymbolGlobal(store: *DocumentStore, handle: *DocumentStore.Handle, symbol: []const u8, source_index: usize) !?DeclWithHandle {
|
fn resolveUse(
|
||||||
|
store: *DocumentStore,
|
||||||
|
arena: *std.heap.ArenaAllocator,
|
||||||
|
uses: []const *ast.Node.Use,
|
||||||
|
symbol: []const u8,
|
||||||
|
handle: *DocumentStore.Handle,
|
||||||
|
) error{OutOfMemory}!?DeclWithHandle {
|
||||||
|
for (uses) |use| {
|
||||||
|
const use_expr = (try resolveTypeOfNode(store, arena, .{ .node = use.expr, .handle = handle })) orelse continue;
|
||||||
|
if (try lookupSymbolContainer(store, arena, use_expr, symbol, false)) |candidate| {
|
||||||
|
if (candidate.handle != handle and !candidate.isPublic()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lookupSymbolGlobal(
|
||||||
|
store: *DocumentStore,
|
||||||
|
arena: *std.heap.ArenaAllocator,
|
||||||
|
handle: *DocumentStore.Handle,
|
||||||
|
symbol: []const u8,
|
||||||
|
source_index: usize,
|
||||||
|
) error{OutOfMemory}!?DeclWithHandle {
|
||||||
for (handle.document_scope.scopes) |scope| {
|
for (handle.document_scope.scopes) |scope| {
|
||||||
if (source_index >= scope.range.start and source_index < scope.range.end) {
|
if (source_index >= scope.range.start and source_index < scope.range.end) {
|
||||||
if (scope.decls.get(symbol)) |candidate| {
|
if (scope.decls.get(symbol)) |candidate| {
|
||||||
@ -1061,9 +1148,7 @@ pub fn lookupSymbolGlobal(store: *DocumentStore, handle: *DocumentStore.Handle,
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
for (scope.uses) |use| {
|
if (try resolveUse(store, arena, scope.uses, symbol, handle)) |result| return result;
|
||||||
// @TODO Resolve use, lookup symbol in resulting scope.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scope.range.start > source_index) return null;
|
if (scope.range.start > source_index) return null;
|
||||||
@ -1072,27 +1157,17 @@ pub fn lookupSymbolGlobal(store: *DocumentStore, handle: *DocumentStore.Handle,
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookupSymbolContainer(store: *DocumentStore, container_handle: NodeWithHandle, symbol: []const u8, accept_fields: bool) !?DeclWithHandle {
|
pub fn lookupSymbolContainer(
|
||||||
|
store: *DocumentStore,
|
||||||
|
arena: *std.heap.ArenaAllocator,
|
||||||
|
container_handle: NodeWithHandle,
|
||||||
|
symbol: []const u8,
|
||||||
|
accept_fields: bool,
|
||||||
|
) error{OutOfMemory}!?DeclWithHandle {
|
||||||
const container = container_handle.node;
|
const container = container_handle.node;
|
||||||
const handle = container_handle.handle;
|
const handle = container_handle.handle;
|
||||||
|
|
||||||
if (container.id != .ContainerDecl and container.id != .Root and container.id != .ErrorSetDecl) {
|
if (findContainerScope(container_handle)) |container_scope| {
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the container scope.
|
|
||||||
var maybe_container_scope: ?*Scope = null;
|
|
||||||
for (handle.document_scope.scopes) |*scope| {
|
|
||||||
switch (scope.*.data) {
|
|
||||||
.container => |node| if (node == container) {
|
|
||||||
maybe_container_scope = scope;
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maybe_container_scope) |container_scope| {
|
|
||||||
if (container_scope.decls.get(symbol)) |candidate| {
|
if (container_scope.decls.get(symbol)) |candidate| {
|
||||||
switch (candidate.value) {
|
switch (candidate.value) {
|
||||||
.ast_node => |node| {
|
.ast_node => |node| {
|
||||||
@ -1103,13 +1178,11 @@ pub fn lookupSymbolContainer(store: *DocumentStore, container_handle: NodeWithHa
|
|||||||
return DeclWithHandle{ .decl = &candidate.value, .handle = handle };
|
return DeclWithHandle{ .decl = &candidate.value, .handle = handle };
|
||||||
}
|
}
|
||||||
|
|
||||||
for (container_scope.uses) |use| {
|
if (try resolveUse(store, arena, container_scope.uses, symbol, handle)) |result| return result;
|
||||||
// @TODO Resolve use, lookup symbol in resulting scope.
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
std.debug.warn("Did not find container scope when looking up in container {} (name: {})\n", .{container, getDeclName(handle.tree, container)});
|
std.debug.warn("Did not find container scope when looking up in container {} (name: {})\n", .{ container, getDeclName(handle.tree, container) });
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
36
src/main.zig
36
src/main.zig
@ -196,26 +196,6 @@ fn publishDiagnostics(handle: DocumentStore.Handle, config: Config) !void {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn containerToCompletion(
|
|
||||||
arena: *std.heap.ArenaAllocator,
|
|
||||||
list: *std.ArrayList(types.CompletionItem),
|
|
||||||
container_handle: analysis.NodeWithHandle,
|
|
||||||
orig_handle: *DocumentStore.Handle,
|
|
||||||
config: Config,
|
|
||||||
) !void {
|
|
||||||
// @TODO Something like iterateSymbolsGlobal but for container to support uses.
|
|
||||||
const container = container_handle.node;
|
|
||||||
const handle = container_handle.handle;
|
|
||||||
|
|
||||||
var child_idx: usize = 0;
|
|
||||||
while (container.iterate(child_idx)) |child_node| : (child_idx += 1) {
|
|
||||||
// Declarations in the same file do not need to be public.
|
|
||||||
if (orig_handle == handle or analysis.isNodePublic(handle.tree, child_node)) {
|
|
||||||
try nodeToCompletion(arena, list, .{ .node = child_node, .handle = handle }, orig_handle, config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolveVarDeclFnAlias(arena: *std.heap.ArenaAllocator, decl_handle: analysis.NodeWithHandle) !analysis.NodeWithHandle {
|
fn resolveVarDeclFnAlias(arena: *std.heap.ArenaAllocator, decl_handle: analysis.NodeWithHandle) !analysis.NodeWithHandle {
|
||||||
const decl = decl_handle.node;
|
const decl = decl_handle.node;
|
||||||
const handle = decl_handle.handle;
|
const handle = decl_handle.handle;
|
||||||
@ -263,7 +243,13 @@ fn nodeToCompletion(
|
|||||||
|
|
||||||
switch (node.id) {
|
switch (node.id) {
|
||||||
.ErrorSetDecl, .Root, .ContainerDecl => {
|
.ErrorSetDecl, .Root, .ContainerDecl => {
|
||||||
try containerToCompletion(arena, list, node_handle, orig_handle, config);
|
const context = DeclToCompletionContext{
|
||||||
|
.completions = list,
|
||||||
|
.config = &config,
|
||||||
|
.arena = arena,
|
||||||
|
.orig_handle = orig_handle,
|
||||||
|
};
|
||||||
|
try analysis.iterateSymbolsContainer(&document_store, arena, node_handle, orig_handle, declToCompletion, context);
|
||||||
},
|
},
|
||||||
.FnProto => {
|
.FnProto => {
|
||||||
const func = node.cast(std.zig.ast.Node.FnProto).?;
|
const func = node.cast(std.zig.ast.Node.FnProto).?;
|
||||||
@ -505,7 +491,7 @@ fn getSymbolGlobal(arena: *std.heap.ArenaAllocator, pos_index: usize, handle: *D
|
|||||||
const name = identifierFromPosition(pos_index, handle.*);
|
const name = identifierFromPosition(pos_index, handle.*);
|
||||||
if (name.len == 0) return null;
|
if (name.len == 0) return null;
|
||||||
|
|
||||||
return try analysis.lookupSymbolGlobal(&document_store, handle, name, pos_index);
|
return try analysis.lookupSymbolGlobal(&document_store, arena, handle, name, pos_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gotoDefinitionGlobal(id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: Config) !void {
|
fn gotoDefinitionGlobal(id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: Config) !void {
|
||||||
@ -539,7 +525,7 @@ fn getSymbolFieldAccess(
|
|||||||
var tokenizer = std.zig.Tokenizer.init(line[range.start..range.end]);
|
var tokenizer = std.zig.Tokenizer.init(line[range.start..range.end]);
|
||||||
|
|
||||||
if (try analysis.getFieldAccessTypeNode(&document_store, arena, handle, pos_index, &tokenizer)) |container_handle| {
|
if (try analysis.getFieldAccessTypeNode(&document_store, arena, handle, pos_index, &tokenizer)) |container_handle| {
|
||||||
return try analysis.lookupSymbolContainer(&document_store, container_handle, name, true);
|
return try analysis.lookupSymbolContainer(&document_store, arena, container_handle, name, true);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -606,7 +592,7 @@ const DeclToCompletionContext = struct {
|
|||||||
orig_handle: *DocumentStore.Handle,
|
orig_handle: *DocumentStore.Handle,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn decltoCompletion(context: DeclToCompletionContext, decl_handle: analysis.DeclWithHandle) !void {
|
fn declToCompletion(context: DeclToCompletionContext, decl_handle: analysis.DeclWithHandle) !void {
|
||||||
const tree = decl_handle.handle.tree;
|
const tree = decl_handle.handle.tree;
|
||||||
|
|
||||||
switch (decl_handle.decl.*) {
|
switch (decl_handle.decl.*) {
|
||||||
@ -661,7 +647,7 @@ fn completeGlobal(id: types.RequestId, pos_index: usize, handle: *DocumentStore.
|
|||||||
.arena = &arena,
|
.arena = &arena,
|
||||||
.orig_handle = handle,
|
.orig_handle = handle,
|
||||||
};
|
};
|
||||||
try analysis.iterateSymbolsGlobal(&document_store, handle, pos_index, decltoCompletion, context);
|
try analysis.iterateSymbolsGlobal(&document_store, &arena, handle, pos_index, declToCompletion, context);
|
||||||
|
|
||||||
try send(types.Response{
|
try send(types.Response{
|
||||||
.id = id,
|
.id = id,
|
||||||
|
Loading…
Reference in New Issue
Block a user