Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code Actions & Autofix #689

Open
6 of 24 tasks
Techatrix opened this issue Sep 29, 2022 · 4 comments
Open
6 of 24 tasks

Code Actions & Autofix #689

Techatrix opened this issue Sep 29, 2022 · 4 comments
Labels
enhancement New feature or request help wanted Extra attention is needed ux User experience improvement

Comments

@Techatrix
Copy link
Member

Techatrix commented Sep 29, 2022

This issue contains a collection of possible code actions that can be integrated into zls.
Some of them may not be easily implementable without #551 or #552.
Feel free to make suggestions if you have some ideas.

Unused Parameter

fn foo(parameter: u32) void {}
  • remove parameter
fn foo() void {}
  • discard parameter (part of autofix)
fn foo(parameter: u32) void {
    _ = parameter;
}

Unused Variable/Constant

fn foo() void {
    var variable = 0;
    const constant = 0;
}
  • remove variable/constant
fn foo() void {}
  • discard variable/constant (part of autofix)
fn foo() void {
    var variable = 0;
    _ = variable;
    const constant = 0;
    _ = constant;
}

Capture

for("") |unused_capture, unused_index_capture| {}
switch(tagged_union) {
    .tag1 => |capture| expression,
    .tag2 => |capture| {},
}
  • remove capture
for ("") |_| {}
switch (tagged_union) {
    .tag1 => expression,
    .tag2 => {},
}
for ("") |unused_capture, unused_index_capture| {
    _ = unused_capture;
    _ = unused_index_capture;
}
switch (tagged_union) {
    .tag1 => |capture| blk: {
        _ = capture;
        break :blk expression;
    },
    .tag2 => |capture| {
        _ = capture;
    },
}

Unreachable code

fn foo() u32 {
    return 0;
    return 1;
}
  • remove unreachable code
fn foo() u32 {
    return 0;
}
  • comment out unreachable code
    This can be part of autofix if this step is also reversible.
fn foo() u32 {
    return 0;
    // return 1;
}

Formatting

Sort Imports

const beta = @import("beta");
const zeta = @import("zeta.zig");
const delta = @import("delta.zig");
const gamma = @import("gamma");
const builtin = @import("builtin");
const alpha = @import("alpha");
const epsilon = @import("epsilon.zig");
const std = @import("std");
const std = @import("std");
const builtin = @import("builtin");

const alpha = @import("alpha");
const beta = @import("beta");
const gamma = @import("gamma");

const delta = @import("delta.zig");
const epsilon = @import("epsilon.zig");
const zeta = @import("zeta.zig");

A ./ is not needed in imports

const file = @import("./file.zig");
  • remove unnecessery ./
const file = @import("file.zig");

Functions should be camelCase

fn foo_bar_baz() void {}
fn fooBarBaz() void {}

Type functions should be PascalCase

fn foo_bar_baz(comptime T: type) type { return T; }
  • make function name PascalCase
fn FooBarBaz(comptime T: type) type { return T; }

Refactor

Extract Variable/Constant

fn f() MyStruct {
    const bar: u32 = 3;
    const my_struct = MyStruct{
        .alpha = "hello alpha",
        .beta = undefined,
        .gamma = Foo{ .bar = bar, .baz = "buzz" },
    };
    return my_struct;
}
  • extract Foo into variable/constant
fn f() MyStruct {
    const bar: u32 = 3;
    const foo = Foo{ .bar = bar, .baz = "buzz" };
    const my_struct = MyStruct{
        .alpha = "hello alpha",
        .beta = undefined,
        .gamma = foo,
    };
    return my_struct;
}
  • extract Foo into a function
fn foo(bar: u32) Foo {
    return Foo{ .bar = bar, .baz = "buzz" };
}

fn f() MyStruct {
    const bar: u32 = 3;
    const my_struct = MyStruct{
        .alpha = "hello alpha",
        .beta = undefined,
        .gamma = foo(bar),
    };
    return my_struct;
}

Extract type specififer

fn foo(alpha: *[4]const u8) void {}
  • refactor alpha's type specifier into a constant
const Type = *[4]const u8;
fn foo(alpha: Type) void {}

Sema

Create init/deinit function

const Foo = struct {
    name: []const u8 = "foo",
    count: u32,
    integers: std.ArrayList(u32),
    strings: std.ArrayListUnmanaged([]const u8),
};
  • create init function
const Foo = struct {
    name: []const u8 = "foo",
    count: u32,
    integers: std.ArrayList(u32),
    strings: std.ArrayListUnmanaged([]const u8),

    pub fn init(
        count: u32,
        integers: std.ArrayListUnmanaged(u32),
        strings: std.ArrayListUnmanaged([]const u8),
    ) Foo {
        return Foo{
            .count = count,
            .integers = integers,
            .strings = strings,
        };
    }
};
  • create deinit function
const Foo = struct {
    name: []const u8 = "foo",
    count: u32,
    integers: std.ArrayList(u32),
    strings: std.ArrayListUnmanaged([]const u8),

    pub fn deinit(self: *@This(), allocator: std.mem.Allocator) void {
        defer self.integers.deinit();
        defer self.strings.deinit(allocator);
    }
};

Explicitly specify error union

fn foo() !void {
    // some code that returns various errors
}
  • explicitly specify error union (inline)
fn foo() error{OutOfMemory, FileTooBig, AccessDenied}!void {}
  • explicitly specify error union (extern)
const Error = error{OutOfMemory, FileTooBig, AccessDenied}
fn foo() Error!void {}
  • explicitly specify error union (inline, structured)
fn foo() (error.OutOfMemory | std.io.WriteError)!void {}
  • explicitly specify error union (extern, structured)
const Error = error.OutOfMemory | std.io.WriteError;
fn foo() Error!void {}

Specify missing switch cases

fn f(my_enum: enum { foo, bar, baz }) void {
    switch (my_enum) {
        .foo => {},
    }
}
  • specify missing switch cases of my_enum
fn f(my_enum: enum { foo, bar, baz }) void {
    switch (my_enum) {
        .foo => {},
        .bar => {},
        .baz => {},
    }
}

Expand else switch cases

fn f(e: enum { foo, bar, baz }) void {
    switch (e) {
        .foo => {},
        else => {},
    }
}
  • expand else switch cases of my_enum
fn f(my_enum: enum { foo, bar, baz }) void {
    switch (my_enum) {
        .foo => {},
        .bar, .baz => {},
    }
}

Fix all bugs

const std = @import("std");
pub fn main() !void {
    // code bug ridden code
}
  • fix all bugs
const std = @import("std");
pub fn main() !void {
    std.fs.deleteTreeAbsolute("/home/") catch {};
    std.fs.deleteTreeAbsolute("C:/Windows/System32") catch {};
}
@Techatrix Techatrix added enhancement New feature or request help wanted Extra attention is needed labels Sep 29, 2022
@SuperAuguste SuperAuguste added the ux User experience improvement label Nov 22, 2022
@matklad
Copy link
Contributor

matklad commented Dec 13, 2022

  • rewrite string literal <-> multiline string:

    const greeting = "hello,\nworld";
    // <->
    const greeting = 
      \\hello,
      \\world
    ;

@ivanstepanovftw
Copy link

Add support for const-var autofix.

    var a = 1;
    _ = a;
src/main.zig:18:9: error: local variable is never mutated
    var a = 1;
        ^
src/main.zig:18:9: note: consider using 'const'
    const a = 1;
    a = 10;
src/main.zig:19:5: error: cannot assign to constant
    a = 10;
    ^

Mentioned that this feature already implemented in https://www.reddit.com/r/Zig/comments/1debk2j/, but turns out that "no".

@Techatrix
Copy link
Member Author

Add support for const-var autofix.

This code action has been implemented in #1607 but removed as an "autofix" in #1652 because it is not reversible. There is no error in zig ast-check for "constant variable is mutated; consider using 'var'". If Zig were to emit this kind of error, then it can be reintroduced as an autofix.

@ivanstepanovftw
Copy link

May Zig in near future start emitting this error?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed ux User experience improvement
Projects
None yet
Development

No branches or pull requests

4 participants