Skip to content

Commit 1323f03

Browse files
FnControlOptionKoltPenny
authored andcommitted
Add hover/goto for container fields in struct init (zigtools#1307)
1 parent 166397d commit 1323f03

2 files changed

Lines changed: 87 additions & 32 deletions

File tree

src/Server.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ pub fn getSymbolEnumLiteral(
321321
defer tracy_zone.end();
322322

323323
const nodes = try ast.nodesOverlappingIndex(server.arena.allocator(), handle.tree, source_index);
324-
return try server.analyser.lookupSymbolEnumLiteral(handle, nodes);
324+
return try server.analyser.lookupSymbolEnumLiteral(handle, source_index, nodes);
325325
}
326326

327327
/// Multiple when using branched types

src/analysis.zig

Lines changed: 86 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2671,33 +2671,82 @@ pub fn lookupSymbolContainer(
26712671
pub fn lookupSymbolEnumLiteral(
26722672
analyser: *Analyser,
26732673
handle: *const DocumentStore.Handle,
2674+
source_index: usize,
26742675
nodes: []Ast.Node.Index,
26752676
) error{OutOfMemory}!?DeclWithHandle {
26762677
if (nodes.len == 0) return null;
26772678

26782679
const tree = handle.tree;
26792680
const node_tags = tree.nodes.items(.tag);
2680-
if (node_tags[nodes[0]] != .enum_literal) return null;
2681+
const main_tokens = tree.nodes.items(.main_token);
2682+
2683+
var struct_init_buf: [2]Ast.Node.Index = undefined;
2684+
if (tree.fullStructInit(&struct_init_buf, nodes[0])) |struct_init| {
2685+
for (struct_init.ast.fields) |field_init| {
2686+
const field_token = handle.tree.firstToken(field_init) - 2;
2687+
const field_loc = offsets.tokenToLoc(handle.tree, field_token);
2688+
if (field_loc.start <= source_index and source_index <= field_loc.end) {
2689+
const field_name = tree.tokenSlice(field_token);
2690+
return analyser.lookupSymbolFieldInit(handle, field_name, nodes);
2691+
}
2692+
}
2693+
} else if (node_tags[nodes[0]] == .enum_literal) {
2694+
const field_name = tree.tokenSlice(main_tokens[nodes[0]]);
2695+
return analyser.lookupSymbolFieldInit(handle, field_name, nodes);
2696+
}
2697+
2698+
return null;
2699+
}
26812700

2682-
const container_type = (try analyser.resolveEnumLiteralType(
2701+
pub fn lookupSymbolFieldInit(
2702+
analyser: *Analyser,
2703+
handle: *const DocumentStore.Handle,
2704+
field_name: []const u8,
2705+
nodes: []Ast.Node.Index,
2706+
) error{OutOfMemory}!?DeclWithHandle {
2707+
if (nodes.len == 0) return null;
2708+
2709+
var container_type = (try analyser.resolveExpressionType(
26832710
handle,
26842711
nodes[0],
26852712
nodes[1..],
26862713
)) orelse return null;
26872714

2715+
if (try analyser.resolveUnwrapErrorUnionType(container_type, .right)) |unwrapped|
2716+
container_type = unwrapped;
2717+
2718+
if (try analyser.resolveUnwrapOptionalType(container_type)) |unwrapped|
2719+
container_type = unwrapped;
2720+
26882721
const container_node = switch (container_type.type.data) {
26892722
.other => |n| n,
26902723
else => return null,
26912724
};
26922725

26932726
return analyser.lookupSymbolContainer(
26942727
.{ .node = container_node, .handle = container_type.handle },
2695-
tree.tokenSlice(tree.nodes.items(.main_token)[nodes[0]]),
2728+
field_name,
26962729
!container_type.isEnumType(),
26972730
);
26982731
}
26992732

2700-
pub fn resolveEnumLiteralType(
2733+
pub fn resolveExpressionType(
2734+
analyser: *Analyser,
2735+
handle: *const DocumentStore.Handle,
2736+
node: Ast.Node.Index,
2737+
ancestors: []Ast.Node.Index,
2738+
) error{OutOfMemory}!?TypeWithHandle {
2739+
return (try analyser.resolveExpressionTypeFromAncestors(
2740+
handle,
2741+
node,
2742+
ancestors,
2743+
)) orelse (try analyser.resolveTypeOfNode(.{
2744+
.node = node,
2745+
.handle = handle,
2746+
}));
2747+
}
2748+
2749+
pub fn resolveExpressionTypeFromAncestors(
27012750
analyser: *Analyser,
27022751
handle: *const DocumentStore.Handle,
27032752
node: Ast.Node.Index,
@@ -2711,8 +2760,16 @@ pub fn resolveEnumLiteralType(
27112760
const token_tags: []std.zig.Token.Tag = tree.tokens.items(.tag);
27122761

27132762
var call_buf: [1]Ast.Node.Index = undefined;
2763+
var struct_init_buf: [2]Ast.Node.Index = undefined;
27142764

2715-
if (tree.fullVarDecl(ancestors[0])) |var_decl| {
2765+
if (tree.fullStructInit(&struct_init_buf, ancestors[0])) |struct_init| {
2766+
if (std.mem.indexOfScalar(Ast.Node.Index, struct_init.ast.fields, node) != null) {
2767+
const field_name = tree.tokenSlice(tree.firstToken(node) - 2);
2768+
if (try analyser.lookupSymbolFieldInit(handle, field_name, ancestors)) |field_decl| {
2769+
return try field_decl.resolveType(analyser);
2770+
}
2771+
}
2772+
} else if (tree.fullVarDecl(ancestors[0])) |var_decl| {
27162773
if (node == var_decl.ast.init_node) {
27172774
return try analyser.resolveTypeOfNode(.{
27182775
.node = ancestors[0],
@@ -2721,36 +2778,27 @@ pub fn resolveEnumLiteralType(
27212778
}
27222779
} else if (tree.fullIf(ancestors[0])) |if_node| {
27232780
if (node == if_node.ast.then_expr or node == if_node.ast.else_expr) {
2724-
return (try analyser.resolveTypeOfNode(.{
2725-
.node = ancestors[0],
2726-
.handle = handle,
2727-
})) orelse (try analyser.resolveEnumLiteralType(
2781+
return try analyser.resolveExpressionType(
27282782
handle,
27292783
ancestors[0],
27302784
ancestors[1..],
2731-
));
2785+
);
27322786
}
27332787
} else if (tree.fullFor(ancestors[0])) |for_node| {
27342788
if (node == for_node.ast.else_expr) {
2735-
return (try analyser.resolveTypeOfNode(.{
2736-
.node = ancestors[0],
2737-
.handle = handle,
2738-
})) orelse (try analyser.resolveEnumLiteralType(
2789+
return try analyser.resolveExpressionType(
27392790
handle,
27402791
ancestors[0],
27412792
ancestors[1..],
2742-
));
2793+
);
27432794
}
27442795
} else if (tree.fullWhile(ancestors[0])) |while_node| {
27452796
if (node == while_node.ast.else_expr) {
2746-
return (try analyser.resolveTypeOfNode(.{
2747-
.node = ancestors[0],
2748-
.handle = handle,
2749-
})) orelse (try analyser.resolveEnumLiteralType(
2797+
return try analyser.resolveExpressionType(
27502798
handle,
27512799
ancestors[0],
27522800
ancestors[1..],
2753-
));
2801+
);
27542802
}
27552803
} else if (tree.fullSwitchCase(ancestors[0])) |switch_case| {
27562804
if (ancestors.len == 1) return null;
@@ -2761,14 +2809,11 @@ pub fn resolveEnumLiteralType(
27612809
}
27622810

27632811
if (node == switch_case.ast.target_expr) {
2764-
return (try analyser.resolveTypeOfNode(.{
2765-
.node = ancestors[1],
2766-
.handle = handle,
2767-
})) orelse (try analyser.resolveEnumLiteralType(
2812+
return try analyser.resolveExpressionType(
27682813
handle,
27692814
ancestors[1],
27702815
ancestors[2..],
2771-
));
2816+
);
27722817
}
27732818

27742819
for (switch_case.ast.values) |value| {
@@ -2833,6 +2878,19 @@ pub fn resolveEnumLiteralType(
28332878
}));
28342879
},
28352880

2881+
.@"return" => {
2882+
if (node != datas[ancestors[0]].lhs) return null;
2883+
2884+
var func_buf: [1]Ast.Node.Index = undefined;
2885+
for (1..ancestors.len) |index| {
2886+
const func = tree.fullFnProto(&func_buf, ancestors[index]) orelse continue;
2887+
return try analyser.resolveTypeOfNode(.{
2888+
.node = func.ast.return_type,
2889+
.handle = handle,
2890+
});
2891+
}
2892+
},
2893+
28362894
.@"break" => {
28372895
if (node != datas[ancestors[0]].rhs) return null;
28382896

@@ -2869,17 +2927,14 @@ pub fn resolveEnumLiteralType(
28692927
}
28702928
} else return null;
28712929

2872-
return (try analyser.resolveTypeOfNode(.{
2873-
.node = ancestors[index],
2874-
.handle = handle,
2875-
})) orelse (try analyser.resolveEnumLiteralType(
2930+
return try analyser.resolveExpressionType(
28762931
handle,
28772932
ancestors[index],
28782933
ancestors[index + 1 ..],
2879-
));
2934+
);
28802935
},
28812936

2882-
else => {}, // TODO: Implement more expressions that may contain enum literals; better safe than sorry
2937+
else => {}, // TODO: Implement more expressions; better safe than sorry
28832938
}
28842939

28852940
return null;

0 commit comments

Comments
 (0)