mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-07 16:18:52 +00:00
-vet flag to do basic vetting of code
This commit is contained in:
+3
-4
@@ -843,7 +843,6 @@ fmt_bit_set :: proc(fi: ^Fmt_Info, v: any, name: string = "") {
|
|||||||
case runtime.Type_Info_Bit_Set:
|
case runtime.Type_Info_Bit_Set:
|
||||||
bits: u64;
|
bits: u64;
|
||||||
bit_size := u64(8*type_info.size);
|
bit_size := u64(8*type_info.size);
|
||||||
verb := 'b';
|
|
||||||
|
|
||||||
switch bit_size {
|
switch bit_size {
|
||||||
case 0: bits = 0;
|
case 0: bits = 0;
|
||||||
@@ -886,7 +885,7 @@ fmt_bit_set :: proc(fi: ^Fmt_Info, v: any, name: string = "") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt_bit_field :: proc(fi: ^Fmt_Info, v: any, name: string = "") {
|
fmt_bit_field :: proc(fi: ^Fmt_Info, v: any, bit_field_name: string = "") {
|
||||||
type_info := type_info_of(v.id);
|
type_info := type_info_of(v.id);
|
||||||
switch info in type_info.variant {
|
switch info in type_info.variant {
|
||||||
case runtime.Type_Info_Named:
|
case runtime.Type_Info_Named:
|
||||||
@@ -902,8 +901,8 @@ fmt_bit_field :: proc(fi: ^Fmt_Info, v: any, name: string = "") {
|
|||||||
case 8: data = cast(u64)(^u64)(v.data)^;
|
case 8: data = cast(u64)(^u64)(v.data)^;
|
||||||
}
|
}
|
||||||
|
|
||||||
if name != "" {
|
if bit_field_name != "" {
|
||||||
write_string(fi.buf, name);
|
write_string(fi.buf, bit_field_name);
|
||||||
write_byte(fi.buf, '{');
|
write_byte(fi.buf, '{');
|
||||||
} else {
|
} else {
|
||||||
write_string(fi.buf, "bit_field{");
|
write_string(fi.buf, "bit_field{");
|
||||||
|
|||||||
+2
-2
@@ -226,9 +226,9 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
case Allocator_Mode.Free:
|
case Allocator_Mode.Free:
|
||||||
last_ptr := rawptr(&scratch.data[scratch.prev_offset]);
|
last_ptr := rawptr(&scratch.data[scratch.prev_offset]);
|
||||||
if old_memory == last_ptr {
|
if old_memory == last_ptr {
|
||||||
size := scratch.curr_offset - scratch.prev_offset;
|
full_size := scratch.curr_offset - scratch.prev_offset;
|
||||||
scratch.curr_offset = scratch.prev_offset;
|
scratch.curr_offset = scratch.prev_offset;
|
||||||
zero(last_ptr, size);
|
zero(last_ptr, full_size);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
// NOTE(bill): It's scratch memory, don't worry about freeing
|
// NOTE(bill): It's scratch memory, don't worry about freeing
|
||||||
|
|||||||
@@ -408,7 +408,6 @@ parametric_polymorphism :: proc() {
|
|||||||
}
|
}
|
||||||
assert(table.count <= len(table.slots));
|
assert(table.count <= len(table.slots));
|
||||||
|
|
||||||
hash := get_hash(key);
|
|
||||||
index = int(hash % u32(len(table.slots)));
|
index = int(hash % u32(len(table.slots)));
|
||||||
|
|
||||||
for table.slots[index].occupied {
|
for table.slots[index].occupied {
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ struct BuildContext {
|
|||||||
bool no_output_files;
|
bool no_output_files;
|
||||||
bool no_crt;
|
bool no_crt;
|
||||||
bool use_lld;
|
bool use_lld;
|
||||||
|
bool vet;
|
||||||
|
|
||||||
gbAffinity affinity;
|
gbAffinity affinity;
|
||||||
isize thread_count;
|
isize thread_count;
|
||||||
|
|||||||
+140
-19
@@ -320,6 +320,8 @@ void check_open_scope(CheckerContext *c, Ast *node) {
|
|||||||
case Ast_StructType:
|
case Ast_StructType:
|
||||||
case Ast_EnumType:
|
case Ast_EnumType:
|
||||||
case Ast_UnionType:
|
case Ast_UnionType:
|
||||||
|
case Ast_BitFieldType:
|
||||||
|
case Ast_BitSetType:
|
||||||
scope->flags |= ScopeFlag_Type;
|
scope->flags |= ScopeFlag_Type;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -413,41 +415,160 @@ GB_COMPARE_PROC(entity_variable_pos_cmp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void check_scope_usage(Checker *c, Scope *scope) {
|
enum VettedEntityKind {
|
||||||
// TODO(bill): Use this?
|
VettedEntity_Invalid,
|
||||||
#if 0
|
|
||||||
Array<Entity *> unused = {};
|
|
||||||
array_init(&unused, heap_allocator());
|
|
||||||
defer (array_free(&unused));
|
|
||||||
|
|
||||||
for_array(i, scope->elements.entries) {
|
VettedEntity_Unused,
|
||||||
Entity *e = scope->elements.entries[i].value;
|
VettedEntity_Shadowed,
|
||||||
if (e != nullptr && (e->flags&EntityFlag_Used) == 0) {
|
};
|
||||||
|
struct VettedEntity {
|
||||||
|
VettedEntityKind kind;
|
||||||
|
Entity *entity;
|
||||||
|
Entity *other;
|
||||||
|
};
|
||||||
|
void init_vetted_entity(VettedEntity *ve, VettedEntityKind kind, Entity *entity, Entity *other=nullptr) {
|
||||||
|
ve->kind = kind;
|
||||||
|
ve->entity = entity;
|
||||||
|
ve->other = other;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GB_COMPARE_PROC(vetted_entity_variable_pos_cmp) {
|
||||||
|
Entity *x = (*cast(VettedEntity **)a)->entity;
|
||||||
|
Entity *y = (*cast(VettedEntity **)b)->entity;
|
||||||
|
|
||||||
|
return token_pos_cmp(x->token.pos, y->token.pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool check_vet_shadowing(Checker *c, Entity *e, VettedEntity *ve) {
|
||||||
|
if (e->kind != Entity_Variable) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String name = e->token.string;
|
||||||
|
if (name == "_") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (e->flags & EntityFlag_Param) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e->scope->flags & (ScopeFlag_Global|ScopeFlag_File|ScopeFlag_Proc)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scope *parent = e->scope->parent;
|
||||||
|
if (parent->flags & (ScopeFlag_Global|ScopeFlag_File)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity *shadowed = scope_lookup(parent, name);
|
||||||
|
if (shadowed == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (shadowed->kind != Entity_Variable) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shadowed->scope->flags & (ScopeFlag_Global|ScopeFlag_File)) {
|
||||||
|
// return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(bill): The entities must be in the same file
|
||||||
|
if (e->token.pos.file != shadowed->token.pos.file) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// NOTE(bill): The shaded identifier must appear before this one to be an
|
||||||
|
// instance of shadowing
|
||||||
|
if (token_pos_cmp(shadowed->token.pos, e->token.pos) > 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// NOTE(bill): If the types differ, don't complain
|
||||||
|
if (are_types_identical(e->type, shadowed->type)) {
|
||||||
|
gb_zero_item(ve);
|
||||||
|
ve->kind = VettedEntity_Shadowed;
|
||||||
|
ve->entity = e;
|
||||||
|
ve->other = shadowed;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check_vet_unused(Checker *c, Entity *e, VettedEntity *ve) {
|
||||||
|
if ((e->flags&EntityFlag_Used) == 0) {
|
||||||
switch (e->kind) {
|
switch (e->kind) {
|
||||||
case Entity_Variable:
|
case Entity_Variable:
|
||||||
case Entity_ImportName:
|
case Entity_ImportName:
|
||||||
case Entity_LibraryName:
|
case Entity_LibraryName:
|
||||||
array_add(&unused, e);
|
gb_zero_item(ve);
|
||||||
|
ve->kind = VettedEntity_Unused;
|
||||||
|
ve->entity = e;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_scope_usage(Checker *c, Scope *scope) {
|
||||||
|
if (!build_context.vet) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vet_unused = true;
|
||||||
|
bool vet_shadowing = true;
|
||||||
|
|
||||||
|
Array<VettedEntity> vetted_entities = {};
|
||||||
|
array_init(&vetted_entities, heap_allocator());
|
||||||
|
|
||||||
|
for_array(i, scope->elements.entries) {
|
||||||
|
Entity *e = scope->elements.entries[i].value;
|
||||||
|
if (e == nullptr) continue;
|
||||||
|
VettedEntity ve = {};
|
||||||
|
if (vet_unused && check_vet_unused(c, e, &ve)) {
|
||||||
|
array_add(&vetted_entities, ve);
|
||||||
|
}
|
||||||
|
if (vet_shadowing && check_vet_shadowing(c, e, &ve)) {
|
||||||
|
array_add(&vetted_entities, ve);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gb_sort_array(vetted_entities.data, vetted_entities.count, vetted_entity_variable_pos_cmp);
|
||||||
|
|
||||||
|
for_array(i, vetted_entities) {
|
||||||
|
auto ve = vetted_entities[i];
|
||||||
|
Entity *e = ve.entity;
|
||||||
|
Entity *other = ve.other;
|
||||||
|
String name = e->token.string;
|
||||||
|
|
||||||
|
switch (ve.kind) {
|
||||||
|
case VettedEntity_Unused:
|
||||||
|
error(e->token, "'%.*s' declared but not used", LIT(name));
|
||||||
|
break;
|
||||||
|
case VettedEntity_Shadowed:
|
||||||
|
if (e->flags&EntityFlag_Using) {
|
||||||
|
error(e->token, "Declaration of '%.*s' from 'using' shadows declaration at line %lld", LIT(name), cast(long long)other->token.pos.line);
|
||||||
|
} else {
|
||||||
|
error(e->token, "Declaration of '%.*s' shadows declaration at line %lld", LIT(name), cast(long long)other->token.pos.line);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
gb_sort_array(unused.data, unused.count, entity_variable_pos_cmp);
|
array_free(&vetted_entities);
|
||||||
|
|
||||||
for_array(i, unused) {
|
|
||||||
Entity *e = unused[i];
|
|
||||||
error(e->token, "'%.*s' declared but not used", LIT(e->token.string));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Scope *child = scope->first_child;
|
for (Scope *child = scope->first_child;
|
||||||
child != nullptr;
|
child != nullptr;
|
||||||
child = child->next) {
|
child = child->next) {
|
||||||
if (!child->is_proc && !child->is_struct && !child->is_file) {
|
if (child->flags & (ScopeFlag_Proc|ScopeFlag_Type|ScopeFlag_File)) {
|
||||||
|
// Ignore these
|
||||||
|
} else {
|
||||||
check_scope_usage(c, child);
|
check_scope_usage(c, child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -349,7 +349,6 @@ enum ScopeFlag {
|
|||||||
ScopeFlag_Proc = 1<<5,
|
ScopeFlag_Proc = 1<<5,
|
||||||
ScopeFlag_Type = 1<<6,
|
ScopeFlag_Type = 1<<6,
|
||||||
|
|
||||||
|
|
||||||
ScopeFlag_HasBeenImported = 1<<10, // This is only applicable to file scopes
|
ScopeFlag_HasBeenImported = 1<<10, // This is only applicable to file scopes
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -214,6 +214,7 @@ enum BuildFlagKind {
|
|||||||
BuildFlag_NoBoundsCheck,
|
BuildFlag_NoBoundsCheck,
|
||||||
BuildFlag_NoCRT,
|
BuildFlag_NoCRT,
|
||||||
BuildFlag_UseLLD,
|
BuildFlag_UseLLD,
|
||||||
|
BuildFlag_Vet,
|
||||||
|
|
||||||
BuildFlag_COUNT,
|
BuildFlag_COUNT,
|
||||||
};
|
};
|
||||||
@@ -256,6 +257,7 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None);
|
add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None);
|
||||||
add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None);
|
add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None);
|
||||||
add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None);
|
add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None);
|
||||||
|
add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None);
|
||||||
|
|
||||||
GB_ASSERT(args.count >= 3);
|
GB_ASSERT(args.count >= 3);
|
||||||
Array<String> flag_args = array_slice(args, 3, args.count);
|
Array<String> flag_args = array_slice(args, 3, args.count);
|
||||||
@@ -563,6 +565,10 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
case BuildFlag_UseLLD:
|
case BuildFlag_UseLLD:
|
||||||
build_context.use_lld = true;
|
build_context.use_lld = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BuildFlag_Vet:
|
||||||
|
build_context.vet = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user