warning diagnostics for unused locals
This commit is contained in:
+144
-14
@@ -1102,12 +1102,12 @@ main func() void {
|
||||
|
||||
@(test)
|
||||
string_literals_preserve_static_length_and_sentinel_through_pointer_views :: proc(t: ^testing.T) {
|
||||
text := `take_sentinel_pointer func(value [*;0]u8) void {}
|
||||
take_mut_sentinel_pointer func(value [*;0]mut u8) void {}
|
||||
take_pointer func(value *u8) void {}
|
||||
take_sentinel_slice func(value [;0]u8) void {}
|
||||
take_mut_sentinel_slice func(value [;0]mut u8) void {}
|
||||
take_slice func(value []u8) void {}
|
||||
text := `take_sentinel_pointer func(_ [*;0]u8) void {}
|
||||
take_mut_sentinel_pointer func(_ [*;0]mut u8) void {}
|
||||
take_pointer func(_ *u8) void {}
|
||||
take_sentinel_slice func(_ [;0]u8) void {}
|
||||
take_mut_sentinel_slice func(_ [;0]mut u8) void {}
|
||||
take_slice func(_ []u8) void {}
|
||||
take_c_string c_func(value *c_char) c_int
|
||||
take_c_sentinel c_func(value [*;0]c_char) c_int
|
||||
main func() void {
|
||||
@@ -1574,8 +1574,8 @@ main func() void {
|
||||
@(test)
|
||||
opaque_anyopaque_and_ptr_cast_compile_and_lower :: proc(t: ^testing.T) {
|
||||
text := `Handle :: opaque
|
||||
take func(value ?*mut anyopaque) void {}
|
||||
use_handle func(handle ?@mut Handle) void {}
|
||||
take func(_ ?*mut anyopaque) void {}
|
||||
use_handle func(_ ?@mut Handle) void {}
|
||||
main func() void {
|
||||
values [2]mut u8 = [1, 2]
|
||||
raw ?*mut anyopaque = (&values).ptr
|
||||
@@ -1833,6 +1833,7 @@ take_int func(value int) int {
|
||||
}
|
||||
main func() void {
|
||||
local i16 :: 1 + 2
|
||||
_ = local
|
||||
_ = 100 + (20 + 8)
|
||||
_ = return_i16()
|
||||
_ = take_i16(1 + 2)
|
||||
@@ -1985,6 +1986,69 @@ main func() void {
|
||||
testing.expect_value(t, hir_module.statements[main.body[2]].kind, hir.Stmt_Kind.Trap)
|
||||
}
|
||||
|
||||
@(test)
|
||||
unused_locals_and_params_warn_without_traps :: proc(t: ^testing.T) {
|
||||
text := `warn_only func(value i32, unused i32) i32 {
|
||||
local i32 = 1
|
||||
write_only i32 = 2
|
||||
write_only = 3
|
||||
consumed i32 = value
|
||||
_ = consumed
|
||||
return value
|
||||
}
|
||||
main func() void {
|
||||
_ = warn_only(1, 2)
|
||||
}
|
||||
`
|
||||
source_file := source.Source{path="test.bro", text=text}
|
||||
diagnostics := source.init_diagnostics(&source_file)
|
||||
defer source.destroy_diagnostics(&diagnostics)
|
||||
symbols := symbol.init_table()
|
||||
defer symbol.destroy_table(&symbols)
|
||||
stream := lexer.lex(&source_file, &diagnostics, &symbols)
|
||||
defer delete(stream.items)
|
||||
ast_module := parser.parse(&stream, &source_file, &diagnostics)
|
||||
defer ast.destroy_module(&ast_module)
|
||||
hir_module := checker.check(&ast_module, &diagnostics, &symbols)
|
||||
defer hir.destroy_module(&hir_module)
|
||||
|
||||
found_unused_param := false
|
||||
found_unused_local := false
|
||||
found_write_only := false
|
||||
warning_count := 0
|
||||
error_count := 0
|
||||
for diagnostic in diagnostics.items {
|
||||
if diagnostic.severity == source.Severity.Warning {
|
||||
warning_count += 1
|
||||
} else {
|
||||
error_count += 1
|
||||
}
|
||||
found_unused_param = found_unused_param || strings.contains(diagnostic.message, "unused parameter 'unused'")
|
||||
found_unused_local = found_unused_local || strings.contains(diagnostic.message, "unused local 'local'")
|
||||
found_write_only = found_write_only || strings.contains(diagnostic.message, "unused local 'write_only'")
|
||||
testing.expect(t, !strings.contains(diagnostic.message, "unused local 'consumed'"))
|
||||
testing.expect(t, !strings.contains(diagnostic.message, "unused parameter 'value'"))
|
||||
}
|
||||
testing.expect_value(t, warning_count, 3)
|
||||
testing.expect_value(t, error_count, 0)
|
||||
testing.expect(t, found_unused_param)
|
||||
testing.expect(t, found_unused_local)
|
||||
testing.expect(t, found_write_only)
|
||||
|
||||
found_function := false
|
||||
for function in hir_module.functions {
|
||||
if symbol.resolve(&symbols, function.name) != "warn_only" {
|
||||
continue
|
||||
}
|
||||
found_function = true
|
||||
testing.expect(t, !function.problematic)
|
||||
for stmt_id in function.body {
|
||||
testing.expect(t, hir_module.statements[stmt_id].kind != hir.Stmt_Kind.Trap)
|
||||
}
|
||||
}
|
||||
testing.expect(t, found_function)
|
||||
}
|
||||
|
||||
@(test)
|
||||
recursive_specialization_reaches_a_fixed_point :: proc(t: ^testing.T) {
|
||||
text := `a func(value int) i32 {
|
||||
@@ -2309,7 +2373,7 @@ zero func($T type) T {
|
||||
value T = undefined
|
||||
return value
|
||||
}
|
||||
buffer func($T type, $N usize, value T) [N]T {
|
||||
buffer func($T type, $N usize, _ T) [N]T {
|
||||
data [N]T = undefined
|
||||
return data
|
||||
}
|
||||
@@ -2656,6 +2720,16 @@ valid_program_compiles_and_runs :: proc(t: ^testing.T) {
|
||||
testing.expect_value(t, state.exit_code, 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
unused_local_warnings_return_status_one_but_do_not_trap :: proc(t: ^testing.T) {
|
||||
output := "/tmp/brolang-test-unused-locals"
|
||||
defer _ = os.remove(output)
|
||||
status := compiler_core.compile_package("examples/programs/unused_locals", output)
|
||||
testing.expect_value(t, status, 1)
|
||||
state := run_executable(output)
|
||||
testing.expect_value(t, state.exit_code, 7)
|
||||
}
|
||||
|
||||
@(test)
|
||||
build_command_is_recognized :: proc(t: ^testing.T) {
|
||||
testing.expect(t, is_build_command("build"))
|
||||
@@ -5721,6 +5795,30 @@ source_store_owns_buffers_indexes_lines_and_deduplicates_diagnostics :: proc(t:
|
||||
testing.expect(t, strings.contains(formatted, "owned.bro:2:1:"))
|
||||
}
|
||||
|
||||
@(test)
|
||||
diagnostic_warnings_format_and_dedupe_by_severity :: proc(t: ^testing.T) {
|
||||
source_file := source.Source{path="test.bro", text="one\n"}
|
||||
diagnostics := source.init_diagnostics(&source_file)
|
||||
defer source.destroy_diagnostics(&diagnostics)
|
||||
span := source.Span{start=0, end=3}
|
||||
|
||||
warning := source.add_warning(&diagnostics, span, "same")
|
||||
warning_again := source.addf_warning(&diagnostics, span, "%s", "same")
|
||||
err := source.add(&diagnostics, span, "same")
|
||||
formatted_warning := source.format(&diagnostics, warning)
|
||||
defer delete(formatted_warning)
|
||||
formatted_error := source.format(&diagnostics, err)
|
||||
defer delete(formatted_error)
|
||||
|
||||
testing.expect_value(t, warning, warning_again)
|
||||
testing.expect(t, warning != err)
|
||||
testing.expect_value(t, len(diagnostics.items), 2)
|
||||
testing.expect_value(t, diagnostics.items[warning].severity, source.Severity.Warning)
|
||||
testing.expect_value(t, diagnostics.items[err].severity, source.Severity.Error)
|
||||
testing.expect(t, strings.contains(formatted_warning, "test.bro:1:1: warning: same"))
|
||||
testing.expect(t, strings.contains(formatted_error, "test.bro:1:1: error: same"))
|
||||
}
|
||||
|
||||
@(test)
|
||||
maximum_signed_i64_literal_parses_exactly :: proc(t: ^testing.T) {
|
||||
source_file := source.Source{path="test.bro", text="value :: 9223372036854775807\nmain func() void {}\n"}
|
||||
@@ -6325,6 +6423,33 @@ unused_import_is_diagnosed_but_remains_executable :: proc(t: ^testing.T) {
|
||||
testing.expect_value(t, state.exit_code, 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
unused_import_is_a_warning :: proc(t: ^testing.T) {
|
||||
sources := source.init_store()
|
||||
defer source.destroy_store(&sources)
|
||||
diagnostics := source.init_store_diagnostics(&sources)
|
||||
defer source.destroy_diagnostics(&diagnostics)
|
||||
symbols := symbol.init_table()
|
||||
defer symbol.destroy_table(&symbols)
|
||||
module, loaded := loader.load("examples/packages/unused/app", &sources, &diagnostics, &symbols)
|
||||
defer ast.destroy_module(&module)
|
||||
hir_module := checker.check(&module, &diagnostics, &symbols)
|
||||
defer hir.destroy_module(&hir_module)
|
||||
|
||||
testing.expect(t, loaded)
|
||||
found := false
|
||||
for diagnostic, index in diagnostics.items {
|
||||
if strings.contains(diagnostic.message, "unused import 'math'") {
|
||||
found = true
|
||||
testing.expect_value(t, diagnostic.severity, source.Severity.Warning)
|
||||
formatted := source.format(&diagnostics, source.diagnostic_id(index))
|
||||
testing.expect(t, strings.contains(formatted, "warning: unused import 'math'"))
|
||||
delete(formatted)
|
||||
}
|
||||
}
|
||||
testing.expect(t, found)
|
||||
}
|
||||
|
||||
@(test)
|
||||
unused_missing_package_does_not_trap :: proc(t: ^testing.T) {
|
||||
output := "/tmp/brolang-test-package-missing-unused"
|
||||
@@ -8309,6 +8434,9 @@ main func() void {
|
||||
point Point = undefined
|
||||
pointer @i32 = undefined
|
||||
maybe ?i32 = undefined
|
||||
_ = point
|
||||
_ = pointer
|
||||
_ = maybe
|
||||
}
|
||||
`
|
||||
source_file := source.Source{path="test.bro", text=text}
|
||||
@@ -9390,7 +9518,7 @@ main func() void {}
|
||||
|
||||
@(test)
|
||||
contextual_inference_resolves_locals_like_globals :: proc(t: ^testing.T) {
|
||||
text := `take_u16 func(v u16) void {}
|
||||
text := `take_u16 func(_ u16) void {}
|
||||
get func() u16 {
|
||||
c :: 10
|
||||
return c
|
||||
@@ -9403,6 +9531,8 @@ main func() void {
|
||||
b u16 :: a
|
||||
n :: 5
|
||||
take_u16(n)
|
||||
_ = z
|
||||
_ = b
|
||||
_ = get()
|
||||
}
|
||||
`
|
||||
@@ -9426,7 +9556,7 @@ main func() void {
|
||||
|
||||
@(test)
|
||||
contextual_inference_demand_from_function_body_reaches_global :: proc(t: ^testing.T) {
|
||||
text := `take_u16 func(v u16) void {}
|
||||
text := `take_u16 func(_ u16) void {}
|
||||
G :: 10
|
||||
main func() void {
|
||||
take_u16(G)
|
||||
@@ -9479,7 +9609,7 @@ contextual_inference_flows_through_compound_assignment :: proc(t: ^testing.T) {
|
||||
|
||||
@(test)
|
||||
contextual_inference_resolves_open_global_arithmetic_across_uses :: proc(t: ^testing.T) {
|
||||
text := `take_ci func(v c_int) void {}
|
||||
text := `take_ci func(_ c_int) void {}
|
||||
W :: 800
|
||||
Z :: 40
|
||||
STEP :: 5
|
||||
@@ -9547,8 +9677,8 @@ contextual_inference_rejects_local_constant_that_does_not_fit :: proc(t: ^testin
|
||||
|
||||
@(test)
|
||||
contextual_inference_flows_through_numeric_arithmetic :: proc(t: ^testing.T) {
|
||||
text := `take_u16 func(v u16) void {}
|
||||
take_f32 func(v f32) void {}
|
||||
text := `take_u16 func(_ u16) void {}
|
||||
take_f32 func(_ f32) void {}
|
||||
G :: 10
|
||||
H u16 :: G + 2
|
||||
GF :: 1.5
|
||||
|
||||
Reference in New Issue
Block a user