fix: "f..o.o;" crashes the server (#629)

this is a fix for #381 and a hack for #409
(related, get triggered by "f..o.o;")
This commit is contained in:
nullptrdevs 2022-09-07 10:14:11 -07:00 committed by GitHub
parent aa81d83136
commit 6269eef776
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 30 additions and 6 deletions

View File

@ -808,8 +808,8 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, arena: *std.heap.ArenaAl
}, },
.field_access => { .field_access => {
if (datas[node].rhs == 0) return null; if (datas[node].rhs == 0) return null;
if (node >= tree.nodes.len - 1) return null; // #boundsCheck const rhs_str = ast.tokenSlice(tree, datas[node].rhs) catch return null;
const rhs_str = tree.tokenSlice(datas[node].rhs);
// 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,
@ -1342,7 +1342,7 @@ pub fn nodeToString(tree: Ast, node: Ast.Node.Index) ?[]const u8 {
.fn_decl, .fn_decl,
=> if (ast.fnProto(tree, node, &buf).?.name_token) |name| => if (ast.fnProto(tree, node, &buf).?.name_token) |name|
return tree.tokenSlice(name), return tree.tokenSlice(name),
.field_access => return tree.tokenSlice(data[node].rhs), .field_access => return ast.tokenSlice(tree, data[node].rhs) catch return null,
.call, .call,
.call_comma, .call_comma,
.async_call, .async_call,

View File

@ -1215,3 +1215,26 @@ pub fn nextFnParam(it: *Ast.full.FnProto.Iterator) ?Ast.full.FnProto.Param {
it.tok_flag = false; it.tok_flag = false;
} }
} }
/// A modified version of tree.tokenSlice that returns an error.UnexpectedToken if the tokenizer encounters an unexpected token
// https://github.com/zigtools/zls/issues/381
pub fn tokenSlice(tree: Ast, token_index: Ast.TokenIndex) ![]const u8 {
const token_starts = tree.tokens.items(.start);
const token_tags = tree.tokens.items(.tag);
const token_tag = token_tags[token_index];
// Many tokens can be determined entirely by their tag.
if (token_tag.lexeme()) |lexeme| {
return lexeme;
}
// For some tokens, re-tokenization is needed to find the end.
var tokenizer: std.zig.Tokenizer = .{
.buffer = tree.source,
.index = token_starts[token_index],
.pending_invalid_token = null,
};
const token = tokenizer.next();
if (token.tag != token_tag) return error.UnexpectedToken; // assert(token.tag == token_tag);
return tree.source[token.loc.start..token.loc.end];
}

View File

@ -182,7 +182,8 @@ pub fn tokenLocation(tree: Ast, token_index: Ast.TokenIndex) Loc {
}; };
const token = tokenizer.next(); const token = tokenizer.next();
std.debug.assert(token.tag == tag); // HACK, should return error.UnextectedToken
if (token.tag != tag) return .{ .start = 0, .end = 0 }; //std.debug.assert(token.tag == tag);
return .{ .start = token.loc.start, .end = token.loc.end }; return .{ .start = token.loc.start, .end = token.loc.end };
} }

View File

@ -382,7 +382,7 @@ fn symbolReferencesInternal(arena: *std.heap.ArenaAllocator, store: *DocumentSto
.field_access => { .field_access => {
try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler); try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler);
const rhs_str = tree.tokenSlice(datas[node].rhs); const rhs_str = ast.tokenSlice(tree, datas[node].rhs) catch return;
var bound_type_params = analysis.BoundTypeParams{}; var bound_type_params = analysis.BoundTypeParams{};
const left_type = try analysis.resolveFieldAccessLhsType( const left_type = try analysis.resolveFieldAccessLhsType(
store, store,

View File

@ -854,7 +854,7 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D
.field_access => { .field_access => {
const data = node_data[node]; const data = node_data[node];
if (data.rhs == 0) return; if (data.rhs == 0) return;
const rhs_str = tree.tokenSlice(data.rhs); const rhs_str = ast.tokenSlice(tree, data.rhs) catch return;
try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, data.lhs }); try await @asyncCall(child_frame, {}, writeNodeTokens, .{ builder, arena, store, data.lhs });