From fd6b94bcc91565410916eed6910d1d58a714640f Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Sun, 7 Mar 2021 21:54:54 +0100 Subject: [PATCH] Fixes multiple small bugs: - Correct completion based on scope - Semantic tokens for while/if/else/for keywords - Fix crash on import path --- src/analysis.zig | 112 ++++++++++++++++++++++++---------------- src/main.zig | 4 +- src/semantic_tokens.zig | 9 +++- 3 files changed, 77 insertions(+), 48 deletions(-) diff --git a/src/analysis.zig b/src/analysis.zig index 85fe845..f4efe5f 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -1456,39 +1456,45 @@ pub fn fnProto(tree: ast.Tree, node: ast.Node.Index, buf: *[1]ast.Node.Index) ?a pub fn getImportStr(tree: ast.Tree, node: ast.Node.Index, source_index: usize) ?[]const u8 { const node_tags = tree.nodes.items(.tag); var buf: [2]ast.Node.Index = undefined; - const decls = declMembers(tree, node_tags[node], node, &buf); - - for (decls) |decl_idx| { - if (!nodeContainsSourceIndex(tree, decl_idx, source_index)) { - continue; + if (isContainer(node_tags[node])) { + const decls = declMembers(tree, node_tags[node], node, &buf); + for (decls) |decl_idx| { + if (getImportStr(tree, decl_idx, source_index)) |name| { + return name; + } } + return null; + } else if (varDecl(tree, node)) |var_decl| { + return getImportStr(tree, var_decl.ast.init_node, source_index); + } else if (node_tags[node] == .@"usingnamespace") { + return getImportStr(tree, tree.nodes.items(.data)[node].lhs, source_index); + } - if (isBuiltinCall(tree, decl_idx)) { - const builtin_token = tree.nodes.items(.main_token)[decl_idx]; - const call_name = tree.tokenSlice(builtin_token); + if (!nodeContainsSourceIndex(tree, node, source_index)) { + return null; + } - if (!std.mem.eql(u8, call_name, "@import")) continue; - const data = tree.nodes.items(.data)[decl_idx]; - const params = switch (node_tags[decl_idx]) { - .builtin_call, .builtin_call_comma => tree.extra_data[data.lhs..data.rhs], - .builtin_call_two, .builtin_call_two_comma => if (data.lhs == 0) - &[_]ast.Node.Index{} - else if (data.rhs == 0) - &[_]ast.Node.Index{data.lhs} - else - &[_]ast.Node.Index{ data.lhs, data.rhs }, - else => unreachable, - }; + if (isBuiltinCall(tree, node)) { + const builtin_token = tree.nodes.items(.main_token)[node]; + const call_name = tree.tokenSlice(builtin_token); - if (params.len != 1) continue; + if (!std.mem.eql(u8, call_name, "@import")) return null; + const data = tree.nodes.items(.data)[node]; + const params = switch (node_tags[node]) { + .builtin_call, .builtin_call_comma => tree.extra_data[data.lhs..data.rhs], + .builtin_call_two, .builtin_call_two_comma => if (data.lhs == 0) + &[_]ast.Node.Index{} + else if (data.rhs == 0) + &[_]ast.Node.Index{data.lhs} + else + &[_]ast.Node.Index{ data.lhs, data.rhs }, + else => unreachable, + }; - const import_str = tree.tokenSlice(tree.nodes.items(.main_token)[params[0]]); - return import_str[1 .. import_str.len - 1]; - } + if (params.len != 1) return null; - if (getImportStr(tree, decl_idx, source_index)) |name| { - return name; - } + const import_str = tree.tokenSlice(tree.nodes.items(.main_token)[params[0]]); + return import_str[1 .. import_str.len - 1]; } return null; @@ -2105,12 +2111,30 @@ fn iterateSymbolsContainerInternal( if (std.mem.indexOfScalar(ast.Node.Index, use_trail.items, use) != null) continue; try use_trail.append(use); - const use_expr = (try resolveTypeOfNode(store, arena, .{ .node = tree.nodes.items(.data)[use].rhs, .handle = handle })) orelse continue; + const rhs = tree.nodes.items(.data)[use].rhs; + // rhs can be invalid so apply the following check to ensure + // we do not go out of bounds when resolving the type + if (rhs == 0 or rhs > tree.nodes.len) continue; + const use_expr = (try resolveTypeOfNode(store, arena, .{ + .node = tree.nodes.items(.data)[use].rhs, + .handle = orig_handle, + })) orelse continue; + const use_expr_node = switch (use_expr.type.data) { .other => |n| n, else => continue, }; - try iterateSymbolsContainerInternal(store, arena, .{ .node = use_expr_node, .handle = use_expr.handle }, orig_handle, callback, context, false, use_trail); + + try iterateSymbolsContainerInternal( + store, + arena, + .{ .node = use_expr_node, .handle = use_expr.handle }, + orig_handle, + callback, + context, + false, + use_trail, + ); } } } @@ -2283,23 +2307,23 @@ fn lookupSymbolGlobalInternal( use_trail: *std.ArrayList(ast.Node.Index), ) error{OutOfMemory}!?DeclWithHandle { for (handle.document_scope.scopes) |scope| { - // if (source_index >= scope.range.start and source_index < scope.range.end) { - if (scope.decls.getEntry(symbol)) |candidate| { - switch (candidate.value) { - .ast_node => |node| { - if (handle.tree.nodes.items(.tag)[node].isContainerField()) continue; - }, - .label_decl => continue, - else => {}, + if (source_index >= scope.range.start and source_index < scope.range.end) { + if (scope.decls.getEntry(symbol)) |candidate| { + switch (candidate.value) { + .ast_node => |node| { + if (handle.tree.nodes.items(.tag)[node].isContainerField()) continue; + }, + .label_decl => continue, + else => {}, + } + return DeclWithHandle{ + .decl = &candidate.value, + .handle = handle, + }; } - return DeclWithHandle{ - .decl = &candidate.value, - .handle = handle, - }; - } - if (try resolveUse(store, arena, scope.uses, symbol, handle, use_trail)) |result| return result; - // } + if (try resolveUse(store, arena, scope.uses, symbol, handle, use_trail)) |result| return result; + } if (scope.range.start > source_index) return null; } diff --git a/src/main.zig b/src/main.zig index b96aded..79be07c 100644 --- a/src/main.zig +++ b/src/main.zig @@ -622,8 +622,8 @@ fn hoverSymbol( const first_token = param.first_doc_comment orelse param.comptime_noalias orelse param.name_token orelse - tree.firstToken(param.type_expr); - const last_token = tree.lastToken(param.anytype_ellipsis3 orelse param.type_expr); + tree.firstToken(param.type_expr); // extern fn + const last_token = param.anytype_ellipsis3 orelse tree.lastToken(param.type_expr); const start = offsets.tokenLocation(tree, first_token).start; const end = offsets.tokenLocation(tree, last_token).end; diff --git a/src/semantic_tokens.zig b/src/semantic_tokens.zig index 32e43d4..2e3b911 100644 --- a/src/semantic_tokens.zig +++ b/src/semantic_tokens.zig @@ -598,6 +598,7 @@ fn writeNodeTokens( try writeToken(builder, while_node.label_token, .label); try writeToken(builder, while_node.inline_token, .keyword); + try writeToken(builder, while_node.ast.while_token, .keyword); try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, while_node.ast.cond_expr }); try writeToken(builder, while_node.payload_token, .variable); if (while_node.ast.cont_expr != 0) @@ -607,8 +608,10 @@ fn writeNodeTokens( try writeToken(builder, while_node.error_token, .variable); - if (while_node.ast.else_expr != 0) + if (while_node.ast.else_expr != 0) { + try writeToken(builder, while_node.else_token, .keyword); try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, while_node.ast.else_expr }); + } }, .@"if", .if_simple, @@ -622,8 +625,10 @@ fn writeNodeTokens( try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, if_node.ast.then_expr }); try writeToken(builder, if_node.error_token, .variable); - if (if_node.ast.else_expr != 0) + if (if_node.ast.else_expr != 0) { + try writeToken(builder, if_node.else_token, .keyword); try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, if_node.ast.else_expr }); + } }, .array_init, .array_init_comma,