From 8c952878fbff18986f4f39415158980fb1b69e1d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 25 Aug 2024 14:03:14 +0100 Subject: Allow empty strings in `link_prefix` and `link_suffix` --- src/checker.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/checker.cpp') diff --git a/src/checker.cpp b/src/checker.cpp index b24a7afdb..637659582 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3175,7 +3175,7 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) { } else if (name == "link_prefix") { if (ev.kind == ExactValue_String) { String link_prefix = ev.value_string; - if (!is_foreign_name_valid(link_prefix)) { + if (link_prefix.len != 0 && !is_foreign_name_valid(link_prefix)) { error(elem, "Invalid link prefix: '%.*s'", LIT(link_prefix)); } else { c->foreign_context.link_prefix = link_prefix; @@ -3187,7 +3187,7 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) { } else if (name == "link_suffix") { if (ev.kind == ExactValue_String) { String link_suffix = ev.value_string; - if (!is_foreign_name_valid(link_suffix)) { + if (link_suffix.len != 0 && !is_foreign_name_valid(link_suffix)) { error(elem, "Invalid link suffix: '%.*s'", LIT(link_suffix)); } else { c->foreign_context.link_suffix = link_suffix; @@ -3489,7 +3489,7 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { if (ev.kind == ExactValue_String) { ac->link_prefix = ev.value_string; - if (!is_foreign_name_valid(ac->link_prefix)) { + if (ac->link_prefix.len != 0 && !is_foreign_name_valid(ac->link_prefix)) { error(elem, "Invalid link prefix: %.*s", LIT(ac->link_prefix)); } } else { @@ -3501,7 +3501,7 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { if (ev.kind == ExactValue_String) { ac->link_suffix = ev.value_string; - if (!is_foreign_name_valid(ac->link_suffix)) { + if (ac->link_suffix.len != 0 && !is_foreign_name_valid(ac->link_suffix)) { error(elem, "Invalid link suffix: %.*s", LIT(ac->link_suffix)); } } else { @@ -3774,7 +3774,7 @@ gb_internal DECL_ATTRIBUTE_PROC(var_decl_attribute) { ExactValue ev = check_decl_attribute_value(c, value); if (ev.kind == ExactValue_String) { ac->link_prefix = ev.value_string; - if (!is_foreign_name_valid(ac->link_prefix)) { + if (ac->link_prefix.len != 0 && !is_foreign_name_valid(ac->link_prefix)) { error(elem, "Invalid link prefix: %.*s", LIT(ac->link_prefix)); } } else { @@ -3785,7 +3785,7 @@ gb_internal DECL_ATTRIBUTE_PROC(var_decl_attribute) { ExactValue ev = check_decl_attribute_value(c, value); if (ev.kind == ExactValue_String) { ac->link_suffix = ev.value_string; - if (!is_foreign_name_valid(ac->link_suffix)) { + if (ac->link_suffix.len != 0 && !is_foreign_name_valid(ac->link_suffix)) { error(elem, "Invalid link suffix: %.*s", LIT(ac->link_suffix)); } } else { -- cgit v1.2.3 From d7e977069a96916627d2f0b8e9ae848279a22784 Mon Sep 17 00:00:00 2001 From: avanspector Date: Mon, 26 Aug 2024 19:59:15 +0200 Subject: Update checker.cpp --- src/checker.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'src/checker.cpp') diff --git a/src/checker.cpp b/src/checker.cpp index 637659582..35b84c155 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3174,7 +3174,7 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) { return true; } else if (name == "link_prefix") { if (ev.kind == ExactValue_String) { - String link_prefix = ev.value_string; + String link_prefix = string_trim_whitespace(ev.value_string); if (link_prefix.len != 0 && !is_foreign_name_valid(link_prefix)) { error(elem, "Invalid link prefix: '%.*s'", LIT(link_prefix)); } else { @@ -3186,7 +3186,7 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) { return true; } else if (name == "link_suffix") { if (ev.kind == ExactValue_String) { - String link_suffix = ev.value_string; + String link_suffix = string_trim_whitespace(ev.value_string); if (link_suffix.len != 0 && !is_foreign_name_valid(link_suffix)) { error(elem, "Invalid link suffix: '%.*s'", LIT(link_suffix)); } else { @@ -4474,6 +4474,8 @@ gb_internal void correct_type_aliases_in_scope(CheckerContext *c, Scope *s) { } } +bool is_collect_entities_post = false; + // NOTE(bill): If file_scopes == nullptr, this will act like a local scope gb_internal void check_collect_entities(CheckerContext *c, Slice const &nodes) { AstFile *curr_file = nullptr; @@ -4532,7 +4534,9 @@ gb_internal void check_collect_entities(CheckerContext *c, Slice const &n case_end; case_ast_node(fb, ForeignBlockDecl, decl); - check_add_foreign_block_decl(c, decl); + if (is_collect_entities_post) { + check_add_foreign_block_decl(c, decl); + } case_end; default: @@ -6437,6 +6441,10 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("export entities - post"); check_export_entities(c); + TIME_SECTION("collect entities - post"); + is_collect_entities_post = true; + check_collect_entities_all(c); + TIME_SECTION("add entities from packages"); check_merge_queues_into_arrays(c); -- cgit v1.2.3 From 43ec2b9253379d03b69f40b57ef2aafd2c968416 Mon Sep 17 00:00:00 2001 From: avanspector Date: Mon, 26 Aug 2024 20:59:16 +0200 Subject: checker: delay foreign block checking if file scope, otherwise as before --- src/checker.cpp | 28 ++++++++++++++++++++-------- src/parser.cpp | 2 +- src/parser.hpp | 1 + 3 files changed, 22 insertions(+), 9 deletions(-) (limited to 'src/checker.cpp') diff --git a/src/checker.cpp b/src/checker.cpp index 35b84c155..fdc1ce840 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -4474,8 +4474,6 @@ gb_internal void correct_type_aliases_in_scope(CheckerContext *c, Scope *s) { } } -bool is_collect_entities_post = false; - // NOTE(bill): If file_scopes == nullptr, this will act like a local scope gb_internal void check_collect_entities(CheckerContext *c, Slice const &nodes) { AstFile *curr_file = nullptr; @@ -4534,8 +4532,8 @@ gb_internal void check_collect_entities(CheckerContext *c, Slice const &n case_end; case_ast_node(fb, ForeignBlockDecl, decl); - if (is_collect_entities_post) { - check_add_foreign_block_decl(c, decl); + if (curr_file != nullptr) { + array_add(&curr_file->delayed_decls_queues[AstDelayQueue_ForeignBlock], decl); } case_end; @@ -4552,6 +4550,14 @@ gb_internal void check_collect_entities(CheckerContext *c, Slice const &n // NOTE(bill): 'when' stmts need to be handled after the other as the condition may refer to something // declared after this stmt in source if (curr_file == nullptr) { + // For 'foreign' block statements that are not in file scope. + for_array(decl_index, nodes) { + Ast *decl = nodes[decl_index]; + if (decl->kind == Ast_ForeignBlockDecl) { + check_add_foreign_block_decl(c, decl); + } + } + for_array(decl_index, nodes) { Ast *decl = nodes[decl_index]; if (decl->kind == Ast_WhenStmt) { @@ -5512,6 +5518,16 @@ gb_internal void check_import_entities(Checker *c) { correct_type_aliases_in_scope(&ctx, pkg->scope); } + for_array(i, pkg->files) { + AstFile *f = pkg->files[i]; + reset_checker_context(&ctx, f, &untyped); + + for (Ast *decl : f->delayed_decls_queues[AstDelayQueue_ForeignBlock]) { + check_add_foreign_block_decl(&ctx, decl); + } + array_clear(&f->delayed_decls_queues[AstDelayQueue_ForeignBlock]); + } + for_array(i, pkg->files) { AstFile *f = pkg->files[i]; reset_checker_context(&ctx, f, &untyped); @@ -6441,10 +6457,6 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("export entities - post"); check_export_entities(c); - TIME_SECTION("collect entities - post"); - is_collect_entities_post = true; - check_collect_entities_all(c); - TIME_SECTION("add entities from packages"); check_merge_queues_into_arrays(c); diff --git a/src/parser.cpp b/src/parser.cpp index b250a3163..e3143dd33 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6446,7 +6446,7 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { } f->total_file_decl_count += calc_decl_count(stmt); - if (stmt->kind == Ast_WhenStmt || stmt->kind == Ast_ExprStmt || stmt->kind == Ast_ImportDecl) { + if (stmt->kind == Ast_WhenStmt || stmt->kind == Ast_ExprStmt || stmt->kind == Ast_ImportDecl || stmt->kind == Ast_ForeignBlockDecl) { f->delayed_decl_count += 1; } } diff --git a/src/parser.hpp b/src/parser.hpp index f1794f79a..d5117a31e 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -82,6 +82,7 @@ enum AstFileFlag : u32 { enum AstDelayQueueKind { AstDelayQueue_Import, AstDelayQueue_Expr, + AstDelayQueue_ForeignBlock, AstDelayQueue_COUNT, }; -- cgit v1.2.3 From 9866c83d619d9d32154ab1452bdbd255f3510bf7 Mon Sep 17 00:00:00 2001 From: avanspector Date: Thu, 29 Aug 2024 23:43:01 +0200 Subject: Add missing checker delaying --- src/checker.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/checker.cpp') diff --git a/src/checker.cpp b/src/checker.cpp index fdc1ce840..bab2d9f86 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -5228,9 +5228,9 @@ gb_internal bool collect_file_decl(CheckerContext *ctx, Ast *decl) { case_end; case_ast_node(fb, ForeignBlockDecl, decl); - if (check_add_foreign_block_decl(ctx, decl)) { - return true; - } + GB_ASSERT(ctx->collect_delayed_decls); + decl->state_flags |= StateFlag_BeenHandled; + array_add(&curr_file->delayed_decls_queues[AstDelayQueue_ForeignBlock], decl); case_end; case_ast_node(ws, WhenStmt, decl); -- cgit v1.2.3 From 47f423c12386c2d886bb8a5a8ab70e80364f9c66 Mon Sep 17 00:00:00 2001 From: avanspector Date: Fri, 30 Aug 2024 01:32:06 +0200 Subject: Set a flag for delayed checking --- src/checker.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/checker.cpp') diff --git a/src/checker.cpp b/src/checker.cpp index bab2d9f86..d5234c01c 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -5513,8 +5513,6 @@ gb_internal void check_import_entities(Checker *c) { for_array(i, pkg->files) { AstFile *f = pkg->files[i]; reset_checker_context(&ctx, f, &untyped); - ctx.collect_delayed_decls = false; - correct_type_aliases_in_scope(&ctx, pkg->scope); } @@ -5522,6 +5520,7 @@ gb_internal void check_import_entities(Checker *c) { AstFile *f = pkg->files[i]; reset_checker_context(&ctx, f, &untyped); + ctx.collect_delayed_decls = true; for (Ast *decl : f->delayed_decls_queues[AstDelayQueue_ForeignBlock]) { check_add_foreign_block_decl(&ctx, decl); } -- cgit v1.2.3 From a4e865f90bd3a6f7e5ff004d691863827d0b9399 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 30 Aug 2024 11:01:06 +0100 Subject: Fix #4166 --- src/checker.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/checker.cpp') diff --git a/src/checker.cpp b/src/checker.cpp index d5234c01c..fa04911ac 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1786,7 +1786,9 @@ gb_internal void add_entity_use(CheckerContext *c, Ast *identifier, Entity *enti entity->flags |= EntityFlag_Used; if (entity_has_deferred_procedure(entity)) { Entity *deferred = entity->Procedure.deferred_procedure.entity; - add_entity_use(c, nullptr, deferred); + if (deferred != entity) { + add_entity_use(c, nullptr, deferred); + } } if (identifier == nullptr || identifier->kind != Ast_Ident) { return; @@ -6114,6 +6116,11 @@ gb_internal void check_deferred_procedures(Checker *c) { case DeferredProcedure_in_out_by_ptr: attribute = "deferred_in_out_by_ptr"; break; } + if (src == dst) { + error(src->token, "'%.*s' cannot be used as its own %s", LIT(dst->token.string), attribute); + continue; + } + if (is_type_polymorphic(src->type) || is_type_polymorphic(dst->type)) { error(src->token, "'%s' cannot be used with a polymorphic procedure", attribute); continue; -- cgit v1.2.3 From 7624ecf4ba2a14611a80000f2b3de06b1eb0724e Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sat, 31 Aug 2024 02:30:32 +0200 Subject: fix some issues with the "bad import name" errors There was so much wrong here: - The `if` statement was never entered because even on invalid import names `path_to_entity_name` returns "_" - Two errors were shown where one doesn't make sense, need to choose one based on context - Structure of the messages were different from other error messages - Suggestion was using the wrong import path --- src/checker.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/checker.cpp') diff --git a/src/checker.cpp b/src/checker.cpp index fa04911ac..543763fc3 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -4946,12 +4946,18 @@ gb_internal void check_add_import_decl(CheckerContext *ctx, Ast *decl) { } - if (import_name.len == 0) { + if (is_blank_ident(import_name) && !is_blank_ident(id->import_name.string)) { String invalid_name = id->fullpath; invalid_name = get_invalid_import_name(invalid_name); - error(id->token, "Import name %.*s, is not a valid identifier. Perhaps you want to reference the package by a different name like this: import \"%.*s\" ", LIT(invalid_name), LIT(invalid_name)); - error(token, "Import name, %.*s, cannot be use as an import name as it is not a valid identifier", LIT(id->import_name.string)); + ERROR_BLOCK(); + + if (id->import_name.string.len > 0) { + error(token, "Import name, '%.*s' cannot be use as an import name as it is not a valid identifier", LIT(id->import_name.string)); + } else { + error(id->token, "Import name '%.*s' is not a valid identifier", LIT(invalid_name)); + error_line("\tSuggestion: Rename the directory or explicitly set an import name like this 'import %.*s'", LIT(id->relpath.string)); + } } else { GB_ASSERT(id->import_name.pos.line != 0); id->import_name.string = import_name; -- cgit v1.2.3 From 7f3d8e115f389d9064905ff5aa8d359399dda20b Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sat, 31 Aug 2024 02:45:17 +0200 Subject: remove comma --- src/checker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/checker.cpp') diff --git a/src/checker.cpp b/src/checker.cpp index 543763fc3..64c66c8a6 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -4953,7 +4953,7 @@ gb_internal void check_add_import_decl(CheckerContext *ctx, Ast *decl) { ERROR_BLOCK(); if (id->import_name.string.len > 0) { - error(token, "Import name, '%.*s' cannot be use as an import name as it is not a valid identifier", LIT(id->import_name.string)); + error(token, "Import name '%.*s' cannot be use as an import name as it is not a valid identifier", LIT(id->import_name.string)); } else { error(id->token, "Import name '%.*s' is not a valid identifier", LIT(invalid_name)); error_line("\tSuggestion: Rename the directory or explicitly set an import name like this 'import %.*s'", LIT(id->relpath.string)); -- cgit v1.2.3 From 19c1ed154cc9e36433fe23e1e34810f9c53ec01d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 17 Sep 2024 11:01:26 +0100 Subject: Add `-vet-packages:` --- src/build_settings.cpp | 3 +-- src/checker.cpp | 16 ++++------------ src/main.cpp | 30 +++++++++++++++++++++++++++++- src/parser.cpp | 31 ++++++++++++++++++++----------- 4 files changed, 54 insertions(+), 26 deletions(-) (limited to 'src/checker.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 1aca5d424..341cbe3e1 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -383,6 +383,7 @@ struct BuildContext { u64 vet_flags; u32 sanitizer_flags; + StringSet vet_packages; bool has_resource; String link_flags; @@ -1462,8 +1463,6 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta bc->thread_count = gb_max(bc->affinity.thread_count, 1); } - string_set_init(&bc->custom_attributes); - bc->ODIN_VENDOR = str_lit("odin"); bc->ODIN_VERSION = ODIN_VERSION; bc->ODIN_ROOT = odin_root_dir(); diff --git a/src/checker.cpp b/src/checker.cpp index 64c66c8a6..deb83bf97 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -533,18 +533,13 @@ gb_internal u64 check_vet_flags(CheckerContext *c) { c->curr_proc_decl->proc_lit) { file = c->curr_proc_decl->proc_lit->file(); } - if (file && file->vet_flags_set) { - return file->vet_flags; - } - return build_context.vet_flags; + + return ast_file_vet_flags(file); } gb_internal u64 check_vet_flags(Ast *node) { AstFile *file = node->file(); - if (file && file->vet_flags_set) { - return file->vet_flags; - } - return build_context.vet_flags; + return ast_file_vet_flags(file); } enum VettedEntityKind { @@ -6497,10 +6492,7 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("check scope usage"); for (auto const &entry : c->info.files) { AstFile *f = entry.value; - u64 vet_flags = build_context.vet_flags; - if (f->vet_flags_set) { - vet_flags = f->vet_flags; - } + u64 vet_flags = ast_file_vet_flags(f); check_scope_usage(c, f->scope, vet_flags); } diff --git a/src/main.cpp b/src/main.cpp index 06c200442..9b1dcf0fa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -346,6 +346,7 @@ enum BuildFlagKind { BuildFlag_VetSemicolon, BuildFlag_VetCast, BuildFlag_VetTabs, + BuildFlag_VetPackages, BuildFlag_CustomAttribute, BuildFlag_IgnoreUnknownAttributes, @@ -555,6 +556,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_VetSemicolon, str_lit("vet-semicolon"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetCast, str_lit("vet-cast"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetTabs, str_lit("vet-tabs"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_VetPackages, str_lit("vet-packages"), BuildFlagParam_String, Command__does_check); add_flag(&build_flags, BuildFlag_CustomAttribute, str_lit("custom-attribute"), BuildFlagParam_String, Command__does_check, true); add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None, Command__does_check); @@ -1221,6 +1223,29 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_VetCast: build_context.vet_flags |= VetFlag_Cast; break; case BuildFlag_VetTabs: build_context.vet_flags |= VetFlag_Tabs; break; + case BuildFlag_VetPackages: + { + GB_ASSERT(value.kind == ExactValue_String); + String val = value.value_string; + String_Iterator it = {val, 0}; + for (;;) { + String pkg = string_split_iterator(&it, ','); + if (pkg.len == 0) { + break; + } + + pkg = string_trim_whitespace(pkg); + if (!string_is_valid_identifier(pkg)) { + gb_printf_err("-%.*s '%.*s' must be a valid identifier\n", LIT(name), LIT(pkg)); + bad_flags = true; + continue; + } + + string_set_add(&build_context.vet_packages, pkg); + } + } + break; + case BuildFlag_CustomAttribute: { GB_ASSERT(value.kind == ExactValue_String); @@ -1234,7 +1259,7 @@ gb_internal bool parse_build_flags(Array args) { attr = string_trim_whitespace(attr); if (!string_is_valid_identifier(attr)) { - gb_printf_err("-custom-attribute '%.*s' must be a valid identifier\n", LIT(attr)); + gb_printf_err("-%.*s '%.*s' must be a valid identifier\n", LIT(name), LIT(attr)); bad_flags = true; continue; } @@ -3150,6 +3175,9 @@ int main(int arg_count, char const **arg_ptr) { build_context.command = command; + string_set_init(&build_context.custom_attributes); + string_set_init(&build_context.vet_packages); + if (!parse_build_flags(args)) { return 1; } diff --git a/src/parser.cpp b/src/parser.cpp index 88147d465..56bea8131 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,10 +1,28 @@ #include "parser_pos.cpp" +gb_internal bool in_vet_packages(AstFile *file) { + if (file == nullptr) { + return true; + } + if (file->pkg == nullptr) { + return true; + } + if (build_context.vet_packages.entries.count == 0) { + return true; + } + return string_set_exists(&build_context.vet_packages, file->pkg->name); +} + gb_internal u64 ast_file_vet_flags(AstFile *f) { if (f != nullptr && f->vet_flags_set) { return f->vet_flags; } - return build_context.vet_flags; + + bool found = in_vet_packages(f); + if (found) { + return build_context.vet_flags; + } + return 0; } gb_internal bool ast_file_vet_style(AstFile *f) { @@ -5372,18 +5390,9 @@ gb_internal Ast *parse_stmt(AstFile *f) { } - -gb_internal u64 check_vet_flags(AstFile *file) { - if (file && file->vet_flags_set) { - return file->vet_flags; - } - return build_context.vet_flags; -} - - gb_internal void parse_enforce_tabs(AstFile *f) { // Checks to see if tabs have been used for indentation - if ((check_vet_flags(f) & VetFlag_Tabs) == 0) { + if ((ast_file_vet_flags(f) & VetFlag_Tabs) == 0) { return; } -- cgit v1.2.3 From 09588836e73d2def550cf5b1f6dab4d9de237e37 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 17 Sep 2024 11:33:42 +0100 Subject: Add `-vet-unused-procedures` --- src/build_settings.cpp | 3 +++ src/checker.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++------- src/main.cpp | 21 ++++++++++++++++++- 3 files changed, 71 insertions(+), 8 deletions(-) (limited to 'src/checker.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 341cbe3e1..7aff8e650 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -285,6 +285,7 @@ enum VetFlags : u64 { VetFlag_Deprecated = 1u<<7, VetFlag_Cast = 1u<<8, VetFlag_Tabs = 1u<<9, + VetFlag_UnusedProcedures = 1u<<10, VetFlag_Unused = VetFlag_UnusedVariables|VetFlag_UnusedImports, @@ -316,6 +317,8 @@ u64 get_vet_flag_from_name(String const &name) { return VetFlag_Cast; } else if (name == "tabs") { return VetFlag_Tabs; + } else if (name == "unused-procedures") { + return VetFlag_UnusedProcedures; } return VetFlag_NONE; } diff --git a/src/checker.cpp b/src/checker.cpp index deb83bf97..af1e0e675 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -676,20 +676,45 @@ gb_internal bool check_vet_unused(Checker *c, Entity *e, VettedEntity *ve) { return false; } -gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) { - bool vet_unused = (vet_flags & VetFlag_Unused) != 0; - bool vet_shadowing = (vet_flags & (VetFlag_Shadowing|VetFlag_Using)) != 0; - +gb_internal void check_scope_usage_internal(Checker *c, Scope *scope, u64 vet_flags, bool per_entity) { + u64 original_vet_flags = vet_flags; Array vetted_entities = {}; array_init(&vetted_entities, heap_allocator()); + defer (array_free(&vetted_entities)); rw_mutex_shared_lock(&scope->mutex); for (auto const &entry : scope->elements) { Entity *e = entry.value; if (e == nullptr) continue; + + vet_flags = original_vet_flags; + if (per_entity) { + vet_flags = ast_file_vet_flags(e->file); + } + + bool vet_unused = (vet_flags & VetFlag_Unused) != 0; + bool vet_shadowing = (vet_flags & (VetFlag_Shadowing|VetFlag_Using)) != 0; + bool vet_unused_procedures = (vet_flags & VetFlag_UnusedProcedures) != 0; + VettedEntity ve_unused = {}; VettedEntity ve_shadowed = {}; - bool is_unused = vet_unused && check_vet_unused(c, e, &ve_unused); + bool is_unused = false; + if (vet_unused && check_vet_unused(c, e, &ve_unused)) { + is_unused = true; + } else if (vet_unused_procedures && + e->kind == Entity_Procedure) { + if (e->flags&EntityFlag_Used) { + is_unused = false; + } else if (e->flags & EntityFlag_Require) { + is_unused = false; + } else if (e->pkg && e->pkg->kind == Package_Init && e->token.string == "main") { + is_unused = false; + } else { + is_unused = true; + ve_unused.kind = VettedEntity_Unused; + ve_unused.entity = e; + } + } bool is_shadowed = vet_shadowing && check_vet_shadowing(c, e, &ve_shadowed); if (is_unused && is_shadowed) { VettedEntity ve_both = ve_shadowed; @@ -712,13 +737,18 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) { } rw_mutex_shared_unlock(&scope->mutex); - gb_sort(vetted_entities.data, vetted_entities.count, gb_size_of(VettedEntity), vetted_entity_variable_pos_cmp); + array_sort(vetted_entities, vetted_entity_variable_pos_cmp); for (auto const &ve : vetted_entities) { Entity *e = ve.entity; Entity *other = ve.other; String name = e->token.string; + vet_flags = original_vet_flags; + if (per_entity) { + vet_flags = ast_file_vet_flags(e->file); + } + if (ve.kind == VettedEntity_Shadowed_And_Unused) { error(e->token, "'%.*s' declared but not used, possibly shadows declaration at line %d", LIT(name), other->token.pos.line); } else if (vet_flags) { @@ -727,6 +757,9 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) { if (e->kind == Entity_Variable && (vet_flags & VetFlag_UnusedVariables) != 0) { error(e->token, "'%.*s' declared but not used", LIT(name)); } + if (e->kind == Entity_Procedure && (vet_flags & VetFlag_UnusedProcedures) != 0) { + error(e->token, "'%.*s' declared but not used", LIT(name)); + } if ((e->kind == Entity_ImportName || e->kind == Entity_LibraryName) && (vet_flags & VetFlag_UnusedImports) != 0) { error(e->token, "'%.*s' declared but not used", LIT(name)); } @@ -744,7 +777,11 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) { } } - array_free(&vetted_entities); +} + + +gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) { + check_scope_usage_internal(c, scope, vet_flags, false); for (Scope *child = scope->head_child; child != nullptr; child = child->next) { if (child->flags & (ScopeFlag_Proc|ScopeFlag_Type|ScopeFlag_File)) { @@ -6495,6 +6532,10 @@ gb_internal void check_parsed_files(Checker *c) { u64 vet_flags = ast_file_vet_flags(f); check_scope_usage(c, f->scope, vet_flags); } + for (auto const &entry : c->info.packages) { + AstPackage *pkg = entry.value; + check_scope_usage_internal(c, pkg->scope, 0, true); + } TIME_SECTION("add basic type information"); // Add "Basic" type information diff --git a/src/main.cpp b/src/main.cpp index 9b1dcf0fa..a969e32a9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -340,6 +340,7 @@ enum BuildFlagKind { BuildFlag_VetUnused, BuildFlag_VetUnusedImports, BuildFlag_VetUnusedVariables, + BuildFlag_VetUnusedProcedures, BuildFlag_VetUsingStmt, BuildFlag_VetUsingParam, BuildFlag_VetStyle, @@ -548,6 +549,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetUnused, str_lit("vet-unused"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetUnusedVariables, str_lit("vet-unused-variables"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_VetUnusedProcedures, str_lit("vet-unused-procedures"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetUnusedImports, str_lit("vet-unused-imports"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetShadowing, str_lit("vet-shadowing"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetUsingStmt, str_lit("vet-using-stmt"), BuildFlagParam_None, Command__does_check); @@ -1222,6 +1224,13 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_VetSemicolon: build_context.vet_flags |= VetFlag_Semicolon; break; case BuildFlag_VetCast: build_context.vet_flags |= VetFlag_Cast; break; case BuildFlag_VetTabs: build_context.vet_flags |= VetFlag_Tabs; break; + case BuildFlag_VetUnusedProcedures: + build_context.vet_flags |= VetFlag_UnusedProcedures; + if (!set_flags[BuildFlag_VetPackages]) { + gb_printf_err("-%.*s must be used with -vet-packages\n", LIT(name)); + bad_flags = true; + } + break; case BuildFlag_VetPackages: { @@ -2389,7 +2398,7 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(0, ""); print_usage_line(1, "-vet-unused"); - print_usage_line(2, "Checks for unused declarations."); + print_usage_line(2, "Checks for unused declarations (variables and imports)."); print_usage_line(0, ""); print_usage_line(1, "-vet-unused-variables"); @@ -2431,6 +2440,16 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(1, "-vet-tabs"); print_usage_line(2, "Errs when the use of tabs has not been used for indentation."); print_usage_line(0, ""); + + print_usage_line(1, "-vet-packages:"); + print_usage_line(2, "Sets which packages by name will be vetted."); + print_usage_line(2, "Files with specific +vet tags will not be ignored if they are not in the packages set."); + print_usage_line(0, ""); + + print_usage_line(1, "-vet-unused-procedures"); + print_usage_line(2, "Checks for unused procedures."); + print_usage_line(2, "Must be used with -vet-packages or specified on a per file with +vet tags."); + print_usage_line(0, ""); } if (check) { -- cgit v1.2.3