Hovering fixes

This commit is contained in:
Luuk de Gram 2021-03-02 15:32:38 +01:00
parent c8a2467fac
commit 1dd39914ec
No known key found for this signature in database
GPG Key ID: A002B174963DBB7D
3 changed files with 127 additions and 72 deletions

View File

@ -11,21 +11,34 @@ pub fn getDocCommentTokenIndex(tree: ast.Tree, node: ast.Node.Index) ?ast.TokenI
const tokens = tree.tokens.items(.tag); const tokens = tree.tokens.items(.tag);
const current = tree.nodes.items(.main_token)[node]; const current = tree.nodes.items(.main_token)[node];
var idx = current;
switch (tags[node]) { switch (tags[node]) {
.fn_proto, .fn_proto_one, .fn_proto_simple, .fn_proto_multi => { .fn_proto, .fn_proto_one, .fn_proto_simple, .fn_proto_multi, .fn_decl => {
var idx = current - 1; idx -= 1;
idx -= @boolToInt(tokens[idx] == .keyword_extern); idx -= @boolToInt(tokens[idx] == .keyword_extern);
idx -= @boolToInt(tokens[idx] == .keyword_pub); idx -= @boolToInt(tokens[idx] == .keyword_pub);
return if (tokens[idx] == .doc_comment) idx else null;
}, },
.local_var_decl, .global_var_decl, .aligned_var_decl, .simple_var_decl => { .local_var_decl, .global_var_decl, .aligned_var_decl, .simple_var_decl => {
return if (tokens[current - 1] == .doc_comment) current - 1 else null; idx -= 1;
idx -= @boolToInt(tokens[idx] == .keyword_pub);
}, },
.container_field, .container_field_init, .container_field_align => { .container_field, .container_field_init, .container_field_align => {
var idx = current - 2; // skip '.' idx -= 2;
return if (tokens[idx] == .doc_comment) idx else null;
}, },
else => return null, else => {
if (isContainer(tags[node])) {
idx -= 2; // go to '='
idx -= 1; // mutability
idx -= 1; // possible 'pub'
idx -= @boolToInt(tokens[idx] == .keyword_pub); // doc comment
}
},
}
// Find first doc comment token
if (tokens[idx] == .doc_comment or tokens[idx] == .container_doc_comment) {
while (tokens[idx] == .doc_comment or tokens[idx] == .container_doc_comment) : (idx -= 1) {}
return idx + 1;
} }
// @TODO: Implement doc comments for tags // @TODO: Implement doc comments for tags
@ -63,7 +76,6 @@ pub fn collectDocComments(
defer lines.deinit(); defer lines.deinit();
const token_tags = tree.tokens.items(.tag); const token_tags = tree.tokens.items(.tag);
const loc = tree.tokenLocation(0, doc_comments);
var curr_line_tok = doc_comments; var curr_line_tok = doc_comments;
while (true) : (curr_line_tok += 1) { while (true) : (curr_line_tok += 1) {
@ -81,8 +93,8 @@ pub fn collectDocComments(
/// Gets a function signature (keywords, name, return value) /// Gets a function signature (keywords, name, return value)
pub fn getFunctionSignature(tree: ast.Tree, func: ast.full.FnProto) []const u8 { pub fn getFunctionSignature(tree: ast.Tree, func: ast.full.FnProto) []const u8 {
const start = tree.tokenLocation(0, func.ast.fn_token).line_start; const start = tree.tokenLocation(0, func.ast.fn_token).line_start;
const end = tree.tokenLocation(0, func.ast.return_type).line_end; const end = tree.tokenLocation(0, tree.nodes.items(.main_token)[func.ast.return_type]).line_end;
return tree.source[start..end]; return tree.source[start .. end - 1];
} }
/// Gets a function snippet insert text /// Gets a function snippet insert text
@ -200,16 +212,15 @@ pub fn getDeclNameToken(tree: ast.Tree, node: ast.Node.Index) ?ast.TokenIndex {
.aligned_var_decl => return tree.alignedVarDecl(node).ast.mut_token + 1, .aligned_var_decl => return tree.alignedVarDecl(node).ast.mut_token + 1,
// function declaration names // function declaration names
.fn_proto => return tree.fnProto(node).name_token, .fn_proto,
.fn_proto_simple => { .fn_proto_multi,
.fn_proto_one,
.fn_proto_simple,
.fn_decl,
=> {
var params: [1]ast.Node.Index = undefined; var params: [1]ast.Node.Index = undefined;
return tree.fnProtoSimple(&params, node).name_token; return fnProto(tree, node, &params).?.name_token;
}, },
.fn_proto_one => {
var params: [1]ast.Node.Index = undefined;
return tree.fnProtoOne(&params, node).name_token;
},
.fn_proto_multi => return tree.fnProtoMulti(node).name_token,
// containers // containers
.container_field => return tree.containerField(node).ast.name_token, .container_field => return tree.containerField(node).ast.name_token,
@ -272,7 +283,17 @@ fn resolveVarDeclAliasInternal(
const lhs = datas[node_handle.node].lhs; const lhs = datas[node_handle.node].lhs;
const container_node = if (isBuiltinCall(tree, lhs)) block: { const container_node = if (isBuiltinCall(tree, lhs)) block: {
const builtin = builtinCallParams(tree, lhs); const data = datas[lhs];
const builtin = switch (node_tags[lhs]) {
.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 (!std.mem.eql(u8, tree.tokenSlice(main_tokens[lhs]), "@import")) if (!std.mem.eql(u8, tree.tokenSlice(main_tokens[lhs]), "@import"))
return null; return null;
@ -726,13 +747,16 @@ pub fn resolveTypeOfNodeInternal(
return try resolveBracketAccessType(store, arena, left_type, .Single, bound_type_params); return try resolveBracketAccessType(store, arena, left_type, .Single, bound_type_params);
}, },
.field_access => { .field_access => {
const rhs_str = nodeToString(handle.tree, datas[node].rhs) orelse return null; const field_access = datas[node];
log.debug("Rhs: {s}", .{node_tags[field_access.rhs]});
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,
arena, arena,
(try resolveTypeOfNodeInternal(store, arena, .{ (try resolveTypeOfNodeInternal(store, arena, .{
.node = datas[node].lhs, .node = field_access.lhs,
.handle = handle, .handle = handle,
}, bound_type_params)) orelse return null, }, bound_type_params)) orelse return null,
bound_type_params, bound_type_params,
@ -799,7 +823,17 @@ pub fn resolveTypeOfNodeInternal(
}; };
}, },
.builtin_call, .builtin_call_comma, .builtin_call_two, .builtin_call_two_comma => { .builtin_call, .builtin_call_comma, .builtin_call_two, .builtin_call_two_comma => {
const params = builtinCallParams(tree, node); const data = datas[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 call_name = tree.tokenSlice(main_tokens[node]); const call_name = tree.tokenSlice(main_tokens[node]);
if (std.mem.eql(u8, call_name, "@This")) { if (std.mem.eql(u8, call_name, "@This")) {
@ -843,7 +877,7 @@ pub fn resolveTypeOfNodeInternal(
} }
if (!std.mem.eql(u8, call_name, "@import")) return null; if (!std.mem.eql(u8, call_name, "@import")) return null;
if (params.len < 1) return null; if (params.len == 0) return null;
const import_param = params[0]; const import_param = params[0];
if (node_tags[import_param] != .string_literal) return null; if (node_tags[import_param] != .string_literal) return null;
@ -866,7 +900,7 @@ pub fn resolveTypeOfNodeInternal(
=> { => {
return TypeWithHandle.typeVal(node_handle); return TypeWithHandle.typeVal(node_handle);
}, },
.fn_proto, .fn_proto_multi, .fn_proto_one, .fn_proto_simple => { .fn_proto, .fn_proto_multi, .fn_proto_one, .fn_proto_simple, .fn_decl => {
var buf: [1]ast.Node.Index = undefined; var buf: [1]ast.Node.Index = undefined;
const fn_proto = fnProto(tree, node, &buf).?; const fn_proto = fnProto(tree, node, &buf).?;
@ -976,6 +1010,7 @@ pub const TypeWithHandle = struct {
.fn_proto_multi, .fn_proto_multi,
.fn_proto_one, .fn_proto_one,
.fn_proto_simple, .fn_proto_simple,
.fn_decl,
=> isTypeFunction(fnProto(tree, n, &buf).?), => isTypeFunction(fnProto(tree, n, &buf).?),
else => false, else => false,
}, },
@ -991,6 +1026,7 @@ pub const TypeWithHandle = struct {
.fn_proto_multi, .fn_proto_multi,
.fn_proto_one, .fn_proto_one,
.fn_proto_simple, .fn_proto_simple,
.fn_decl,
=> isGenericFunction(fnProto(tree, n, &buf).?), => isGenericFunction(fnProto(tree, n, &buf).?),
else => false, else => false,
}, },
@ -1006,6 +1042,7 @@ pub const TypeWithHandle = struct {
.fn_proto_multi, .fn_proto_multi,
.fn_proto_one, .fn_proto_one,
.fn_proto_simple, .fn_proto_simple,
.fn_decl,
=> true, => true,
else => false, else => false,
}, },
@ -1024,16 +1061,26 @@ fn maybeCollectImport(tree: ast.Tree, builtin_call: ast.Node.Index, arr: *std.Ar
const datas = tree.nodes.items(.data); const datas = tree.nodes.items(.data);
const builtin_tag = tags[builtin_call]; const builtin_tag = tags[builtin_call];
const builtin_data = datas[builtin_call]; const data = datas[builtin_call];
std.debug.assert(builtin_tag == .builtin_call); std.debug.assert(isBuiltinCall(tree, builtin_call));
if (!std.mem.eql(u8, tree.tokenSlice(builtin_call), "@import")) return; if (!std.mem.eql(u8, tree.tokenSlice(builtin_call), "@import")) return;
const params = tree.extra_data[builtin_data.lhs..builtin_data.rhs];
const params = switch (builtin_tag) {
.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) return; if (params.len > 1) return;
if (tags[params[0]] != .string_literal) return; if (tags[params[0]] != .string_literal) return;
const import_str = tree.tokenSlice(params[0]); const import_str = tree.tokenSlice(tree.nodes.items(.main_token)[params[0]]);
try arr.append(import_str[1 .. import_str.len - 1]); try arr.append(import_str[1 .. import_str.len - 1]);
} }
@ -1219,6 +1266,8 @@ 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 main_tokens = tree.nodes.items(.main_token);
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),
@ -1267,29 +1316,13 @@ fn isBuiltinCall(tree: ast.Tree, node: ast.Node.Index) bool {
}; };
} }
pub fn builtinCallParams(tree: ast.Tree, node: ast.Node.Index) []const ast.Node.Index {
std.debug.assert(isBuiltinCall(tree, node));
const datas = tree.nodes.items(.data);
return switch (tree.nodes.items(.tag)[node]) {
.builtin_call, .builtin_call_comma => tree.extra_data[datas[node].lhs..datas[node].rhs],
.builtin_call_two, .builtin_call_two_comma => if (datas[node].lhs == 0)
&[_]ast.Node.Index{}
else if (datas[node].rhs == 0)
&[_]ast.Node.Index{datas[node].lhs}
else
&[_]ast.Node.Index{ datas[node].lhs, datas[node].rhs },
else => unreachable,
};
}
pub fn fnProto(tree: ast.Tree, node: ast.Node.Index, buf: *[1]ast.Node.Index) ?ast.full.FnProto { pub fn fnProto(tree: ast.Tree, node: ast.Node.Index, buf: *[1]ast.Node.Index) ?ast.full.FnProto {
return switch (tree.nodes.items(.tag)[node]) { return switch (tree.nodes.items(.tag)[node]) {
.fn_proto => tree.fnProto(node), .fn_proto => tree.fnProto(node),
.fn_proto_multi => tree.fnProtoMulti(node), .fn_proto_multi => tree.fnProtoMulti(node),
.fn_proto_one => tree.fnProtoOne(buf, node), .fn_proto_one => tree.fnProtoOne(buf, node),
.fn_proto_simple => tree.fnProtoSimple(buf, node), .fn_proto_simple => tree.fnProtoSimple(buf, node),
// .fn_decl => tree.fnProto(tree.nodes.items(.data)[node].lhs), .fn_decl => fnProto(tree, tree.nodes.items(.data)[node].lhs, buf),
else => null, else => null,
}; };
} }
@ -1315,10 +1348,21 @@ pub fn getImportStr(tree: ast.Tree, node: ast.Node.Index, source_index: usize) ?
const call_name = tree.tokenSlice(builtin_token); const call_name = tree.tokenSlice(builtin_token);
if (!std.mem.eql(u8, call_name, "@import")) continue; if (!std.mem.eql(u8, call_name, "@import")) continue;
const params = builtinCallParams(tree, decl_idx); 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 (params.len != 1) continue; if (params.len != 1) continue;
const import_str = tree.tokenSlice(tree.firstToken(params[0])); const import_str = tree.tokenSlice(tree.nodes.items(.main_token)[params[0]]);
return import_str[1 .. import_str.len - 1]; return import_str[1 .. import_str.len - 1];
} }
@ -1653,7 +1697,7 @@ fn getDocumentSymbolsInternal(allocator: *std.mem.Allocator, tree: ast.Tree, nod
}; };
const tags = tree.nodes.items(.tag); const tags = tree.nodes.items(.tag);
log.debug("{s} - {s}", .{ name, tags[node] }); // log.debug("{s} - {s}", .{ name, tags[node] });
(try context.symbols.addOne()).* = .{ (try context.symbols.addOne()).* = .{
.name = name, .name = name,
.kind = switch (tags[node]) { .kind = switch (tags[node]) {
@ -2104,7 +2148,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| {
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| {
@ -2120,7 +2164,7 @@ fn lookupSymbolGlobalInternal(
} }
// 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;
} }
@ -2459,10 +2503,7 @@ fn makeScopeInternal(
} }
switch (node) { switch (node) {
.fn_decl => { .fn_proto, .fn_proto_one, .fn_proto_simple, .fn_proto_multi, .fn_decl => |fn_tag| {
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, data[node_idx].rhs);
},
.fn_proto, .fn_proto_one, .fn_proto_simple, .fn_proto_multi => {
var buf: [1]ast.Node.Index = undefined; var buf: [1]ast.Node.Index = undefined;
const func = fnProto(tree, node_idx, &buf).?; const func = fnProto(tree, node_idx, &buf).?;
@ -2485,6 +2526,10 @@ fn makeScopeInternal(
} }
} }
if (fn_tag == .fn_decl) {
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, data[node_idx].rhs);
}
return; return;
}, },
.test_decl => { .test_decl => {
@ -2543,7 +2588,6 @@ fn makeScopeInternal(
for (statements) |idx| { for (statements) |idx| {
try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, idx); try makeScopeInternal(allocator, scopes, error_completions, enum_completions, tree, idx);
// if (tags[
if (varDecl(tree, idx)) |var_decl| { if (varDecl(tree, idx)) |var_decl| {
const name = tree.tokenSlice(var_decl.ast.mut_token + 1); const name = tree.tokenSlice(var_decl.ast.mut_token + 1);
if (try scopes.items[scope_idx].decls.fetchPut(name, .{ .ast_node = idx })) |existing| { if (try scopes.items[scope_idx].decls.fetchPut(name, .{ .ast_node = idx })) |existing| {
@ -2624,7 +2668,7 @@ fn makeScopeInternal(
else => unreachable, else => unreachable,
}; };
if (while_node.label_token) |label| { if (while_node.label_token) |label| {
std.debug.assert(tags[label] == .identifier); std.debug.assert(token_tags[label] == .identifier);
var scope = try scopes.addOne(allocator); var scope = try scopes.addOne(allocator);
scope.* = .{ scope.* = .{
.range = .{ .range = .{

View File

@ -650,7 +650,6 @@ fn getLabelGlobal(pos_index: usize, handle: *DocumentStore.Handle) !?analysis.De
fn getSymbolGlobal(arena: *std.heap.ArenaAllocator, pos_index: usize, handle: *DocumentStore.Handle) !?analysis.DeclWithHandle { fn getSymbolGlobal(arena: *std.heap.ArenaAllocator, pos_index: usize, handle: *DocumentStore.Handle) !?analysis.DeclWithHandle {
const name = identifierFromPosition(pos_index, handle.*); const name = identifierFromPosition(pos_index, handle.*);
logger.debug("Name: {s}", .{name});
if (name.len == 0) return null; if (name.len == 0) return null;
return try analysis.lookupSymbolGlobal(&document_store, arena, handle, name, pos_index); return try analysis.lookupSymbolGlobal(&document_store, arena, handle, name, pos_index);

View File

@ -368,8 +368,20 @@ fn symbolReferencesInternal(
.builtin_call_comma, .builtin_call_comma,
.builtin_call_two, .builtin_call_two,
.builtin_call_two_comma, .builtin_call_two_comma,
=> { => |builtin_tag| {
for (analysis.builtinCallParams(tree, node)) |param| const data = datas[node];
const params = switch (builtin_tag) {
.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,
};
for (params) |param|
try symbolReferencesInternal(arena, store, .{ .node = param, .handle = handle }, decl, encoding, context, handler); try symbolReferencesInternal(arena, store, .{ .node = param, .handle = handle }, decl, encoding, context, handler);
}, },
.@"asm", .asm_simple => |a| { .@"asm", .asm_simple => |a| {