Sfoglia il codice sorgente

Add `-show-unused` (Shows unused package declarations of all imported packages)

Crude output at the moment but better than nothing
gingerBill 5 anni fa
parent
commit
6f71d1f2a9
7 ha cambiato i file con 207 aggiunte e 32 eliminazioni
  1. 1 0
      src/build_settings.cpp
  2. 1 2
      src/check_decl.cpp
  3. 9 19
      src/checker.cpp
  4. 7 6
      src/checker.hpp
  5. 159 0
      src/main.cpp
  6. 3 3
      src/parser.cpp
  7. 27 2
      src/ptr_set.cpp

+ 1 - 0
src/build_settings.cpp

@@ -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;

+ 1 - 2
src/check_decl.cpp

@@ -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);
 	}
 

+ 9 - 19
src/checker.cpp

@@ -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);
 	}

+ 7 - 6
src/checker.hpp

@@ -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 - 0
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 {

+ 3 - 3
src/parser.cpp

@@ -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);

+ 27 - 2
src/ptr_set.cpp

@@ -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);
@@ -146,6 +147,29 @@ gb_inline bool ptr_set_exists(PtrSet<T> *s, T ptr) {
 // Returns true if it already exists
 template <typename T>
 T ptr_set_add(PtrSet<T> *s, T ptr) {
+	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) {
+		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 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) {
@@ -153,7 +177,7 @@ T ptr_set_add(PtrSet<T> *s, T ptr) {
 	}
 	fr = ptr_set__find(s, ptr);
 	if (fr.entry_index != PTR_SET_SENTINEL) {
-		index = fr.entry_index;
+		exists = true;
 	} else {
 		index = ptr_set__add_entry(s, ptr);
 		if (fr.entry_prev != PTR_SET_SENTINEL) {
@@ -165,10 +189,11 @@ T ptr_set_add(PtrSet<T> *s, T ptr) {
 	if (ptr_set__full(s)) {
 		ptr_set_grow(s);
 	}
-	return ptr;
+	return exists;
 }
 
 
+
 template <typename T>
 void ptr_set__erase(PtrSet<T> *s, PtrSetFindResult fr) {
 	PtrSetFindResult last;