Debugging utilities (#860)
* add debug printing for Ast and DocumentScope * add optional failing allocator
This commit is contained in:
		
							parent
							
								
									f473088b64
								
							
						
					
					
						commit
						94ec3a0a86
					
				
							
								
								
									
										12
									
								
								build.zig
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								build.zig
									
									
									
									
									
								
							@ -50,6 +50,18 @@ pub fn build(b: *std.build.Builder) !void {
 | 
				
			|||||||
        b.option(bool, "enable_tracy_callstack", "Enable callstack graphs.") orelse false,
 | 
					        b.option(bool, "enable_tracy_callstack", "Enable callstack graphs.") orelse false,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    exe_options.addOption(
 | 
				
			||||||
 | 
					        bool,
 | 
				
			||||||
 | 
					        "enable_failing_allocator",
 | 
				
			||||||
 | 
					        b.option(bool, "enable_failing_allocator", "Whether to use a randomly failing allocator.") orelse false,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    exe_options.addOption(
 | 
				
			||||||
 | 
					        u32,
 | 
				
			||||||
 | 
					        "enable_failing_allocator_likelihood",
 | 
				
			||||||
 | 
					        b.option(u32, "enable_failing_allocator_likelihood", "The chance that an allocation will fail is `1/likelihood`") orelse 256,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const version = v: {
 | 
					    const version = v: {
 | 
				
			||||||
        const version_string = b.fmt("{d}.{d}.{d}", .{ zls_version.major, zls_version.minor, zls_version.patch });
 | 
					        const version_string = b.fmt("{d}.{d}.{d}", .{ zls_version.major, zls_version.minor, zls_version.patch });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -2389,30 +2389,6 @@ pub const DocumentScope = struct {
 | 
				
			|||||||
    error_completions: CompletionSet,
 | 
					    error_completions: CompletionSet,
 | 
				
			||||||
    enum_completions: CompletionSet,
 | 
					    enum_completions: CompletionSet,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn debugPrint(self: DocumentScope) void {
 | 
					 | 
				
			||||||
        for (self.scopes.items) |scope| {
 | 
					 | 
				
			||||||
            log.debug(
 | 
					 | 
				
			||||||
                \\--------------------------
 | 
					 | 
				
			||||||
                \\Scope {}, loc: [{d}, {d})
 | 
					 | 
				
			||||||
                \\ {d} usingnamespaces
 | 
					 | 
				
			||||||
                \\Decls:
 | 
					 | 
				
			||||||
            , .{
 | 
					 | 
				
			||||||
                scope.data,
 | 
					 | 
				
			||||||
                scope.loc.start,
 | 
					 | 
				
			||||||
                scope.loc.end,
 | 
					 | 
				
			||||||
                scope.uses.len,
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var decl_it = scope.decls.iterator();
 | 
					 | 
				
			||||||
            var idx: usize = 0;
 | 
					 | 
				
			||||||
            while (decl_it.next()) |_| : (idx += 1) {
 | 
					 | 
				
			||||||
                if (idx != 0) log.debug(", ", .{});
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            // log.debug("{s}", .{name_decl.key});
 | 
					 | 
				
			||||||
            log.debug("\n--------------------------\n", .{});
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn deinit(self: *DocumentScope, allocator: std.mem.Allocator) void {
 | 
					    pub fn deinit(self: *DocumentScope, allocator: std.mem.Allocator) void {
 | 
				
			||||||
        for (self.scopes.items) |*scope| {
 | 
					        for (self.scopes.items) |*scope| {
 | 
				
			||||||
            scope.deinit(allocator);
 | 
					            scope.deinit(allocator);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										136
									
								
								src/debug.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								src/debug.zig
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,136 @@
 | 
				
			|||||||
 | 
					const std = @import("std");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const analysis = @import("analysis.zig");
 | 
				
			||||||
 | 
					const offsets = @import("offsets.zig");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn printTree(tree: std.zig.Ast) void {
 | 
				
			||||||
 | 
					    if (!std.debug.runtime_safety) @compileError("this function should only be used in debug mode!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std.debug.print(
 | 
				
			||||||
 | 
					        \\
 | 
				
			||||||
 | 
					        \\nodes   tag                  lhs rhs token
 | 
				
			||||||
 | 
					        \\-----------------------------------------------
 | 
				
			||||||
 | 
					        \\
 | 
				
			||||||
 | 
					    , .{});
 | 
				
			||||||
 | 
					    var i: usize = 0;
 | 
				
			||||||
 | 
					    while (i < tree.nodes.len) : (i += 1) {
 | 
				
			||||||
 | 
					        std.debug.print("    {d:<3} {s:<20} {d:<3} {d:<3} {d:<3} {s}\n", .{
 | 
				
			||||||
 | 
					            i,
 | 
				
			||||||
 | 
					            @tagName(tree.nodes.items(.tag)[i]),
 | 
				
			||||||
 | 
					            tree.nodes.items(.data)[i].lhs,
 | 
				
			||||||
 | 
					            tree.nodes.items(.data)[i].rhs,
 | 
				
			||||||
 | 
					            tree.nodes.items(.main_token)[i],
 | 
				
			||||||
 | 
					            offsets.tokenToSlice(tree, tree.nodes.items(.main_token)[i]),
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std.debug.print(
 | 
				
			||||||
 | 
					        \\
 | 
				
			||||||
 | 
					        \\tokens  tag                  start
 | 
				
			||||||
 | 
					        \\----------------------------------
 | 
				
			||||||
 | 
					        \\
 | 
				
			||||||
 | 
					    , .{});
 | 
				
			||||||
 | 
					    i = 0;
 | 
				
			||||||
 | 
					    while (i < tree.tokens.len) : (i += 1) {
 | 
				
			||||||
 | 
					        std.debug.print("    {d:<3} {s:<20} {d:<}\n", .{
 | 
				
			||||||
 | 
					            i,
 | 
				
			||||||
 | 
					            @tagName(tree.tokens.items(.tag)[i]),
 | 
				
			||||||
 | 
					            tree.tokens.items(.start)[i],
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn printDocumentScope(doc_scope: analysis.DocumentScope) void {
 | 
				
			||||||
 | 
					    if (!std.debug.runtime_safety) @compileError("this function should only be used in debug mode!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (doc_scope.scopes.items) |scope, i| {
 | 
				
			||||||
 | 
					        if (i != 0) std.debug.print("\n\n", .{});
 | 
				
			||||||
 | 
					        std.debug.print(
 | 
				
			||||||
 | 
					            \\[{d}, {d}] {}
 | 
				
			||||||
 | 
					            \\usingnamespaces: {d}
 | 
				
			||||||
 | 
					            \\Decls:
 | 
				
			||||||
 | 
					            \\
 | 
				
			||||||
 | 
					        , .{
 | 
				
			||||||
 | 
					            scope.loc.start,
 | 
				
			||||||
 | 
					            scope.loc.end,
 | 
				
			||||||
 | 
					            scope.data,
 | 
				
			||||||
 | 
					            scope.uses.items.len,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var decl_it = scope.decls.iterator();
 | 
				
			||||||
 | 
					        var idx: usize = 0;
 | 
				
			||||||
 | 
					        while (decl_it.next()) |entry| : (idx += 1) {
 | 
				
			||||||
 | 
					            std.debug.print("    {s:<8} {}\n", .{ entry.key_ptr.*, entry.value_ptr.* });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub const FailingAllocator = struct {
 | 
				
			||||||
 | 
					    internal_allocator: std.mem.Allocator,
 | 
				
			||||||
 | 
					    random: std.rand.DefaultPrng,
 | 
				
			||||||
 | 
					    likelihood: u32,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// the chance that an allocation will fail is `1/likelihood`
 | 
				
			||||||
 | 
					    /// `likelihood == 0` means that every allocation will fail
 | 
				
			||||||
 | 
					    /// `likelihood == std.math.intMax(u32)` means that no allocation will be forced to fail
 | 
				
			||||||
 | 
					    pub fn init(internal_allocator: std.mem.Allocator, likelihood: u32) FailingAllocator {
 | 
				
			||||||
 | 
					        var seed = std.mem.zeroes([8]u8);
 | 
				
			||||||
 | 
					        std.os.getrandom(&seed) catch {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return FailingAllocator{
 | 
				
			||||||
 | 
					            .internal_allocator = internal_allocator,
 | 
				
			||||||
 | 
					            .random = std.rand.DefaultPrng.init(@bitCast(u64, seed)),
 | 
				
			||||||
 | 
					            .likelihood = likelihood,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn allocator(self: *FailingAllocator) std.mem.Allocator {
 | 
				
			||||||
 | 
					        return .{
 | 
				
			||||||
 | 
					            .ptr = self,
 | 
				
			||||||
 | 
					            .vtable = &.{
 | 
				
			||||||
 | 
					                .alloc = alloc,
 | 
				
			||||||
 | 
					                .resize = resize,
 | 
				
			||||||
 | 
					                .free = free,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn alloc(
 | 
				
			||||||
 | 
					        ctx: *anyopaque,
 | 
				
			||||||
 | 
					        len: usize,
 | 
				
			||||||
 | 
					        log2_ptr_align: u8,
 | 
				
			||||||
 | 
					        return_address: usize,
 | 
				
			||||||
 | 
					    ) ?[*]u8 {
 | 
				
			||||||
 | 
					        const self = @ptrCast(*FailingAllocator, @alignCast(@alignOf(FailingAllocator), ctx));
 | 
				
			||||||
 | 
					        if (shouldFail(self)) return null;
 | 
				
			||||||
 | 
					        return self.internal_allocator.rawAlloc(len, log2_ptr_align, return_address);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn resize(
 | 
				
			||||||
 | 
					        ctx: *anyopaque,
 | 
				
			||||||
 | 
					        old_mem: []u8,
 | 
				
			||||||
 | 
					        log2_old_align: u8,
 | 
				
			||||||
 | 
					        new_len: usize,
 | 
				
			||||||
 | 
					        ra: usize,
 | 
				
			||||||
 | 
					    ) bool {
 | 
				
			||||||
 | 
					        const self = @ptrCast(*FailingAllocator, @alignCast(@alignOf(FailingAllocator), ctx));
 | 
				
			||||||
 | 
					        if (!self.internal_allocator.rawResize(old_mem, log2_old_align, new_len, ra))
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn free(
 | 
				
			||||||
 | 
					        ctx: *anyopaque,
 | 
				
			||||||
 | 
					        old_mem: []u8,
 | 
				
			||||||
 | 
					        log2_old_align: u8,
 | 
				
			||||||
 | 
					        ra: usize,
 | 
				
			||||||
 | 
					    ) void {
 | 
				
			||||||
 | 
					        const self = @ptrCast(*FailingAllocator, @alignCast(@alignOf(FailingAllocator), ctx));
 | 
				
			||||||
 | 
					        self.internal_allocator.rawFree(old_mem, log2_old_align, ra);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn shouldFail(self: *FailingAllocator) bool {
 | 
				
			||||||
 | 
					        if (self.likelihood == std.math.maxInt(u32)) return false;
 | 
				
			||||||
 | 
					        return 0 == self.random.random().intRangeAtMostBiased(u32, 0, self.likelihood);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -8,6 +8,7 @@ const configuration = @import("configuration.zig");
 | 
				
			|||||||
const Server = @import("Server.zig");
 | 
					const Server = @import("Server.zig");
 | 
				
			||||||
const setup = @import("setup.zig");
 | 
					const setup = @import("setup.zig");
 | 
				
			||||||
const Header = @import("Header.zig");
 | 
					const Header = @import("Header.zig");
 | 
				
			||||||
 | 
					const debug = @import("debug.zig");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const logger = std.log.scoped(.main);
 | 
					const logger = std.log.scoped(.main);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -263,9 +264,12 @@ const stack_frames = switch (zig_builtin.mode) {
 | 
				
			|||||||
pub fn main() !void {
 | 
					pub fn main() !void {
 | 
				
			||||||
    var gpa_state = std.heap.GeneralPurposeAllocator(.{ .stack_trace_frames = stack_frames }){};
 | 
					    var gpa_state = std.heap.GeneralPurposeAllocator(.{ .stack_trace_frames = stack_frames }){};
 | 
				
			||||||
    defer _ = gpa_state.deinit();
 | 
					    defer _ = gpa_state.deinit();
 | 
				
			||||||
    var tracy_state = if (tracy.enable_allocation) tracy.tracyAllocator(gpa_state.allocator()) else void{};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const allocator: std.mem.Allocator = if (tracy.enable_allocation) tracy_state.allocator() else gpa_state.allocator();
 | 
					    var tracy_state = if (tracy.enable_allocation) tracy.tracyAllocator(gpa_state.allocator()) else void{};
 | 
				
			||||||
 | 
					    const inner_allocator: std.mem.Allocator = if (tracy.enable_allocation) tracy_state.allocator() else gpa_state.allocator();
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    var failing_allocator_state = if(build_options.enable_failing_allocator) debug.FailingAllocator.init(inner_allocator, build_options.enable_failing_allocator_likelihood) else void{};
 | 
				
			||||||
 | 
					    const allocator: std.mem.Allocator = if(build_options.enable_failing_allocator) failing_allocator_state.allocator() else inner_allocator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var config = ConfigWithPath{
 | 
					    var config = ConfigWithPath{
 | 
				
			||||||
        .config = undefined,
 | 
					        .config = undefined,
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub const analysis = @import("analysis.zig");
 | 
					pub const analysis = @import("analysis.zig");
 | 
				
			||||||
pub const Header = @import("Header.zig");
 | 
					pub const Header = @import("Header.zig");
 | 
				
			||||||
 | 
					pub const debug = @import("debug.zig");
 | 
				
			||||||
pub const offsets = @import("offsets.zig");
 | 
					pub const offsets = @import("offsets.zig");
 | 
				
			||||||
pub const Config = @import("Config.zig");
 | 
					pub const Config = @import("Config.zig");
 | 
				
			||||||
pub const Server = @import("Server.zig");
 | 
					pub const Server = @import("Server.zig");
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user