Merge pull request #15478 from der-teufel-programming/autodoc-decltests

autodoc: Gather and display decltests
This commit is contained in:
Loris Cro 2023-04-29 18:23:18 +02:00 committed by GitHub
commit 13aaa16ab2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 93 additions and 5 deletions

View File

@ -563,12 +563,14 @@ const NAV_MODES = {
let currentType = getType(mod.main);
curNav.declObjs = [currentType];
let lastDecl = mod.main;
for (let i = 0; i < curNav.declNames.length; i += 1) {
let childDecl = findSubDecl(currentType, curNav.declNames[i]);
window.last_decl = childDecl;
if (childDecl == null) {
return render404();
}
lastDecl = childDecl;
let childDeclValue = resolveValue(childDecl.value).expr;
if ("type" in childDeclValue) {
@ -593,9 +595,7 @@ const NAV_MODES = {
let lastIsType = isType(last);
let lastIsContainerType = isContainerType(last);
if (lastIsDecl) {
renderDocTest(last);
}
renderDocTest(lastDecl);
if (lastIsContainerType) {
return renderContainer(last);
@ -642,7 +642,25 @@ const NAV_MODES = {
if (!decl.decltest) return;
const astNode = getAstNode(decl.decltest);
domSectDocTests.classList.remove("hidden");
domDocTestsCode.innerHTML = astNode.code;
domDocTestsCode.innerHTML = renderZigSource(astNode.code);
}
function renderZigSource(code) {
let lines = code.split("\n");
let result = "";
let indent_level = 0;
for(let i = 0; i < lines.length; i += 1) {
let line = lines[i].trim();
if(line[0] == "}") indent_level -= 1;
for(let j = 0; j < indent_level; j += 1) {
result += " ";
}
if (line.startsWith("\\\\")) result += " "
result += line;
result += "\n";
if(line[line.length - 1] == "{") indent_level += 1;
}
return result;
}
function renderUnknownDecl(decl) {

View File

@ -3104,7 +3104,9 @@ fn analyzeAllDecls(
while (it.next()) |d| {
const decl_name_index = file.zir.extra[d.sub_index + 5];
switch (decl_name_index) {
0, 1, 2 => continue, // skip over usingnamespace decls
0, 1 => continue, // skip over usingnamespace decls
2 => continue, // skip decltests
else => if (file.zir.string_bytes[decl_name_index] == 0) {
continue;
},
@ -3120,6 +3122,24 @@ fn analyzeAllDecls(
);
}
// Fourth loop to analyze decltests
it = original_it;
while (it.next()) |d| {
const decl_name_index = file.zir.extra[d.sub_index + 5];
switch (decl_name_index) {
0, 1 => continue, // skip over usingnamespace decls
2 => {},
else => continue, // skip tests and normal decls
}
try self.analyzeDecltest(
file,
scope,
parent_src,
d,
);
}
return it.extra_index;
}
@ -3327,6 +3347,56 @@ fn analyzeUsingnamespaceDecl(
}
}
fn analyzeDecltest(
self: *Autodoc,
file: *File,
scope: *Scope,
parent_src: SrcLocInfo,
d: Zir.DeclIterator.Item,
) AutodocErrors!void {
const data = file.zir.instructions.items(.data);
const value_index = file.zir.extra[d.sub_index + 6];
const decl_name_index = file.zir.extra[d.sub_index + 7];
// This is known to work because decl values are always block_inlines
const value_pl_node = data[value_index].pl_node;
const decl_src = try self.srcLocInfo(file, value_pl_node.src_node, parent_src);
const func_index = getBlockInlineBreak(file.zir, value_index).?;
const pl_node = data[Zir.refToIndex(func_index).?].pl_node;
const fn_src = try self.srcLocInfo(file, pl_node.src_node, decl_src);
const tree = try file.getTree(self.comp_module.gpa);
const test_source_code = tree.getNodeSource(fn_src.src_node);
const decl_name: ?[]const u8 = if (decl_name_index != 0)
file.zir.nullTerminatedString(decl_name_index)
else
null;
// astnode
const ast_node_index = idx: {
const idx = self.ast_nodes.items.len;
try self.ast_nodes.append(self.arena, .{
.file = self.files.getIndex(file).?,
.line = decl_src.line,
.col = 0,
.name = decl_name,
.code = test_source_code,
});
break :idx idx;
};
const decl_status = scope.resolveDeclName(decl_name_index, file, 0);
switch (decl_status.*) {
.Analyzed => |idx| {
self.decls.items[idx].decltest = ast_node_index;
},
else => unreachable, // we assume analyzeAllDecls analyzed other decls by this point
}
}
/// An unresolved path has a non-string WalkResult at its beginnig, while every
/// other element is a string WalkResult. Resolving means iteratively map each
/// string to a Decl / Type / Call / etc.