Better alias support
This commit is contained in:
parent
e68bec8673
commit
bfdeecbd04
@ -207,6 +207,35 @@ fn getDeclName(tree: *ast.Tree, node: *ast.Node) ?[]const u8 {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolves variable declarationms like `const decl = @import("decl-file.zig").decl;` to the module's node
|
||||||
|
pub fn resolveVarDeclAlias(store: *DocumentStore, arena: *std.heap.ArenaAllocator, decl_handle: NodeWithHandle) !?DeclWithHandle {
|
||||||
|
const decl = decl_handle.node;
|
||||||
|
const handle = decl_handle.handle;
|
||||||
|
|
||||||
|
if (decl.cast(ast.Node.VarDecl)) |var_decl| {
|
||||||
|
if (var_decl.init_node == null) return null;
|
||||||
|
|
||||||
|
const base_expr = var_decl.init_node.?;
|
||||||
|
if (base_expr.cast(ast.Node.InfixOp)) |infix_op| {
|
||||||
|
if (infix_op.op != .Period) return null;
|
||||||
|
if (infix_op.lhs.cast(ast.Node.BuiltinCall)) |builtin_call| {
|
||||||
|
const name = handle.tree.tokenSlice(infix_op.rhs.firstToken());
|
||||||
|
|
||||||
|
if (!std.mem.eql(u8, handle.tree.tokenSlice(builtin_call.builtin_token), "@import"))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (!std.mem.eql(u8, handle.tree.tokenSlice(var_decl.name_token), name))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
const container_node = (try resolveTypeOfNode(store, arena, .{ .node = infix_op.lhs, .handle = handle })) orelse return null;
|
||||||
|
return lookupSymbolContainer(store, arena, container_node, name, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
fn findReturnStatementInternal(
|
fn findReturnStatementInternal(
|
||||||
tree: *ast.Tree,
|
tree: *ast.Tree,
|
||||||
fn_decl: *ast.Node.FnProto,
|
fn_decl: *ast.Node.FnProto,
|
||||||
|
70
src/main.zig
70
src/main.zig
@ -199,33 +199,6 @@ fn publishDiagnostics(handle: DocumentStore.Handle, config: Config) !void {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolveVarDeclFnAlias(arena: *std.heap.ArenaAllocator, decl_handle: analysis.NodeWithHandle) !analysis.NodeWithHandle {
|
|
||||||
const decl = decl_handle.node;
|
|
||||||
const handle = decl_handle.handle;
|
|
||||||
|
|
||||||
if (decl.cast(std.zig.ast.Node.VarDecl)) |var_decl| {
|
|
||||||
const child_node = block: {
|
|
||||||
if (var_decl.type_node) |type_node| {
|
|
||||||
if (std.mem.eql(u8, "type", handle.tree.tokenSlice(type_node.firstToken()))) {
|
|
||||||
break :block var_decl.init_node orelse type_node;
|
|
||||||
}
|
|
||||||
break :block type_node;
|
|
||||||
}
|
|
||||||
break :block var_decl.init_node.?;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (try analysis.resolveTypeOfNode(&document_store, arena, .{ .node = child_node, .handle = handle })) |resolved_node| {
|
|
||||||
// TODO Just return it anyway?
|
|
||||||
// This would allow deep goto definition etc.
|
|
||||||
// Try it out.
|
|
||||||
if (resolved_node.node.id == .FnProto) {
|
|
||||||
return resolved_node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return decl_handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn nodeToCompletion(
|
fn nodeToCompletion(
|
||||||
arena: *std.heap.ArenaAllocator,
|
arena: *std.heap.ArenaAllocator,
|
||||||
list: *std.ArrayList(types.CompletionItem),
|
list: *std.ArrayList(types.CompletionItem),
|
||||||
@ -317,9 +290,14 @@ fn nodeToCompletion(
|
|||||||
const var_decl = node.cast(std.zig.ast.Node.VarDecl).?;
|
const var_decl = node.cast(std.zig.ast.Node.VarDecl).?;
|
||||||
const is_const = handle.tree.token_ids[var_decl.mut_token] == .Keyword_const;
|
const is_const = handle.tree.token_ids[var_decl.mut_token] == .Keyword_const;
|
||||||
|
|
||||||
const result = try resolveVarDeclFnAlias(arena, node_handle);
|
if (try analysis.resolveVarDeclAlias(&document_store, arena, node_handle)) |result| {
|
||||||
if (result.node != node) {
|
const context = DeclToCompletionContext{
|
||||||
return try nodeToCompletion(arena, list, result, orig_handle, config);
|
.completions = list,
|
||||||
|
.config = &config,
|
||||||
|
.arena = arena,
|
||||||
|
.orig_handle = orig_handle,
|
||||||
|
};
|
||||||
|
return try declToCompletion(context, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
try list.append(.{
|
try list.append(.{
|
||||||
@ -403,12 +381,14 @@ fn gotoDefinitionSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, de
|
|||||||
|
|
||||||
const location = switch (decl_handle.decl.*) {
|
const location = switch (decl_handle.decl.*) {
|
||||||
.ast_node => |node| block: {
|
.ast_node => |node| block: {
|
||||||
const result = try resolveVarDeclFnAlias(arena, .{ .node = node, .handle = handle });
|
if (try analysis.resolveVarDeclAlias(&document_store, arena, .{ .node = node, .handle = handle })) |result| {
|
||||||
handle = result.handle;
|
handle = result.handle;
|
||||||
|
break :block result.location();
|
||||||
|
}
|
||||||
|
|
||||||
const name_token = analysis.getDeclNameToken(result.handle.tree, result.node) orelse
|
const name_token = analysis.getDeclNameToken(handle.tree, node) orelse
|
||||||
return try respondGeneric(id, null_result_response);
|
return try respondGeneric(id, null_result_response);
|
||||||
break :block result.handle.tree.tokenLocation(0, name_token);
|
break :block handle.tree.tokenLocation(0, name_token);
|
||||||
},
|
},
|
||||||
else => decl_handle.location(),
|
else => decl_handle.location(),
|
||||||
};
|
};
|
||||||
@ -424,33 +404,35 @@ fn gotoDefinitionSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, de
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hoverSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, decl_handle: analysis.DeclWithHandle) !void {
|
fn hoverSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, decl_handle: analysis.DeclWithHandle) (std.os.WriteError || error{OutOfMemory})!void {
|
||||||
const handle = decl_handle.handle;
|
const handle = decl_handle.handle;
|
||||||
|
|
||||||
const hover_kind: types.MarkupKind = if (client_capabilities.hover_supports_md) .Markdown else .PlainText;
|
const hover_kind: types.MarkupKind = if (client_capabilities.hover_supports_md) .Markdown else .PlainText;
|
||||||
const md_string = switch (decl_handle.decl.*) {
|
const md_string = switch (decl_handle.decl.*) {
|
||||||
.ast_node => |node| ast_node: {
|
.ast_node => |node| ast_node: {
|
||||||
const result = try resolveVarDeclFnAlias(arena, .{ .node = node, .handle = handle });
|
if (try analysis.resolveVarDeclAlias(&document_store, arena, .{ .node = node, .handle = handle })) |result| {
|
||||||
|
return try hoverSymbol(id, arena, result);
|
||||||
|
}
|
||||||
|
|
||||||
const doc_str = if (try analysis.getDocComments(&arena.allocator, result.handle.tree, result.node, hover_kind)) |str|
|
const doc_str = if (try analysis.getDocComments(&arena.allocator, handle.tree, node, hover_kind)) |str|
|
||||||
str
|
str
|
||||||
else
|
else
|
||||||
"";
|
"";
|
||||||
|
|
||||||
const signature_str = switch (result.node.id) {
|
const signature_str = switch (node.id) {
|
||||||
.VarDecl => blk: {
|
.VarDecl => blk: {
|
||||||
const var_decl = result.node.cast(std.zig.ast.Node.VarDecl).?;
|
const var_decl = node.cast(std.zig.ast.Node.VarDecl).?;
|
||||||
break :blk analysis.getVariableSignature(result.handle.tree, var_decl);
|
break :blk analysis.getVariableSignature(handle.tree, var_decl);
|
||||||
},
|
},
|
||||||
.FnProto => blk: {
|
.FnProto => blk: {
|
||||||
const fn_decl = result.node.cast(std.zig.ast.Node.FnProto).?;
|
const fn_decl = node.cast(std.zig.ast.Node.FnProto).?;
|
||||||
break :blk analysis.getFunctionSignature(result.handle.tree, fn_decl);
|
break :blk analysis.getFunctionSignature(handle.tree, fn_decl);
|
||||||
},
|
},
|
||||||
.ContainerField => blk: {
|
.ContainerField => blk: {
|
||||||
const field = node.cast(std.zig.ast.Node.ContainerField).?;
|
const field = node.cast(std.zig.ast.Node.ContainerField).?;
|
||||||
break :blk analysis.getContainerFieldSignature(result.handle.tree, field);
|
break :blk analysis.getContainerFieldSignature(handle.tree, field);
|
||||||
},
|
},
|
||||||
else => analysis.nodeToString(result.handle.tree, result.node) orelse return try respondGeneric(id, null_result_response),
|
else => analysis.nodeToString(handle.tree, node) orelse return try respondGeneric(id, null_result_response),
|
||||||
};
|
};
|
||||||
|
|
||||||
break :ast_node if (hover_kind == .Markdown)
|
break :ast_node if (hover_kind == .Markdown)
|
||||||
|
Loading…
Reference in New Issue
Block a user