From bfdeecbd042dcbfd4ee96e490992f6eb7ca1ceb2 Mon Sep 17 00:00:00 2001 From: Alexandros Naskos Date: Mon, 15 Jun 2020 01:19:21 +0300 Subject: [PATCH] Better alias support --- src/analysis.zig | 29 ++++++++++++++++++++ src/main.zig | 70 ++++++++++++++++++------------------------------ 2 files changed, 55 insertions(+), 44 deletions(-) diff --git a/src/analysis.zig b/src/analysis.zig index 4d92a31..09b1b8c 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -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( tree: *ast.Tree, fn_decl: *ast.Node.FnProto, diff --git a/src/main.zig b/src/main.zig index c70ecef..a959824 100644 --- a/src/main.zig +++ b/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( arena: *std.heap.ArenaAllocator, list: *std.ArrayList(types.CompletionItem), @@ -317,9 +290,14 @@ fn nodeToCompletion( const var_decl = node.cast(std.zig.ast.Node.VarDecl).?; const is_const = handle.tree.token_ids[var_decl.mut_token] == .Keyword_const; - const result = try resolveVarDeclFnAlias(arena, node_handle); - if (result.node != node) { - return try nodeToCompletion(arena, list, result, orig_handle, config); + if (try analysis.resolveVarDeclAlias(&document_store, arena, node_handle)) |result| { + const context = DeclToCompletionContext{ + .completions = list, + .config = &config, + .arena = arena, + .orig_handle = orig_handle, + }; + return try declToCompletion(context, result); } try list.append(.{ @@ -403,12 +381,14 @@ fn gotoDefinitionSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, de const location = switch (decl_handle.decl.*) { .ast_node => |node| block: { - const result = try resolveVarDeclFnAlias(arena, .{ .node = node, .handle = handle }); - handle = result.handle; + if (try analysis.resolveVarDeclAlias(&document_store, arena, .{ .node = node, .handle = handle })) |result| { + 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); - break :block result.handle.tree.tokenLocation(0, name_token); + break :block handle.tree.tokenLocation(0, name_token); }, 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 hover_kind: types.MarkupKind = if (client_capabilities.hover_supports_md) .Markdown else .PlainText; const md_string = switch (decl_handle.decl.*) { .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 else ""; - const signature_str = switch (result.node.id) { + const signature_str = switch (node.id) { .VarDecl => blk: { - const var_decl = result.node.cast(std.zig.ast.Node.VarDecl).?; - break :blk analysis.getVariableSignature(result.handle.tree, var_decl); + const var_decl = node.cast(std.zig.ast.Node.VarDecl).?; + break :blk analysis.getVariableSignature(handle.tree, var_decl); }, .FnProto => blk: { - const fn_decl = result.node.cast(std.zig.ast.Node.FnProto).?; - break :blk analysis.getFunctionSignature(result.handle.tree, fn_decl); + const fn_decl = node.cast(std.zig.ast.Node.FnProto).?; + break :blk analysis.getFunctionSignature(handle.tree, fn_decl); }, .ContainerField => blk: { 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)