Autodoc: only group structs under "namespaces"

The old heuristic of checking only for the number of fields has the
downside of classifying all opaque types, such as `std.c.FILE`, as
"namespaces" rather than "types".
This commit is contained in:
Ian Johnson 2024-07-07 22:12:37 -04:00 committed by Andrew Kelley
parent 854e86c567
commit 2511830442
4 changed files with 53 additions and 47 deletions

View file

@ -1,14 +1,15 @@
(function() {
const CAT_namespace = 0;
const CAT_global_variable = 1;
const CAT_function = 2;
const CAT_primitive = 3;
const CAT_error_set = 4;
const CAT_global_const = 5;
const CAT_alias = 6;
const CAT_type = 7;
const CAT_type_type = 8;
const CAT_type_function = 9;
const CAT_container = 1;
const CAT_global_variable = 2;
const CAT_function = 3;
const CAT_primitive = 4;
const CAT_error_set = 5;
const CAT_global_const = 6;
const CAT_alias = 7;
const CAT_type = 8;
const CAT_type_type = 9;
const CAT_type_function = 10;
const domDocTestsCode = document.getElementById("docTestsCode");
const domFnErrorsAnyError = document.getElementById("fnErrorsAnyError");
@ -184,6 +185,7 @@
const category = wasm_exports.categorize_decl(decl_index, 0);
switch (category) {
case CAT_namespace:
case CAT_container:
return renderNamespacePage(decl_index);
case CAT_global_variable:
case CAT_primitive:
@ -426,16 +428,12 @@
while (true) {
const member_category = wasm_exports.categorize_decl(member, 0);
switch (member_category) {
case CAT_namespace:
if (wasm_exports.decl_field_count(member) > 0) {
typesList.push({original: original, member: member});
} else {
namespacesList.push({original: original, member: member});
}
continue member_loop;
case CAT_namespace:
namespacesList.push({original: original, member: member});
continue member_loop;
case CAT_container:
typesList.push({original: original, member: member});
continue member_loop;
case CAT_global_variable:
varsList.push(member);
continue member_loop;

View file

@ -115,7 +115,7 @@ pub fn categorize(decl: *const Decl) Walk.Category {
pub fn get_child(decl: *const Decl, name: []const u8) ?Decl.Index {
switch (decl.categorize()) {
.alias => |aliasee| return aliasee.get().get_child(name),
.namespace => |node| {
.namespace, .container => |node| {
const file = decl.file.get();
const scope = file.scopes.get(node) orelse return null;
const child_node = scope.get_child(name) orelse return null;
@ -128,7 +128,7 @@ pub fn get_child(decl: *const Decl, name: []const u8) ?Decl.Index {
/// Looks up a decl by name accessible in `decl`'s namespace.
pub fn lookup(decl: *const Decl, name: []const u8) ?Decl.Index {
const namespace_node = switch (decl.categorize()) {
.namespace => |node| node,
.namespace, .container => |node| node,
else => decl.parent.get().ast_node,
};
const file = decl.file.get();

View file

@ -7,7 +7,10 @@ file: File.Index,
/// keep in sync with "CAT_" constants in main.js
pub const Category = union(enum(u8)) {
/// A struct type used only to group declarations.
namespace: Ast.Node.Index,
/// A container type (struct, union, enum, opaque).
container: Ast.Node.Index,
global_variable: Ast.Node.Index,
/// A function that has not been detected as returning a type.
function: Ast.Node.Index,
@ -45,13 +48,6 @@ pub const File = struct {
return file.node_decls.get(decl_node) orelse return .none;
}
pub fn field_count(file: *const File, node: Ast.Node.Index) u32 {
const scope = file.scopes.get(node) orelse return 0;
if (scope.tag != .namespace) return 0;
const namespace: *Scope.Namespace = @alignCast(@fieldParentPtr("base", scope));
return namespace.field_count;
}
pub const Index = enum(u32) {
_,
@ -87,7 +83,18 @@ pub const File = struct {
const node_tags = ast.nodes.items(.tag);
const token_tags = ast.tokens.items(.tag);
switch (node_tags[node]) {
.root => return .{ .namespace = node },
.root => {
for (ast.rootDecls()) |member| {
switch (node_tags[member]) {
.container_field_init,
.container_field_align,
.container_field,
=> return .{ .container = node },
else => {},
}
}
return .{ .namespace = node };
},
.global_var_decl,
.local_var_decl,
@ -122,7 +129,7 @@ pub const File = struct {
full: Ast.full.FnProto,
) Category {
return switch (categorize_expr(file_index, full.ast.return_type)) {
.namespace, .error_set, .type_type => .{ .type_function = node },
.namespace, .container, .error_set, .type_type => .{ .type_function = node },
else => .{ .function = node },
};
}
@ -140,6 +147,7 @@ pub const File = struct {
const node_tags = ast.nodes.items(.tag);
const node_datas = ast.nodes.items(.data);
const main_tokens = ast.nodes.items(.main_token);
const token_tags = ast.tokens.items(.tag);
//log.debug("categorize_expr tag {s}", .{@tagName(node_tags[node])});
return switch (node_tags[node]) {
.container_decl,
@ -154,7 +162,23 @@ pub const File = struct {
.tagged_union_enum_tag_trailing,
.tagged_union_two,
.tagged_union_two_trailing,
=> .{ .namespace = node },
=> {
var buf: [2]Ast.Node.Index = undefined;
const container_decl = ast.fullContainerDecl(&buf, node).?;
if (token_tags[container_decl.ast.main_token] != .keyword_struct) {
return .{ .container = node };
}
for (container_decl.ast.members) |member| {
switch (node_tags[member]) {
.container_field_init,
.container_field_align,
.container_field,
=> return .{ .container = node },
else => {},
}
}
return .{ .namespace = node };
},
.error_set_decl,
.merge_error_sets,
@ -240,6 +264,7 @@ pub const File = struct {
return .{ .error_set = node };
} else if (then_cat == .type or else_cat == .type or
then_cat == .namespace or else_cat == .namespace or
then_cat == .container or else_cat == .container or
then_cat == .error_set or else_cat == .error_set or
then_cat == .type_function or else_cat == .type_function)
{
@ -346,7 +371,7 @@ pub const File = struct {
any_type = true;
all_type_type = false;
},
.type, .namespace, .type_function => {
.type, .namespace, .container, .type_function => {
any_type = true;
all_error_set = false;
all_type_type = false;
@ -431,7 +456,6 @@ pub const Scope = struct {
names: std.StringArrayHashMapUnmanaged(Ast.Node.Index) = .{},
doctests: std.StringArrayHashMapUnmanaged(Ast.Node.Index) = .{},
decl_index: Decl.Index,
field_count: u32,
};
fn getNamespaceDecl(start_scope: *Scope) Decl.Index {
@ -500,7 +524,6 @@ fn struct_decl(
namespace.* = .{
.parent = scope,
.decl_index = parent_decl,
.field_count = 0,
};
try w.file.get().scopes.putNoClobber(gpa, node, &namespace.base);
try w.scanDecls(namespace, container_decl.ast.members);
@ -1061,14 +1084,6 @@ fn scanDecls(w: *Walk, namespace: *Scope.Namespace, members: []const Ast.Node.In
continue;
},
.container_field_init,
.container_field_align,
.container_field,
=> {
namespace.field_count += 1;
continue;
},
else => continue,
};

View file

@ -274,13 +274,6 @@ export fn fn_error_set_decl(decl_index: Decl.Index, node: Ast.Node.Index) Decl.I
};
}
export fn decl_field_count(decl_index: Decl.Index) u32 {
switch (decl_index.get().categorize()) {
.namespace => |node| return decl_index.get().file.get().field_count(node),
else => return 0,
}
}
fn decl_error_set_fallible(decl_index: Decl.Index) Oom![]ErrorIdentifier {
error_set_result.clearRetainingCapacity();
try addErrorsFromDecl(decl_index, &error_set_result);
@ -583,7 +576,7 @@ export fn decl_category_name(decl_index: Decl.Index) String {
const ast = decl.file.get_ast();
const token_tags = ast.tokens.items(.tag);
const name = switch (decl.categorize()) {
.namespace => |node| {
.namespace, .container => |node| {
const node_tags = ast.nodes.items(.tag);
if (node_tags[decl.ast_node] == .root)
return String.init("struct");