Skip to content

Commit 38afce3

Browse files
committed
Issue warnings on some potential name conflicts
1 parent 824ecbf commit 38afce3

File tree

8 files changed

+263
-8
lines changed

8 files changed

+263
-8
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@
6363
- Fix GCC 15 warning in grisu3 (#338).
6464
- Bump CMake to >= 3.26.1 (Debian Bookworm).
6565
- Fix CMAKE warnings on custom commands with TARGET and DEPENDS (CMP0175).
66+
- Issue warnings on some potential name conflicts that can break C source
67+
and add `-s` option to silence warnings (#354).
6668

6769
## [0.6.1]
6870

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,10 @@ that for clang debug builds, -fsanitize=undefined has been added and this may
330330
require dependent source code to also use that flag to avoid missing linker
331331
symbols. The feature can be disabled in CMakeLists.txt. CMake has been bumped to
332332
version 3.16 which is the latest version where Appveyor will build MVSC 2015.
333+
Warnings added for potential name conflicts in enum names and table fields
334+
that could result in confusing C compiler errors. Not all warnigs are errors
335+
to the option `-s` was also added to silence warnings. The existing `-g`
336+
option can resolve some conflicts.
333337

334338
Release 0.6.1 contains primarily bug fixes and numerous contributions from the
335339
community to handle platform edge cases. Additionally, pendantic GCC warnings
@@ -1208,6 +1212,10 @@ If unfortunate, it is possible to have a read accessor method conflict
12081212
with other generated methods and typenames. Usually a small change in
12091213
the schema will resolve this issue.
12101214

1215+
As of flatcc 0.6.2 conservative warnings will detect most likely
1216+
potential conflicts in enum member names and table field names. The
1217+
`-s` option silences warnings.
1218+
12111219
As of flatcc 0.5.2 read accors are generated with and without a `_get`
12121220
suffix so it is also possible to use `Monster_pos_get(monster)` instead
12131221
of `Monster_pos(monster)`. When calling flatcc with option `-g` the

include/flatcc/flatcc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ struct flatcc_options {
5454
int bool_size;
5555
int require_root_type;
5656
int strict_enum_init;
57+
int silence;
5758
uint64_t vt_max_count;
5859

5960
const char *default_schema_ext;

src/cli/flatcc_cli.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ void usage(FILE *fp)
2323
" -r, --recursive Recursively generate included schema files\n"
2424
" -a Generate all (like -cwvr)\n"
2525
" -g Use _get suffix only to avoid conflicts\n"
26+
" -s Silence warnings\n"
2627
" -d Dependency file like gcc -MMD\n"
2728
" -I<inpath> Search path for include files (multiple allowed)\n"
2829
" -o<outpath> Write files relative to this path (dir must exist)\n"
@@ -83,6 +84,11 @@ void help(FILE *fp)
8384
"'Monster_name(monster)'. This avoids potential conflicts with\n"
8485
"other generated symbols when a schema change is impractical.\n"
8586
"\n"
87+
"-s Silence warnings, notably on potential conflicts that might cause\n"
88+
"C source code to generate errors. These warnings are not perfect and can\n"
89+
"be ignored if the C code compiles, though it is recommended to change\n"
90+
"names in the schema if possible.\n"
91+
"\n"
8692
"-d generates a dependency file, e.g. 'monster.fbs.d' in the output dir.\n"
8793
"\n"
8894
"--depfile implies -d but accepts an explicit filename with a path\n"
@@ -344,6 +350,9 @@ int set_opt(flatcc_options_t *opts, const char *s, const char *a)
344350
case 'g':
345351
opts->cgen_no_conflicts = 1;
346352
return noarg;
353+
case 's':
354+
opts->silence = 1;
355+
return noarg;
347356
case 'd':
348357
opts->gen_dep = 1;
349358
return noarg;

src/compiler/parser.c

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,14 @@ const char *error_find_file_of_token(fb_parser_t *P, fb_token_t *t)
5858
return "";
5959
}
6060

61-
void error_report(fb_parser_t *P, fb_token_t *t, const char *msg, fb_token_t *peer, const char *s, size_t len)
61+
void error_report_ext(fb_parser_t *P, fb_token_t *t, const char *msg, fb_token_t *peer, const char *s, size_t len, int is_warning)
6262
{
6363
const char *file, *peer_file;
64+
const char *kind = is_warning ? "warning" : "error";
6465

66+
if (is_warning && P->opts.silence) {
67+
return;
68+
}
6569
if (t && !s) {
6670
s = t->text;
6771
len = (size_t)t->len;
@@ -75,25 +79,37 @@ void error_report(fb_parser_t *P, fb_token_t *t, const char *msg, fb_token_t *pe
7579
}
7680
if (t && !peer) {
7781
file = error_find_file_of_token(P, t);
78-
fb_print_error(P, "%s:%ld:%ld: error: '%.*s': %s\n",
79-
file, (long)t->linenum, (long)t->pos, len, s, msg);
82+
fb_print_error(P, "%s:%ld:%ld: %s: '%.*s': %s\n",
83+
file, (long)t->linenum, (long)t->pos, kind, len, s, msg);
8084
} else if (t && peer) {
8185
file = error_find_file_of_token(P, t);
8286
peer_file = error_find_file_of_token(P, peer);
83-
fb_print_error(P, "%s:%ld:%ld: error: '%.*s': %s: %s:%ld:%ld: '%.*s'\n",
84-
file, (long)t->linenum, (long)t->pos, len, s, msg,
87+
fb_print_error(P, "%s:%ld:%ld: %s: '%.*s': %s: %s:%ld:%ld: '%.*s'\n",
88+
file, (long)t->linenum, (long)t->pos, kind, len, s, msg,
8589
peer_file, (long)peer->linenum, (long)peer->pos, (int)peer->len, peer->text);
8690
} else if (!t && !peer) {
8791
fb_print_error(P, "error: %s\n", msg);
8892
} else if (peer) {
8993
peer_file = error_find_file_of_token(P, peer);
90-
fb_print_error(P, "error: %s: %s:%ld:%ld: '%.*s'\n",
91-
msg,
94+
fb_print_error(P, "%s: %s: %s:%ld:%ld: '%.*s'\n",
95+
kind, msg,
9296
peer_file, (long)peer->linenum, (long)peer->pos, (int)peer->len, peer->text);
9397
} else {
9498
fb_print_error(P, "internal error: unexpected state\n");
9599
}
96-
++P->failed;
100+
if (!is_warning) {
101+
++P->failed;
102+
}
103+
}
104+
105+
void error_report(fb_parser_t *P, fb_token_t *t, const char *msg, fb_token_t *peer, const char *s, size_t len)
106+
{
107+
error_report_ext(P, t, msg, peer, s, len, 0);
108+
}
109+
110+
void warn_report(fb_parser_t *P, fb_token_t *t, const char *msg, fb_token_t *peer, const char *s, size_t len)
111+
{
112+
error_report_ext(P, t, msg, peer, s, len, 1);
97113
}
98114

99115
void error_ref_sym(fb_parser_t *P, fb_ref_t *ref, const char *msg, fb_symbol_t *s2)

src/compiler/parser.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ const char *__flatcc_error_find_file_of_token(fb_parser_t *P, fb_token_t *t);
127127
void __flatcc_error_report(fb_parser_t *P, fb_token_t *t, const char *msg, fb_token_t *peer, const char *s, size_t len);
128128
#define error_report __flatcc_error_report
129129

130+
void __flatcc_warn_report(fb_parser_t *P, fb_token_t *t, const char *msg, fb_token_t *peer, const char *s, size_t len);
131+
#define warn_report __flatcc_warn_report
132+
130133
static void error_tok_2(fb_parser_t *P, fb_token_t *t, const char *msg, fb_token_t *peer)
131134
{
132135
error_report(P, t, msg, peer, 0, 0);
@@ -137,6 +140,17 @@ static inline void error_tok(fb_parser_t *P, fb_token_t *t, const char *msg)
137140
error_tok_2(P, t, msg, 0);
138141
}
139142

143+
static inline void warn_tok(fb_parser_t *P, fb_token_t *t, const char *msg)
144+
{
145+
warn_report(P, t, msg, 0, 0, 0);
146+
}
147+
148+
/* Show both token and string */
149+
static inline void warn_tok_as_string(fb_parser_t *P, fb_token_t *t, const char *msg, const char *s, size_t len)
150+
{
151+
warn_report(P, t, msg, 0, s, len);
152+
}
153+
140154
/* Only use the token location. */
141155
static inline void error_tok_as_string(fb_parser_t *P, fb_token_t *t, const char *msg, char *s, size_t len)
142156
{

src/compiler/semantics.c

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,87 @@ static const char *fb_known_attribute_names[] = {
2929
"sorted",
3030
};
3131

32+
static const char *fb_reserved_kw_enum_members[] = {
33+
"_const_ptr_add",
34+
"_ptr_add",
35+
"_size",
36+
"array_copy",
37+
"array_copy_from_pe",
38+
"array_copy_to_pe",
39+
"assign",
40+
"assign_from_pe",
41+
"assign_to_pe",
42+
"cast_from_be",
43+
"cast_from_le",
44+
"cast_from_pe",
45+
"cast_to_be",
46+
"cast_to_le",
47+
"cast_to_pe",
48+
"copy",
49+
"copy_from_pe",
50+
"copy_to_pe",
51+
"enum_t",
52+
"from_pe",
53+
"is_known_value",
54+
"name",
55+
"parse_json_enum",
56+
"print_json_enum",
57+
"read",
58+
"read_from_pe",
59+
"read_to_pe",
60+
"to_pe",
61+
// "vec_*",
62+
"write",
63+
"write_from_pe",
64+
"write_to_pe",
65+
};
66+
67+
static const char *fb_reserved_kw_table_fields[] = {
68+
"add_type",
69+
"add_value",
70+
"begin",
71+
"clone",
72+
"create",
73+
"end",
74+
"end_pe",
75+
"force_add",
76+
"table_t",
77+
"verity_table",
78+
};
79+
80+
static const char *fb_reserved_kw_table_field_prefixes[] = {
81+
"as_",
82+
"clone_as_",
83+
"create_as_",
84+
"end_as_",
85+
"parse_json_",
86+
"print_json_",
87+
"start_as_",
88+
// "vec_ ",
89+
"verify_as_*",
90+
};
91+
92+
static const char *fb_reserved_kw_table_field_suffixes[] = {
93+
"_add",
94+
"_clone",
95+
"_create",
96+
"_end",
97+
"_get",
98+
"_get_ptr",
99+
"_force_add",
100+
"_is_present",
101+
"_pick",
102+
"_push_start",
103+
"_push_end",
104+
"_push_create",
105+
"_start",
106+
};
107+
108+
/* For table and enum members. */
109+
static const char *fb_reserved_kw_vec_prefixes[] = {
110+
"vec_",
111+
};
112+
32113
static const int fb_known_attribute_types[] = {
33114
vt_invalid, /* Unknowns have arbitrary types. */
34115
vt_uint,
@@ -396,6 +477,110 @@ static void install_known_attributes(fb_parser_t *P)
396477
}
397478
}
398479

480+
static void install_reserved_keyword_table(fb_parser_t *P, const char *table[], size_t count, int kind)
481+
{
482+
fb_reserved_kw_t *kw;
483+
size_t i;
484+
485+
for (i = 0; i < count; ++i) {
486+
kw = new_elem(P, sizeof(*kw));
487+
kw->name.name.s.s = (char *)table[i];
488+
kw->name.name.s.len = (int)strlen(table[i]);
489+
kw->name.link = 0;
490+
kw->kind = kind;
491+
define_fb_name(&P->schema.root_schema->keyword_index, &kw->name);
492+
}
493+
}
494+
495+
#define KW_TABLE_LEN(T) (sizeof(T)/sizeof(T[0]))
496+
497+
static void install_reserved_keywords(fb_parser_t *P)
498+
{
499+
install_reserved_keyword_table(P, fb_reserved_kw_enum_members,
500+
KW_TABLE_LEN(fb_reserved_kw_enum_members),
501+
fb_reserved_kw_kind_enum_member);
502+
install_reserved_keyword_table(P, fb_reserved_kw_table_fields,
503+
KW_TABLE_LEN(fb_reserved_kw_table_fields),
504+
fb_reserved_kw_kind_table_field);
505+
install_reserved_keyword_table(P, fb_reserved_kw_table_field_prefixes,
506+
KW_TABLE_LEN(fb_reserved_kw_table_field_prefixes),
507+
fb_reserved_kw_kind_table_field_prefix);
508+
install_reserved_keyword_table(P, fb_reserved_kw_table_field_suffixes,
509+
KW_TABLE_LEN(fb_reserved_kw_table_field_suffixes),
510+
fb_reserved_kw_kind_table_field_suffix);
511+
install_reserved_keyword_table(P, fb_reserved_kw_vec_prefixes,
512+
KW_TABLE_LEN(fb_reserved_kw_vec_prefixes),
513+
fb_reserved_kw_kind_vec_prefix);
514+
}
515+
516+
static void check_reserved_enum_member(fb_parser_t *P, fb_symbol_t *sym)
517+
{
518+
const char *text = sym->ident->text;
519+
size_t len = (size_t)sym->ident->len;
520+
fb_reserved_kw_t *kw = 0;
521+
size_t i;
522+
523+
kw = (fb_reserved_kw_t *)fb_name_table_find(&P->schema.root_schema->keyword_index,
524+
text, len);
525+
if (kw && kw->kind == fb_reserved_kw_kind_enum_member) {
526+
warn_tok(P, sym->ident, "potential enum member name conflict in C source");
527+
warn_tok_as_string(P, sym->ident, "name is reserved", kw->name.name.s.s, (size_t)kw->name.name.s.len);
528+
return;
529+
}
530+
for (i = 0; i < len; ++i) {
531+
if (text[i] =='_') {
532+
if (i + 1 < len) {
533+
kw = (fb_reserved_kw_t *)fb_name_table_find(&P->schema.root_schema->keyword_index,
534+
text, i + 1);
535+
if (kw && (kw->kind == fb_reserved_kw_kind_vec_prefix)) {
536+
warn_tok(P, sym->ident, "potential enum member name conflict in C source");
537+
warn_tok_as_string(P, sym->ident, "prefix is reserved", kw->name.name.s.s, (size_t)kw->name.name.s.len);
538+
return;
539+
}
540+
}
541+
}
542+
}
543+
}
544+
545+
static void check_reserved_table_field(fb_parser_t *P, fb_symbol_t *sym)
546+
{
547+
const char *text = sym->ident->text;
548+
size_t len = (size_t)sym->ident->len;
549+
fb_reserved_kw_t *kw = 0;
550+
size_t i;
551+
552+
kw = (fb_reserved_kw_t *)fb_name_table_find(&P->schema.root_schema->keyword_index,
553+
text, len);
554+
if (kw && kw->kind == fb_reserved_kw_kind_table_field) {
555+
warn_tok(P, sym->ident, "potential table field conflict in C source (option -g might help)");
556+
warn_tok_as_string(P, sym->ident, "name is reserved", kw->name.name.s.s, (size_t)kw->name.name.s.len);
557+
return;
558+
}
559+
for (i = 0; i < len; ++i) {
560+
if (text[i] =='_') {
561+
if (i + 1 < len) {
562+
kw = (fb_reserved_kw_t *)fb_name_table_find(&P->schema.root_schema->keyword_index,
563+
text, i + 1);
564+
if (kw && (kw->kind == fb_reserved_kw_kind_table_field_prefix
565+
|| kw->kind == fb_reserved_kw_kind_vec_prefix)) {
566+
warn_tok(P, sym->ident, "potential table field conflict in C source (option -g might help)");
567+
warn_tok_as_string(P, sym->ident, "prefix is reserved", kw->name.name.s.s, (size_t)kw->name.name.s.len);
568+
return;
569+
}
570+
}
571+
if (i > 0) {
572+
kw = (fb_reserved_kw_t *)fb_name_table_find(&P->schema.root_schema->keyword_index,
573+
text + i, len - i);
574+
if (kw && kw->kind == fb_reserved_kw_kind_table_field_suffix) {
575+
warn_tok(P, sym->ident, "potential table field conflict in C source (option -g might help)");
576+
warn_tok_as_string(P, sym->ident, "suffix is reserved", kw->name.name.s.s, (size_t)kw->name.name.s.len);
577+
return;
578+
}
579+
}
580+
}
581+
}
582+
}
583+
399584
static void revert_order(fb_compound_type_t **list) {
400585
fb_compound_type_t *next, *prev = 0, *link = *list;
401586

@@ -948,6 +1133,7 @@ static int process_table(fb_parser_t *P, fb_compound_type_t *ct)
9481133
error_sym(P, sym, "internal error: member type expected");
9491134
return -1;
9501135
}
1136+
check_reserved_table_field(P, sym);
9511137
member = (fb_member_t *)sym;
9521138
if (member->type.type == vt_invalid) {
9531139
continue;
@@ -1619,6 +1805,9 @@ static int process_enum(fb_parser_t *P, fb_compound_type_t *ct)
16191805

16201806
for (sym = ct->members; sym; sym = sym->link, first = 0) {
16211807
member = (fb_member_t *)sym;
1808+
if (!is_union) {
1809+
check_reserved_enum_member(P, sym);
1810+
}
16221811
if ((old = define_fb_symbol(&ct->index, sym))) {
16231812
if (old->ident == &P->t_none) {
16241813
/*
@@ -1822,6 +2011,7 @@ int fb_build_schema(fb_parser_t *P)
18222011
}
18232012
}
18242013
install_known_attributes(P);
2014+
install_reserved_keywords(P);
18252015

18262016
if (!P->opts.hide_later_enum) {
18272017
for (sym = S->symbols; sym; sym = sym->link) {

0 commit comments

Comments
 (0)