Completion fixes

This commit is contained in:
Luuk de Gram 2021-03-02 22:01:13 +01:00
parent 1dd39914ec
commit 92adeb8826
No known key found for this signature in database
GPG Key ID: A002B174963DBB7D
2 changed files with 61 additions and 43 deletions

View File

@ -12,32 +12,37 @@ pub fn getDocCommentTokenIndex(tree: ast.Tree, node: ast.Node.Index) ?ast.TokenI
const current = tree.nodes.items(.main_token)[node]; const current = tree.nodes.items(.main_token)[node];
var idx = current; var idx = current;
if (idx == 0) return null;
switch (tags[node]) { switch (tags[node]) {
.fn_proto, .fn_proto_one, .fn_proto_simple, .fn_proto_multi, .fn_decl => { .fn_proto, .fn_proto_one, .fn_proto_simple, .fn_proto_multi, .fn_decl => {
idx -= 1; idx -= 1;
idx -= @boolToInt(tokens[idx] == .keyword_extern); if (tokens[idx] == .keyword_extern and idx > 0)
idx -= @boolToInt(tokens[idx] == .keyword_pub); idx -= 1;
if (tokens[idx] == .keyword_pub and idx < 0)
idx -= 1;
}, },
.local_var_decl, .global_var_decl, .aligned_var_decl, .simple_var_decl => { .local_var_decl, .global_var_decl, .aligned_var_decl, .simple_var_decl => {
idx -= 1; idx -= 1;
idx -= @boolToInt(tokens[idx] == .keyword_pub); if (tokens[idx] == .keyword_pub and idx > 0)
idx -= 1;
}, },
.container_field, .container_field_init, .container_field_align => { .container_field, .container_field_init, .container_field_align => {
idx -= 2; idx -= 2; // skip '.' token
}, },
else => { else => {
if (isContainer(tags[node])) { if (isContainer(tags[node])) {
idx -= 2; // go to '=' idx -= 1; // go to '='
idx -= 1; // mutability idx -= 1; // mutability
idx -= 1; // possible 'pub' idx -= 1; // possible 'pub'
idx -= @boolToInt(tokens[idx] == .keyword_pub); // doc comment if (tokens[idx] == .keyword_pub and idx > 0)
idx -= 1;
} }
}, },
} }
// Find first doc comment token // Find first doc comment token
if (tokens[idx] == .doc_comment or tokens[idx] == .container_doc_comment) { if (tokens[idx] == .doc_comment or tokens[idx] == .container_doc_comment) {
while (tokens[idx] == .doc_comment or tokens[idx] == .container_doc_comment) : (idx -= 1) {} while ((tokens[idx] == .doc_comment or tokens[idx] == .container_doc_comment) and idx > 0) : (idx -= 1) {}
return idx + 1; return idx + 1;
} }
@ -164,14 +169,15 @@ pub fn getVariableSignature(tree: ast.Tree, var_decl: ast.full.VarDecl) []const
// analysis.getContainerFieldSignature(handle.tree, field) // analysis.getContainerFieldSignature(handle.tree, field)
pub fn getContainerFieldSignature(tree: ast.Tree, field: ast.full.ContainerField) []const u8 { pub fn getContainerFieldSignature(tree: ast.Tree, field: ast.full.ContainerField) []const u8 {
const start = tree.tokenLocation(0, field.ast.name_token).line_start; const start = tree.tokenLocation(0, field.ast.name_token).line_start;
const end = tree.tokenLocation(@truncate(u32, start), tree.lastToken(field.ast.value_expr)).line_start; const end_node = if (field.ast.value_expr != 0) field.ast.value_expr else field.ast.type_expr;
return tree.source[start..end]; const end = tree.tokenLocation(@truncate(u32, start), tree.lastToken(end_node)).line_end;
return tree.source[start .. end - 1];
} }
/// The type node is "type" /// The type node is "type"
fn typeIsType(tree: ast.Tree, node: ast.Node.Index) bool { fn typeIsType(tree: ast.Tree, node: ast.Node.Index) bool {
if (tree.nodes.items(.tag)[node] == .identifier) { if (tree.nodes.items(.tag)[node] == .identifier) {
return std.mem.eql(u8, tree.tokenSlice(node), "type"); return std.mem.eql(u8, tree.tokenSlice(tree.nodes.items(.main_token)[node]), "type");
} }
return false; return false;
} }
@ -182,7 +188,6 @@ pub fn isTypeFunction(tree: ast.Tree, func: ast.full.FnProto) bool {
pub fn isGenericFunction(tree: ast.Tree, func: *ast.full.FnProto) bool { pub fn isGenericFunction(tree: ast.Tree, func: *ast.full.FnProto) bool {
var it = func.iterate(); var it = func.iterate();
var slice = tree.nodes.items(.tag);
while (it.next()) |param| { while (it.next()) |param| {
if (param.anytype_ellipsis3 != null or param.comptime_noalias != null) { if (param.anytype_ellipsis3 != null or param.comptime_noalias != null) {
return true; return true;
@ -204,12 +209,13 @@ pub fn isPascalCase(name: []const u8) bool {
pub fn getDeclNameToken(tree: ast.Tree, node: ast.Node.Index) ?ast.TokenIndex { pub fn getDeclNameToken(tree: ast.Tree, node: ast.Node.Index) ?ast.TokenIndex {
const tags = tree.nodes.items(.tag); const tags = tree.nodes.items(.tag);
switch (tags[node]) { const main_token = tree.nodes.items(.main_token)[node];
return switch (tags[node]) {
// regular declaration names. + 1 to mut token because name comes after 'const'/'var' // regular declaration names. + 1 to mut token because name comes after 'const'/'var'
.local_var_decl => return tree.localVarDecl(node).ast.mut_token + 1, .local_var_decl => tree.localVarDecl(node).ast.mut_token + 1,
.global_var_decl => return tree.globalVarDecl(node).ast.mut_token + 1, .global_var_decl => tree.globalVarDecl(node).ast.mut_token + 1,
.simple_var_decl => return tree.simpleVarDecl(node).ast.mut_token + 1, .simple_var_decl => tree.simpleVarDecl(node).ast.mut_token + 1,
.aligned_var_decl => return tree.alignedVarDecl(node).ast.mut_token + 1, .aligned_var_decl => tree.alignedVarDecl(node).ast.mut_token + 1,
// function declaration names // function declaration names
.fn_proto, .fn_proto,
@ -217,15 +223,17 @@ pub fn getDeclNameToken(tree: ast.Tree, node: ast.Node.Index) ?ast.TokenIndex {
.fn_proto_one, .fn_proto_one,
.fn_proto_simple, .fn_proto_simple,
.fn_decl, .fn_decl,
=> { => blk: {
var params: [1]ast.Node.Index = undefined; var params: [1]ast.Node.Index = undefined;
return fnProto(tree, node, &params).?.name_token; break :blk fnProto(tree, node, &params).?.name_token;
}, },
// containers // containers
.container_field => return tree.containerField(node).ast.name_token, .container_field => tree.containerField(node).ast.name_token,
.container_field_init => return tree.containerFieldInit(node).ast.name_token, .container_field_init => tree.containerFieldInit(node).ast.name_token,
.container_field_align => return tree.containerFieldAlign(node).ast.name_token, .container_field_align => tree.containerFieldAlign(node).ast.name_token,
.identifier => main_token,
// @TODO: Errors // @TODO: Errors
// .error_=> { // .error_=> {
@ -234,11 +242,12 @@ pub fn getDeclNameToken(tree: ast.Tree, node: ast.Node.Index) ?ast.TokenIndex {
// }, // },
// lhs of main token is name token, so use `node` - 1 // lhs of main token is name token, so use `node` - 1
.test_decl => return getDeclNameToken(tree, node - 1), .test_decl => if (tree.tokens.items(.tag)[main_token + 1] == .string_literal)
else => {}, return main_token + 1
} else
null,
return null; else => null,
};
} }
fn getDeclName(tree: ast.Tree, node: ast.Node.Index) ?[]const u8 { fn getDeclName(tree: ast.Tree, node: ast.Node.Index) ?[]const u8 {
@ -251,7 +260,7 @@ fn getDeclName(tree: ast.Tree, node: ast.Node.Index) ?[]const u8 {
fn isContainerDecl(decl_handle: DeclWithHandle) bool { fn isContainerDecl(decl_handle: DeclWithHandle) bool {
return switch (decl_handle.decl.*) { return switch (decl_handle.decl.*) {
.ast_node => |inner_node| isContainer(decl_handle.handle.tree.nodes.items(.tag)[inner_node]) or inner_node == 0, .ast_node => |inner_node| isContainer(decl_handle.handle.tree.nodes.items(.tag)[inner_node]),
else => false, else => false,
}; };
} }
@ -748,9 +757,8 @@ pub fn resolveTypeOfNodeInternal(
}, },
.field_access => { .field_access => {
const field_access = datas[node]; const field_access = datas[node];
log.debug("Rhs: {s}", .{node_tags[field_access.rhs]}); const rhs_str = nodeToString(handle.tree, node) orelse return null;
const rhs_str = nodeToString(handle.tree, field_access.rhs) orelse return null;
log.debug("Acces string: {s}", .{rhs_str});
// If we are accessing a pointer type, remove one pointerness level :) // If we are accessing a pointer type, remove one pointerness level :)
const left_type = try resolveFieldAccessLhsType( const left_type = try resolveFieldAccessLhsType(
store, store,
@ -918,7 +926,9 @@ pub fn resolveTypeOfNodeInternal(
.type = .{ .data = .{ .other = node }, .is_type_val = false }, .type = .{ .data = .{ .other = node }, .is_type_val = false },
.handle = handle, .handle = handle,
}, },
else => {}, else => {
log.debug("TODO: implement type resolving for ast tag: {s}", .{node_tags[node]});
},
} }
return null; return null;
} }
@ -1267,7 +1277,7 @@ pub fn isNodePublic(tree: ast.Tree, node: ast.Node.Index) bool {
pub fn nodeToString(tree: ast.Tree, node: ast.Node.Index) ?[]const u8 { pub fn nodeToString(tree: ast.Tree, node: ast.Node.Index) ?[]const u8 {
const data = tree.nodes.items(.data); const data = tree.nodes.items(.data);
const main_tokens = tree.nodes.items(.main_token); const main_token = tree.nodes.items(.main_token)[node];
var buf: [1]ast.Node.Index = undefined; var buf: [1]ast.Node.Index = undefined;
switch (tree.nodes.items(.tag)[node]) { switch (tree.nodes.items(.tag)[node]) {
.container_field => return tree.tokenSlice(tree.containerField(node).ast.name_token), .container_field => return tree.tokenSlice(tree.containerField(node).ast.name_token),
@ -1291,6 +1301,16 @@ pub fn nodeToString(tree: ast.Tree, node: ast.Node.Index) ?[]const u8 {
.fn_proto_simple => if (tree.fnProtoSimple(&buf, node).name_token) |name| { .fn_proto_simple => if (tree.fnProtoSimple(&buf, node).name_token) |name| {
return tree.tokenSlice(name); return tree.tokenSlice(name);
}, },
// .call,
// .call_comma,
// .call_one,
// .call_one_comma,
// .async_call,
// .async_call_comma,
// .async_call_one,
// .async_call_one_comma,
// => return tree.tokenSlice(main_token - 1),
.field_access => return tree.tokenSlice(data[node].rhs),
else => { else => {
log.debug("INVALID: {}", .{tree.nodes.items(.tag)[node]}); log.debug("INVALID: {}", .{tree.nodes.items(.tag)[node]});
}, },
@ -1820,6 +1840,7 @@ pub const DeclWithHandle = struct {
const tree = self.handle.tree; const tree = self.handle.tree;
const node_tags = tree.nodes.items(.tag); const node_tags = tree.nodes.items(.tag);
const main_tokens = tree.nodes.items(.main_token); const main_tokens = tree.nodes.items(.main_token);
return switch (self.decl.*) { return switch (self.decl.*) {
.ast_node => |node| try resolveTypeOfNodeInternal(store, arena, .{ .node = node, .handle = self.handle }, bound_type_params), .ast_node => |node| try resolveTypeOfNodeInternal(store, arena, .{ .node = node, .handle = self.handle }, bound_type_params),
.param_decl => |*param_decl| { .param_decl => |*param_decl| {
@ -1925,11 +1946,10 @@ fn findContainerScope(container_handle: NodeWithHandle) ?*Scope {
if (!isContainer(handle.tree.nodes.items(.tag)[container])) return null; if (!isContainer(handle.tree.nodes.items(.tag)[container])) return null;
// Find the container scope. // Find the container scope.
var container_scope: ?*Scope = null;
return for (handle.document_scope.scopes) |*scope| { return for (handle.document_scope.scopes) |*scope| {
switch (scope.*.data) { switch (scope.data) {
.container => |node| if (node == container) { .container => |node| if (node == container) {
break container_scope; break scope;
}, },
else => {}, else => {},
} }
@ -2148,6 +2168,7 @@ 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, i| { for (handle.document_scope.scopes) |scope, i| {
// @TODO: Fix scope positions
// 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) {

View File

@ -220,11 +220,10 @@ fn publishDiagnostics(arena: *std.heap.ArenaAllocator, handle: DocumentStore.Han
for (tree.rootDecls()) |decl_idx| { for (tree.rootDecls()) |decl_idx| {
const decl = tree.nodes.items(.tag)[decl_idx]; const decl = tree.nodes.items(.tag)[decl_idx];
switch (decl) { switch (decl) {
.fn_proto => blk: { .fn_proto, .fn_proto_multi, .fn_proto_one, .fn_proto_simple, .fn_decl => blk: {
const func = tree.fnProto(decl_idx); var buf: [1]std.zig.ast.Node.Index = undefined;
const is_extern = func.extern_export_token != null; const func = analysis.fnProto(tree, decl_idx, &buf).?;
if (is_extern) if (func.extern_export_token != null) break :blk;
break :blk;
if (config.warn_style) { if (config.warn_style) {
if (func.name_token) |name_token| { if (func.name_token) |name_token| {
@ -362,7 +361,7 @@ fn nodeToCompletion(
.arena = arena, .arena = arena,
.orig_handle = orig_handle, .orig_handle = orig_handle,
}; };
try analysis.iterateSymbolsContainer(&document_store, arena, node_handle, orig_handle, declToCompletion, context, !is_type_val); try analysis.iterateSymbolsContainer(&document_store, arena, node_handle, orig_handle, declToCompletion, context, is_type_val);
} }
if (is_type_val) return; if (is_type_val) return;
@ -873,7 +872,6 @@ fn hasComment(tree: ast.Tree, start_token: ast.TokenIndex, end_token: ast.TokenI
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.*) {
.ast_node => |node| try nodeToCompletion(context.arena, context.completions, .{ .node = node, .handle = decl_handle.handle }, null, context.orig_handle, false, context.config.*), .ast_node => |node| try nodeToCompletion(context.arena, context.completions, .{ .node = node, .handle = decl_handle.handle }, null, context.orig_handle, false, context.config.*),
.param_decl => |param| { .param_decl => |param| {
@ -1236,7 +1234,6 @@ fn completionHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req:
if (req.params.position.character >= 0) { if (req.params.position.character >= 0) {
const doc_position = try offsets.documentPosition(handle.document, req.params.position, offset_encoding); const doc_position = try offsets.documentPosition(handle.document, req.params.position, offset_encoding);
const pos_context = try analysis.documentPositionContext(arena, handle.document, doc_position); const pos_context = try analysis.documentPositionContext(arena, handle.document, doc_position);
const use_snippets = config.enable_snippets and client_capabilities.supports_snippets; const use_snippets = config.enable_snippets and client_capabilities.supports_snippets;
switch (pos_context) { switch (pos_context) {
.builtin => try completeBuiltin(arena, id, config), .builtin => try completeBuiltin(arena, id, config),