Fixes multiple small bugs:

- Correct completion based on scope
 - Semantic tokens for while/if/else/for keywords
 - Fix crash on import path
This commit is contained in:
Luuk de Gram 2021-03-07 21:54:54 +01:00
parent a078a62a37
commit fd6b94bcc9
No known key found for this signature in database
GPG Key ID: A002B174963DBB7D
3 changed files with 77 additions and 48 deletions

View File

@ -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 { pub fn getImportStr(tree: ast.Tree, node: ast.Node.Index, source_index: usize) ?[]const u8 {
const node_tags = tree.nodes.items(.tag); const node_tags = tree.nodes.items(.tag);
var buf: [2]ast.Node.Index = undefined; var buf: [2]ast.Node.Index = undefined;
const decls = declMembers(tree, node_tags[node], node, &buf); if (isContainer(node_tags[node])) {
const decls = declMembers(tree, node_tags[node], node, &buf);
for (decls) |decl_idx| { for (decls) |decl_idx| {
if (!nodeContainsSourceIndex(tree, decl_idx, source_index)) { if (getImportStr(tree, decl_idx, source_index)) |name| {
continue; 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)) { if (!nodeContainsSourceIndex(tree, node, source_index)) {
const builtin_token = tree.nodes.items(.main_token)[decl_idx]; return null;
const call_name = tree.tokenSlice(builtin_token); }
if (!std.mem.eql(u8, call_name, "@import")) continue; if (isBuiltinCall(tree, node)) {
const data = tree.nodes.items(.data)[decl_idx]; const builtin_token = tree.nodes.items(.main_token)[node];
const params = switch (node_tags[decl_idx]) { const call_name = tree.tokenSlice(builtin_token);
.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 (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]]); if (params.len != 1) return null;
return import_str[1 .. import_str.len - 1];
}
if (getImportStr(tree, decl_idx, source_index)) |name| { const import_str = tree.tokenSlice(tree.nodes.items(.main_token)[params[0]]);
return name; return import_str[1 .. import_str.len - 1];
}
} }
return null; return null;
@ -2105,12 +2111,30 @@ fn iterateSymbolsContainerInternal(
if (std.mem.indexOfScalar(ast.Node.Index, use_trail.items, use) != null) continue; if (std.mem.indexOfScalar(ast.Node.Index, use_trail.items, use) != null) continue;
try use_trail.append(use); 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) { const use_expr_node = switch (use_expr.type.data) {
.other => |n| n, .other => |n| n,
else => continue, 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), use_trail: *std.ArrayList(ast.Node.Index),
) error{OutOfMemory}!?DeclWithHandle { ) 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.getEntry(symbol)) |candidate| { if (scope.decls.getEntry(symbol)) |candidate| {
switch (candidate.value) { switch (candidate.value) {
.ast_node => |node| { .ast_node => |node| {
if (handle.tree.nodes.items(.tag)[node].isContainerField()) continue; if (handle.tree.nodes.items(.tag)[node].isContainerField()) continue;
}, },
.label_decl => continue, .label_decl => continue,
else => {}, 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; if (scope.range.start > source_index) return null;
} }

View File

@ -622,8 +622,8 @@ fn hoverSymbol(
const first_token = param.first_doc_comment orelse const first_token = param.first_doc_comment orelse
param.comptime_noalias orelse param.comptime_noalias orelse
param.name_token orelse param.name_token orelse
tree.firstToken(param.type_expr); tree.firstToken(param.type_expr); // extern fn
const last_token = tree.lastToken(param.anytype_ellipsis3 orelse param.type_expr); const last_token = param.anytype_ellipsis3 orelse tree.lastToken(param.type_expr);
const start = offsets.tokenLocation(tree, first_token).start; const start = offsets.tokenLocation(tree, first_token).start;
const end = offsets.tokenLocation(tree, last_token).end; const end = offsets.tokenLocation(tree, last_token).end;

View File

@ -598,6 +598,7 @@ fn writeNodeTokens(
try writeToken(builder, while_node.label_token, .label); try writeToken(builder, while_node.label_token, .label);
try writeToken(builder, while_node.inline_token, .keyword); 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 await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, while_node.ast.cond_expr });
try writeToken(builder, while_node.payload_token, .variable); try writeToken(builder, while_node.payload_token, .variable);
if (while_node.ast.cont_expr != 0) if (while_node.ast.cont_expr != 0)
@ -607,8 +608,10 @@ fn writeNodeTokens(
try writeToken(builder, while_node.error_token, .variable); 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 }); try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, while_node.ast.else_expr });
}
}, },
.@"if", .@"if",
.if_simple, .if_simple,
@ -622,8 +625,10 @@ fn writeNodeTokens(
try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, if_node.ast.then_expr }); try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, if_node.ast.then_expr });
try writeToken(builder, if_node.error_token, .variable); 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 }); try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, if_node.ast.else_expr });
}
}, },
.array_init, .array_init,
.array_init_comma, .array_init_comma,