mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-26 04:44:57 +00:00
Add -show-unused (Shows unused package declarations of all imported packages)
Crude output at the moment but better than nothing
This commit is contained in:
@@ -143,6 +143,7 @@ struct BuildContext {
|
||||
bool generate_docs;
|
||||
i32 optimization_level;
|
||||
bool show_timings;
|
||||
bool show_unused;
|
||||
bool show_more_timings;
|
||||
bool show_system_calls;
|
||||
bool keep_temp_files;
|
||||
|
||||
@@ -1007,11 +1007,10 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ptr_set_exists(&entity_set, e)) {
|
||||
if (ptr_set_update(&entity_set, e)) {
|
||||
error(arg, "Previous use of `%.*s` in procedure group", LIT(e->token.string));
|
||||
continue;
|
||||
}
|
||||
ptr_set_add(&entity_set, e);
|
||||
array_add(&pge->entities, e);
|
||||
}
|
||||
|
||||
|
||||
@@ -700,7 +700,7 @@ void init_universal(void) {
|
||||
builtin_pkg->kind = Package_Normal;
|
||||
|
||||
builtin_pkg->scope = create_scope(nullptr);
|
||||
builtin_pkg->scope->flags |= ScopeFlag_Pkg | ScopeFlag_Global;
|
||||
builtin_pkg->scope->flags |= ScopeFlag_Pkg | ScopeFlag_Global | ScopeFlag_Builtin;
|
||||
builtin_pkg->scope->pkg = builtin_pkg;
|
||||
|
||||
intrinsics_pkg = gb_alloc_item(a, AstPackage);
|
||||
@@ -708,7 +708,7 @@ void init_universal(void) {
|
||||
intrinsics_pkg->kind = Package_Normal;
|
||||
|
||||
intrinsics_pkg->scope = create_scope(nullptr);
|
||||
intrinsics_pkg->scope->flags |= ScopeFlag_Pkg | ScopeFlag_Global;
|
||||
intrinsics_pkg->scope->flags |= ScopeFlag_Pkg | ScopeFlag_Global | ScopeFlag_Builtin;
|
||||
intrinsics_pkg->scope->pkg = intrinsics_pkg;
|
||||
|
||||
config_pkg = gb_alloc_item(a, AstPackage);
|
||||
@@ -716,7 +716,7 @@ void init_universal(void) {
|
||||
config_pkg->kind = Package_Normal;
|
||||
|
||||
config_pkg->scope = create_scope(nullptr);
|
||||
config_pkg->scope->flags |= ScopeFlag_Pkg | ScopeFlag_Global;
|
||||
config_pkg->scope->flags |= ScopeFlag_Pkg | ScopeFlag_Global | ScopeFlag_Builtin;
|
||||
config_pkg->scope->pkg = config_pkg;
|
||||
|
||||
|
||||
@@ -1501,11 +1501,10 @@ void add_min_dep_type_info(Checker *c, Type *t) {
|
||||
ti_index = type_info_index(&c->info, t, false);
|
||||
}
|
||||
GB_ASSERT(ti_index >= 0);
|
||||
if (ptr_set_exists(set, ti_index)) {
|
||||
if (ptr_set_update(set, ti_index)) {
|
||||
// Type Already exists
|
||||
return;
|
||||
}
|
||||
ptr_set_add(set, ti_index);
|
||||
|
||||
// Add nested types
|
||||
if (t->kind == Type_Named) {
|
||||
@@ -1688,12 +1687,10 @@ void add_dependency_to_set(Checker *c, Entity *entity) {
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr_set_exists(set, entity)) {
|
||||
if (ptr_set_update(set, entity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ptr_set_add(set, entity);
|
||||
DeclInfo *decl = decl_info_of_entity(entity);
|
||||
if (decl == nullptr) {
|
||||
return;
|
||||
@@ -3567,11 +3564,9 @@ struct ImportPathItem {
|
||||
Array<ImportPathItem> find_import_path(Checker *c, AstPackage *start, AstPackage *end, PtrSet<AstPackage *> *visited) {
|
||||
Array<ImportPathItem> empty_path = {};
|
||||
|
||||
if (ptr_set_exists(visited, start)) {
|
||||
if (ptr_set_update(visited, start)) {
|
||||
return empty_path;
|
||||
}
|
||||
ptr_set_add(visited, start);
|
||||
|
||||
|
||||
String path = start->fullpath;
|
||||
AstPackage **found = string_map_get(&c->info.packages, path);
|
||||
@@ -3657,10 +3652,8 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) {
|
||||
GB_ASSERT(scope->flags&ScopeFlag_Pkg);
|
||||
|
||||
|
||||
if (ptr_set_exists(&parent_scope->imported, scope)) {
|
||||
if (ptr_set_update(&parent_scope->imported, scope)) {
|
||||
// error(token, "Multiple import of the same file within this scope");
|
||||
} else {
|
||||
ptr_set_add(&parent_scope->imported, scope);
|
||||
}
|
||||
|
||||
String import_name = path_to_entity_name(id->import_name.string, id->fullpath, false);
|
||||
@@ -4013,10 +4006,9 @@ void check_import_entities(Checker *c) {
|
||||
if (pkg == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (ptr_set_exists(&emitted, pkg)) {
|
||||
if (ptr_set_update(&emitted, pkg)) {
|
||||
continue;
|
||||
}
|
||||
ptr_set_add(&emitted, pkg);
|
||||
|
||||
array_add(&package_order, n);
|
||||
}
|
||||
@@ -4259,11 +4251,9 @@ void calculate_global_init_order(Checker *c) {
|
||||
// if (!decl_info_has_init(d)) {
|
||||
// continue;
|
||||
// }
|
||||
if (ptr_set_exists(&emitted, d)) {
|
||||
if (ptr_set_update(&emitted, d)) {
|
||||
continue;
|
||||
}
|
||||
ptr_set_add(&emitted, d);
|
||||
|
||||
|
||||
array_add(&info->variable_init_order, d);
|
||||
}
|
||||
|
||||
@@ -160,12 +160,13 @@ struct ProcInfo {
|
||||
|
||||
|
||||
enum ScopeFlag : i32 {
|
||||
ScopeFlag_Pkg = 1<<1,
|
||||
ScopeFlag_Global = 1<<2,
|
||||
ScopeFlag_File = 1<<3,
|
||||
ScopeFlag_Init = 1<<4,
|
||||
ScopeFlag_Proc = 1<<5,
|
||||
ScopeFlag_Type = 1<<6,
|
||||
ScopeFlag_Pkg = 1<<1,
|
||||
ScopeFlag_Builtin = 1<<2,
|
||||
ScopeFlag_Global = 1<<3,
|
||||
ScopeFlag_File = 1<<4,
|
||||
ScopeFlag_Init = 1<<5,
|
||||
ScopeFlag_Proc = 1<<6,
|
||||
ScopeFlag_Type = 1<<7,
|
||||
|
||||
ScopeFlag_HasBeenImported = 1<<10, // This is only applicable to file scopes
|
||||
|
||||
|
||||
159
src/main.cpp
159
src/main.cpp
@@ -568,6 +568,7 @@ enum BuildFlagKind {
|
||||
BuildFlag_OutFile,
|
||||
BuildFlag_OptimizationLevel,
|
||||
BuildFlag_ShowTimings,
|
||||
BuildFlag_ShowUnused,
|
||||
BuildFlag_ShowMoreTimings,
|
||||
BuildFlag_ShowSystemCalls,
|
||||
BuildFlag_ThreadCount,
|
||||
@@ -669,6 +670,7 @@ bool parse_build_flags(Array<String> args) {
|
||||
add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String);
|
||||
add_flag(&build_flags, BuildFlag_OptimizationLevel, str_lit("opt"), BuildFlagParam_Integer);
|
||||
add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_ShowUnused, str_lit("show-unused"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_ShowMoreTimings, str_lit("show-more-timings"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_ShowSystemCalls, str_lit("show-system-calls"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_ThreadCount, str_lit("thread-count"), BuildFlagParam_Integer);
|
||||
@@ -860,6 +862,14 @@ bool parse_build_flags(Array<String> args) {
|
||||
GB_ASSERT(value.kind == ExactValue_Invalid);
|
||||
build_context.show_timings = true;
|
||||
break;
|
||||
case BuildFlag_ShowUnused:
|
||||
GB_ASSERT(value.kind == ExactValue_Invalid);
|
||||
build_context.show_unused = true;
|
||||
if (build_context.command != "check") {
|
||||
gb_printf_err("%.*s is only allowed with 'odin check'\n", LIT(name));
|
||||
bad_flags = true;
|
||||
}
|
||||
break;
|
||||
case BuildFlag_ShowMoreTimings:
|
||||
GB_ASSERT(value.kind == ExactValue_Invalid);
|
||||
build_context.show_timings = true;
|
||||
@@ -1487,6 +1497,7 @@ void print_show_help(String const arg0, String const &command) {
|
||||
|
||||
bool build = command == "build";
|
||||
bool run_or_build = command == "run" || command == "build";
|
||||
bool check_only = command == "check";
|
||||
bool check = command == "run" || command == "build" || command == "check";
|
||||
|
||||
print_usage_line(0, "");
|
||||
@@ -1521,6 +1532,12 @@ void print_show_help(String const arg0, String const &command) {
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (check_only) {
|
||||
print_usage_line(1, "-show-unused");
|
||||
print_usage_line(2, "Shows unused package declarations within the current project");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
print_usage_line(1, "-keep-temp-files");
|
||||
print_usage_line(2, "Keeps the temporary files generated during compilation");
|
||||
@@ -1599,6 +1616,23 @@ void print_show_help(String const arg0, String const &command) {
|
||||
print_usage_line(1, "-extra-linker-flags:<string>");
|
||||
print_usage_line(2, "Adds extra linker specific flags in a string");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-microarch:<string>");
|
||||
print_usage_line(2, "Specifies the specific micro-architecture for the build in a string");
|
||||
print_usage_line(2, "Examples:");
|
||||
print_usage_line(3, "-microarch:sandybridge");
|
||||
print_usage_line(3, "-microarch:native");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (check) {
|
||||
print_usage_line(1, "-disallow-do");
|
||||
print_usage_line(2, "Disallows the 'do' keyword in the project");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-default-to-nil-allocator");
|
||||
print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
@@ -1632,6 +1666,127 @@ void print_show_help(String const arg0, String const &command) {
|
||||
}
|
||||
}
|
||||
|
||||
int unused_entity_kind_ordering[Entity_Count] = {
|
||||
/*Invalid*/ -1,
|
||||
/*Constant*/ 0,
|
||||
/*Variable*/ 1,
|
||||
/*TypeName*/ 4,
|
||||
/*Procedure*/ 2,
|
||||
/*ProcGroup*/ 3,
|
||||
/*Builtin*/ -1,
|
||||
/*ImportName*/ -1,
|
||||
/*LibraryName*/ -1,
|
||||
/*Nil*/ -1,
|
||||
/*Label*/ -1,
|
||||
};
|
||||
char const *unused_entity_names[Entity_Count] = {
|
||||
/*Invalid*/ "",
|
||||
/*Constant*/ "constants",
|
||||
/*Variable*/ "variables",
|
||||
/*TypeName*/ "types",
|
||||
/*Procedure*/ "procedures",
|
||||
/*ProcGroup*/ "proc_group",
|
||||
/*Builtin*/ "",
|
||||
/*ImportName*/ "import names",
|
||||
/*LibraryName*/ "library names",
|
||||
/*Nil*/ "",
|
||||
/*Label*/ "",
|
||||
};
|
||||
|
||||
|
||||
GB_COMPARE_PROC(cmp_entities_for_unused) {
|
||||
GB_ASSERT(a != nullptr);
|
||||
GB_ASSERT(b != nullptr);
|
||||
Entity *x = *cast(Entity **)a;
|
||||
Entity *y = *cast(Entity **)b;
|
||||
int res = 0;
|
||||
res = string_compare(x->pkg->name, y->pkg->name);
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
int ox = unused_entity_kind_ordering[x->kind];
|
||||
int oy = unused_entity_kind_ordering[y->kind];
|
||||
if (ox < oy) {
|
||||
return -1;
|
||||
} else if (ox > oy) {
|
||||
return +1;
|
||||
}
|
||||
res = string_compare(x->token.string, y->token.string);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void print_show_unused(Checker *c) {
|
||||
CheckerInfo *info = &c->info;
|
||||
|
||||
auto unused = array_make<Entity *>(permanent_allocator(), 0, info->entities.count);
|
||||
for_array(i, info->entities) {
|
||||
Entity *e = info->entities[i];
|
||||
if (e == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (e->pkg == nullptr || e->pkg->scope == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (e->pkg->scope->flags & ScopeFlag_Builtin) {
|
||||
continue;
|
||||
}
|
||||
switch (e->kind) {
|
||||
case Entity_Invalid:
|
||||
case Entity_Builtin:
|
||||
case Entity_Nil:
|
||||
case Entity_Label:
|
||||
continue;
|
||||
case Entity_Constant:
|
||||
case Entity_Variable:
|
||||
case Entity_TypeName:
|
||||
case Entity_Procedure:
|
||||
case Entity_ProcGroup:
|
||||
case Entity_ImportName:
|
||||
case Entity_LibraryName:
|
||||
// Fine
|
||||
break;
|
||||
}
|
||||
if ((e->scope->flags & (ScopeFlag_Pkg|ScopeFlag_File)) == 0) {
|
||||
continue;
|
||||
}
|
||||
if (e->token.string.len == 0) {
|
||||
continue;
|
||||
}
|
||||
if (e->token.string == "_") {
|
||||
continue;
|
||||
}
|
||||
if (ptr_set_exists(&info->minimum_dependency_set, e)) {
|
||||
continue;
|
||||
}
|
||||
array_add(&unused, e);
|
||||
}
|
||||
|
||||
gb_sort_array(unused.data, unused.count, cmp_entities_for_unused);
|
||||
|
||||
print_usage_line(0, "Unused Package Declarations");
|
||||
|
||||
AstPackage *curr_pkg = nullptr;
|
||||
EntityKind curr_entity_kind = Entity_Invalid;
|
||||
for_array(i, unused) {
|
||||
Entity *e = unused[i];
|
||||
if (curr_pkg != e->pkg) {
|
||||
curr_pkg = e->pkg;
|
||||
curr_entity_kind = Entity_Invalid;
|
||||
print_usage_line(0, "");
|
||||
print_usage_line(0, "package %.*s", LIT(curr_pkg->name));
|
||||
}
|
||||
if (curr_entity_kind != e->kind) {
|
||||
curr_entity_kind = e->kind;
|
||||
print_usage_line(1, "%s", unused_entity_names[e->kind]);
|
||||
}
|
||||
// TokenPos pos = e->token.pos;
|
||||
// print_usage_line(2, "%.*s(%td:%td) %.*s", LIT(pos.file), pos.line, pos.column, LIT(e->token.string));
|
||||
print_usage_line(2, "%.*s", LIT(e->token.string));
|
||||
}
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
int main(int arg_count, char const **arg_ptr) {
|
||||
if (arg_count < 2) {
|
||||
usage(make_string_c(arg_ptr[0]));
|
||||
@@ -1821,6 +1976,10 @@ int main(int arg_count, char const **arg_ptr) {
|
||||
temp_allocator_free_all(&temporary_allocator_data);
|
||||
|
||||
if (build_context.no_output_files) {
|
||||
if (build_context.show_unused) {
|
||||
print_show_unused(&checker);
|
||||
}
|
||||
|
||||
if (build_context.query_data_set_settings.ok) {
|
||||
generate_and_print_query_data(&checker, timings);
|
||||
} else {
|
||||
|
||||
@@ -1099,7 +1099,7 @@ Ast *ast_label_decl(AstFile *f, Token token, Ast *name) {
|
||||
}
|
||||
|
||||
Ast *ast_value_decl(AstFile *f, Array<Ast *> const &names, Ast *type, Array<Ast *> const &values, bool is_mutable,
|
||||
CommentGroup *docs, CommentGroup *comment) {
|
||||
CommentGroup *docs, CommentGroup *comment) {
|
||||
Ast *result = alloc_ast_node(f, Ast_ValueDecl);
|
||||
result->ValueDecl.names = slice_from_array(names);
|
||||
result->ValueDecl.type = type;
|
||||
@@ -1122,7 +1122,7 @@ Ast *ast_package_decl(AstFile *f, Token token, Token name, CommentGroup *docs, C
|
||||
}
|
||||
|
||||
Ast *ast_import_decl(AstFile *f, Token token, bool is_using, Token relpath, Token import_name,
|
||||
CommentGroup *docs, CommentGroup *comment) {
|
||||
CommentGroup *docs, CommentGroup *comment) {
|
||||
Ast *result = alloc_ast_node(f, Ast_ImportDecl);
|
||||
result->ImportDecl.token = token;
|
||||
result->ImportDecl.is_using = is_using;
|
||||
@@ -1134,7 +1134,7 @@ Ast *ast_import_decl(AstFile *f, Token token, bool is_using, Token relpath, Toke
|
||||
}
|
||||
|
||||
Ast *ast_foreign_import_decl(AstFile *f, Token token, Array<Token> filepaths, Token library_name,
|
||||
CommentGroup *docs, CommentGroup *comment) {
|
||||
CommentGroup *docs, CommentGroup *comment) {
|
||||
Ast *result = alloc_ast_node(f, Ast_ForeignImportDecl);
|
||||
result->ForeignImportDecl.token = token;
|
||||
result->ForeignImportDecl.filepaths = slice_from_array(filepaths);
|
||||
|
||||
@@ -24,6 +24,7 @@ struct PtrSet {
|
||||
template <typename T> void ptr_set_init (PtrSet<T> *s, gbAllocator a, isize capacity = 16);
|
||||
template <typename T> void ptr_set_destroy(PtrSet<T> *s);
|
||||
template <typename T> T ptr_set_add (PtrSet<T> *s, T ptr);
|
||||
template <typename T> bool ptr_set_update (PtrSet<T> *s, T ptr); // returns true if it previously existsed
|
||||
template <typename T> bool ptr_set_exists (PtrSet<T> *s, T ptr);
|
||||
template <typename T> void ptr_set_remove (PtrSet<T> *s, T ptr);
|
||||
template <typename T> void ptr_set_clear (PtrSet<T> *s);
|
||||
@@ -152,9 +153,7 @@ T ptr_set_add(PtrSet<T> *s, T ptr) {
|
||||
ptr_set_grow(s);
|
||||
}
|
||||
fr = ptr_set__find(s, ptr);
|
||||
if (fr.entry_index != PTR_SET_SENTINEL) {
|
||||
index = fr.entry_index;
|
||||
} else {
|
||||
if (fr.entry_index == PTR_SET_SENTINEL) {
|
||||
index = ptr_set__add_entry(s, ptr);
|
||||
if (fr.entry_prev != PTR_SET_SENTINEL) {
|
||||
s->entries.data[fr.entry_prev].next = index;
|
||||
@@ -168,6 +167,32 @@ T ptr_set_add(PtrSet<T> *s, T ptr) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool ptr_set_update(PtrSet<T> *s, T ptr) { // returns true if it previously existsed
|
||||
bool exists = false;
|
||||
PtrSetIndex index;
|
||||
PtrSetFindResult fr;
|
||||
if (s->hashes.count == 0) {
|
||||
ptr_set_grow(s);
|
||||
}
|
||||
fr = ptr_set__find(s, ptr);
|
||||
if (fr.entry_index != PTR_SET_SENTINEL) {
|
||||
exists = true;
|
||||
} else {
|
||||
index = ptr_set__add_entry(s, ptr);
|
||||
if (fr.entry_prev != PTR_SET_SENTINEL) {
|
||||
s->entries.data[fr.entry_prev].next = index;
|
||||
} else {
|
||||
s->hashes.data[fr.hash_index] = index;
|
||||
}
|
||||
}
|
||||
if (ptr_set__full(s)) {
|
||||
ptr_set_grow(s);
|
||||
}
|
||||
return exists;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
void ptr_set__erase(PtrSet<T> *s, PtrSetFindResult fr) {
|
||||
|
||||
Reference in New Issue
Block a user