mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-09 12:23:04 +00:00
diagnostics: suggest fixes for undeclared symbols
From
input.y:1.17-19: warning: symbol baz is used, but is not defined as a token and has no rules [-Wother]
1 | %printer {} foo baz
| ^~~
to
input.y:1.17-19: warning: symbol 'baz' is used, but is not defined as a token and has no rules; did you mean 'bar'? [-Wother]
1 | %printer {} foo baz
| ^~~
| bar
* bootstrap.conf: We need fstrcmp.
* src/symtab.c (symbol_from_uniqstr_fuzzy): New.
(complain_symbol_undeclared): Use it.
* tests/diagnostics.at (Suggestions): New.
* data/bison-default.css (insertion): Rename as...
(fixit-insert): this, as this is what GCC uses.
This commit is contained in:
@@ -22,7 +22,8 @@ gnulib_modules='
|
|||||||
calloc-posix close closeout config-h c-strcase
|
calloc-posix close closeout config-h c-strcase
|
||||||
configmake
|
configmake
|
||||||
dirname
|
dirname
|
||||||
error extensions fdl fopen-safer
|
error extensions
|
||||||
|
fdl fopen-safer fstrcmp
|
||||||
getopt-gnu
|
getopt-gnu
|
||||||
gettext-h git-version-gen gitlog-to-changelog
|
gettext-h git-version-gen gitlog-to-changelog
|
||||||
gpl-3.0 intprops inttypes isnan javacomp-script
|
gpl-3.0 intprops inttypes isnan javacomp-script
|
||||||
|
|||||||
@@ -21,7 +21,8 @@
|
|||||||
.warning { color: purple; }
|
.warning { color: purple; }
|
||||||
.error { color: red; }
|
.error { color: red; }
|
||||||
.note { color: cyan; }
|
.note { color: cyan; }
|
||||||
.insertion { color: green; }
|
|
||||||
|
.fixit-insert { color: green; }
|
||||||
|
|
||||||
/* Semantic values in Bison's own parser traces. */
|
/* Semantic values in Bison's own parser traces. */
|
||||||
.value { color: green; }
|
.value { color: green; }
|
||||||
|
|||||||
5
lib/.gitignore
vendored
5
lib/.gitignore
vendored
@@ -53,6 +53,7 @@
|
|||||||
/config.h
|
/config.h
|
||||||
/config.in.h
|
/config.in.h
|
||||||
/configmake.h
|
/configmake.h
|
||||||
|
/diffseq.h
|
||||||
/dirname-lgpl.c
|
/dirname-lgpl.c
|
||||||
/dirname.c
|
/dirname.c
|
||||||
/dirname.h
|
/dirname.h
|
||||||
@@ -91,6 +92,8 @@
|
|||||||
/fseterr.c
|
/fseterr.c
|
||||||
/fseterr.h
|
/fseterr.h
|
||||||
/fstat.c
|
/fstat.c
|
||||||
|
/fstrcmp.c
|
||||||
|
/fstrcmp.h
|
||||||
/fsync.c
|
/fsync.c
|
||||||
/getdtablesize.c
|
/getdtablesize.c
|
||||||
/gethrxtime.c
|
/gethrxtime.c
|
||||||
@@ -324,6 +327,8 @@
|
|||||||
/windows-recmutex.h
|
/windows-recmutex.h
|
||||||
/windows-rwlock.c
|
/windows-rwlock.c
|
||||||
/windows-rwlock.h
|
/windows-rwlock.h
|
||||||
|
/windows-tls.c
|
||||||
|
/windows-tls.h
|
||||||
/xalloc-die.c
|
/xalloc-die.c
|
||||||
/xalloc-oversized.h
|
/xalloc-oversized.h
|
||||||
/xalloc.h
|
/xalloc.h
|
||||||
|
|||||||
2
lib/glthread/.gitignore
vendored
2
lib/glthread/.gitignore
vendored
@@ -1,3 +1,5 @@
|
|||||||
/lock.c
|
/lock.c
|
||||||
/lock.h
|
/lock.h
|
||||||
/threadlib.c
|
/threadlib.c
|
||||||
|
/tls.c
|
||||||
|
/tls.h
|
||||||
|
|||||||
5
m4/.gitignore
vendored
5
m4/.gitignore
vendored
@@ -71,6 +71,8 @@
|
|||||||
/iswblank.m4
|
/iswblank.m4
|
||||||
/javacomp.m4
|
/javacomp.m4
|
||||||
/javaexec.m4
|
/javaexec.m4
|
||||||
|
/jm-winsz1.m4
|
||||||
|
/jm-winsz2.m4
|
||||||
/largefile.m4
|
/largefile.m4
|
||||||
/lcmessage.m4
|
/lcmessage.m4
|
||||||
/ldexp.m4
|
/ldexp.m4
|
||||||
@@ -179,6 +181,7 @@
|
|||||||
/threadlib.m4
|
/threadlib.m4
|
||||||
/time_h.m4
|
/time_h.m4
|
||||||
/timespec.m4
|
/timespec.m4
|
||||||
|
/tls.m4
|
||||||
/uintmax_t.m4
|
/uintmax_t.m4
|
||||||
/unistd-safer.m4
|
/unistd-safer.m4
|
||||||
/unistd_h.m4
|
/unistd_h.m4
|
||||||
@@ -202,5 +205,3 @@
|
|||||||
/xalloc.m4
|
/xalloc.m4
|
||||||
/xsize.m4
|
/xsize.m4
|
||||||
/xstrndup.m4
|
/xstrndup.m4
|
||||||
/jm-winsz1.m4
|
|
||||||
/jm-winsz2.m4
|
|
||||||
|
|||||||
@@ -473,7 +473,7 @@ location_caret (location loc, const char *style, FILE *out)
|
|||||||
void
|
void
|
||||||
location_caret_suggestion (location loc, const char *s, FILE *out)
|
location_caret_suggestion (location loc, const char *s, FILE *out)
|
||||||
{
|
{
|
||||||
const char *style = "insertion";
|
const char *style = "fixit-insert";
|
||||||
fprintf (out, " | %*s",
|
fprintf (out, " | %*s",
|
||||||
loc.start.column - 1 - caret_info.skip + (caret_info.skip ? 3 : 0),
|
loc.start.column - 1 - caret_info.skip + (caret_info.skip ? 3 : 0),
|
||||||
"");
|
"");
|
||||||
|
|||||||
56
src/symtab.c
56
src/symtab.c
@@ -24,6 +24,7 @@
|
|||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
|
||||||
#include <assure.h>
|
#include <assure.h>
|
||||||
|
#include <fstrcmp.h>
|
||||||
#include <hash.h>
|
#include <hash.h>
|
||||||
|
|
||||||
#include "complain.h"
|
#include "complain.h"
|
||||||
@@ -32,6 +33,8 @@
|
|||||||
#include "quote.h"
|
#include "quote.h"
|
||||||
|
|
||||||
|
|
||||||
|
static struct hash_table *symbol_table = NULL;
|
||||||
|
static struct hash_table *semantic_type_table = NULL;
|
||||||
|
|
||||||
/*----------------------------------------------------------------.
|
/*----------------------------------------------------------------.
|
||||||
| Symbols sorted by tag. Allocated by table_sort, after which no |
|
| Symbols sorted by tag. Allocated by table_sort, after which no |
|
||||||
@@ -41,6 +44,7 @@
|
|||||||
static symbol **symbols_sorted = NULL;
|
static symbol **symbols_sorted = NULL;
|
||||||
static semantic_type **semantic_types_sorted = NULL;
|
static semantic_type **semantic_types_sorted = NULL;
|
||||||
|
|
||||||
|
|
||||||
/*------------------------.
|
/*------------------------.
|
||||||
| Distinguished symbols. |
|
| Distinguished symbols. |
|
||||||
`------------------------*/
|
`------------------------*/
|
||||||
@@ -321,15 +325,54 @@ complain_class_redeclared (symbol *sym, symbol_class class, location second)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const symbol *
|
||||||
|
symbol_from_uniqstr_fuzzy (const uniqstr key)
|
||||||
|
{
|
||||||
|
aver (symbols_sorted);
|
||||||
|
#define FSTRCMP_THRESHOLD 0.6
|
||||||
|
double best_similarity = FSTRCMP_THRESHOLD;
|
||||||
|
const symbol *res = NULL;
|
||||||
|
size_t count = hash_get_n_entries (symbol_table);
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
symbol *sym = symbols_sorted[i];
|
||||||
|
if (STRNEQ (key, sym->tag)
|
||||||
|
&& (sym->content->status == declared
|
||||||
|
|| sym->content->status == undeclared))
|
||||||
|
{
|
||||||
|
double similarity = fstrcmp_bounded (key, sym->tag, best_similarity);
|
||||||
|
if (best_similarity < similarity)
|
||||||
|
{
|
||||||
|
res = sym;
|
||||||
|
best_similarity = similarity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
complain_symbol_undeclared (symbol *sym)
|
complain_symbol_undeclared (symbol *sym)
|
||||||
{
|
{
|
||||||
assert (sym->content->status != declared);
|
assert (sym->content->status != declared);
|
||||||
complain (&sym->location,
|
const symbol *best = symbol_from_uniqstr_fuzzy (sym->tag);
|
||||||
sym->content->status == needed ? complaint : Wother,
|
if (best)
|
||||||
_("symbol %s is used, but is not defined as a token"
|
{
|
||||||
" and has no rules"),
|
complain (&sym->location,
|
||||||
quote (sym->tag));
|
sym->content->status == needed ? complaint : Wother,
|
||||||
|
_("symbol %s is used, but is not defined as a token"
|
||||||
|
" and has no rules; did you mean %s?"),
|
||||||
|
quote_n (0, sym->tag),
|
||||||
|
quote_n (1, best->tag));
|
||||||
|
if (feature_flag & feature_caret)
|
||||||
|
location_caret_suggestion (sym->location, best->tag, stderr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
complain (&sym->location,
|
||||||
|
sym->content->status == needed ? complaint : Wother,
|
||||||
|
_("symbol %s is used, but is not defined as a token"
|
||||||
|
" and has no rules"),
|
||||||
|
quote (sym->tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -694,9 +737,6 @@ symbol_translation (symbol *this)
|
|||||||
/* Initial capacity of symbol and semantic type hash table. */
|
/* Initial capacity of symbol and semantic type hash table. */
|
||||||
#define HT_INITIAL_CAPACITY 257
|
#define HT_INITIAL_CAPACITY 257
|
||||||
|
|
||||||
static struct hash_table *symbol_table = NULL;
|
|
||||||
static struct hash_table *semantic_type_table = NULL;
|
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
hash_compare_symbol (const symbol *m1, const symbol *m2)
|
hash_compare_symbol (const symbol *m1, const symbol *m2)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ AT_DATA([experr], [$4])
|
|||||||
AT_CHECK([LC_ALL=en_US.UTF-8 $5 bison -fcaret --color=debug -Wall input.y], [$3], [], [experr])
|
AT_CHECK([LC_ALL=en_US.UTF-8 $5 bison -fcaret --color=debug -Wall input.y], [$3], [], [experr])
|
||||||
|
|
||||||
# When no style, same messages, but without style.
|
# When no style, same messages, but without style.
|
||||||
AT_CHECK([perl -pi -e 's{(</?\w+>)}{ $[]1 eq "<tag>" ? $[]1 : "" }ge' experr])
|
AT_CHECK([perl -pi -e 's{(</?(-|\w)+>)}{ $[]1 eq "<tag>" ? $[]1 : "" }ge' experr])
|
||||||
|
|
||||||
# Cannot use AT_BISON_CHECK easily as we need to change the
|
# Cannot use AT_BISON_CHECK easily as we need to change the
|
||||||
# environment.
|
# environment.
|
||||||
@@ -344,7 +344,7 @@ input.y:9.8-33: previous declaration
|
|||||||
9 | %token <note>ABCDEFGHIJKLMNOPQRSTUVWXYZ</note> ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
9 | %token <note>ABCDEFGHIJKLMNOPQRSTUVWXYZ</note> ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||||
| <note>^~~~~~~~~~~~~~~~~~~~~~~~~~</note>
|
| <note>^~~~~~~~~~~~~~~~~~~~~~~~~~</note>
|
||||||
input.y:10.56-69: <warning>warning:</warning> deprecated directive: '%error-verbose', use '%define parse.error verbose' [<warning>-Wdeprecated</warning>]
|
input.y:10.56-69: <warning>warning:</warning> deprecated directive: '%error-verbose', use '%define parse.error verbose' [<warning>-Wdeprecated</warning>]
|
||||||
10 | <warning>%error-verbose</warning>
|
10 | <warning>%error-verbose</warning>
|
||||||
| <warning>^~~~~~~~~~~~~~</warning>
|
| <warning>^~~~~~~~~~~~~~</warning>
|
||||||
| <fixit-insert>%define parse.error verbose</fixit-insert>
|
| <fixit-insert>%define parse.error verbose</fixit-insert>
|
||||||
input.y: <warning>warning:</warning> fix-its can be applied. Rerun with option '--update'. [<warning>-Wother</warning>]
|
input.y: <warning>warning:</warning> fix-its can be applied. Rerun with option '--update'. [<warning>-Wother</warning>]
|
||||||
@@ -377,7 +377,7 @@ input.y:9.8-33: previous declaration
|
|||||||
9 | %token <note>ABCDEFGHIJKLMNOPQRSTUVWXYZ</note> ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEF...
|
9 | %token <note>ABCDEFGHIJKLMNOPQRSTUVWXYZ</note> ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEF...
|
||||||
| <note>^~~~~~~~~~~~~~~~~~~~~~~~~~</note>
|
| <note>^~~~~~~~~~~~~~~~~~~~~~~~~~</note>
|
||||||
input.y:10.56-69: <warning>warning:</warning> deprecated directive: '%error-verbose', use '%define parse.error verbose' [<warning>-Wdeprecated</warning>]
|
input.y:10.56-69: <warning>warning:</warning> deprecated directive: '%error-verbose', use '%define parse.error verbose' [<warning>-Wdeprecated</warning>]
|
||||||
10 | <warning>%error-verbose</warning>
|
10 | <warning>%error-verbose</warning>
|
||||||
| <warning>^~~~~~~~~~~~~~</warning>
|
| <warning>^~~~~~~~~~~~~~</warning>
|
||||||
| <fixit-insert>%define parse.error verbose</fixit-insert>
|
| <fixit-insert>%define parse.error verbose</fixit-insert>
|
||||||
input.y: <warning>warning:</warning> fix-its can be applied. Rerun with option '--update'. [<warning>-Wother</warning>]
|
input.y: <warning>warning:</warning> fix-its can be applied. Rerun with option '--update'. [<warning>-Wother</warning>]
|
||||||
@@ -410,11 +410,39 @@ input.y:9.8-33: previous declaration
|
|||||||
9 | %token <note>ABCDEFGHIJKLMNOPQRSTUVWXYZ</note> ABCDEFGHIJKLMN...
|
9 | %token <note>ABCDEFGHIJKLMNOPQRSTUVWXYZ</note> ABCDEFGHIJKLMN...
|
||||||
| <note>^~~~~~~~~~~~~~~~~~~~~~~~~~</note>
|
| <note>^~~~~~~~~~~~~~~~~~~~~~~~~~</note>
|
||||||
input.y:10.56-69: <warning>warning:</warning> deprecated directive: '%error-verbose', use '%define parse.error verbose' [<warning>-Wdeprecated</warning>]
|
input.y:10.56-69: <warning>warning:</warning> deprecated directive: '%error-verbose', use '%define parse.error verbose' [<warning>-Wdeprecated</warning>]
|
||||||
10 | ... <warning>%error-verbose</warning>
|
10 | ... <warning>%error-verbose</warning>
|
||||||
| <warning>^~~~~~~~~~~~~~</warning>
|
| <warning>^~~~~~~~~~~~~~</warning>
|
||||||
| <fixit-insert>%define parse.error verbose</fixit-insert>
|
| <fixit-insert>%define parse.error verbose</fixit-insert>
|
||||||
input.y: <warning>warning:</warning> fix-its can be applied. Rerun with option '--update'. [<warning>-Wother</warning>]
|
input.y: <warning>warning:</warning> fix-its can be applied. Rerun with option '--update'. [<warning>-Wother</warning>]
|
||||||
]],
|
]],
|
||||||
|
[[COLUMNS=60]])
|
||||||
|
|
||||||
|
|
||||||
|
## ------------- ##
|
||||||
|
## Suggestions. ##
|
||||||
|
## ------------- ##
|
||||||
|
|
||||||
|
# Don't suggest to fix QUX with QUUX and QUUX with QUX...
|
||||||
|
AT_TEST([[Suggestions]],
|
||||||
|
[[%%
|
||||||
|
res: QUX baz
|
||||||
|
bar: QUUX
|
||||||
|
]],
|
||||||
|
[1],
|
||||||
|
[[input.y:11.6-9: <error>error:</error> symbol 'QUUX' is used, but is not defined as a token and has no rules
|
||||||
|
11 | bar: <error>QUUX</error>
|
||||||
|
| <error>^~~~</error>
|
||||||
|
input.y:10.6-8: <error>error:</error> symbol 'QUX' is used, but is not defined as a token and has no rules
|
||||||
|
10 | res: <error>QUX</error> baz
|
||||||
|
| <error>^~~</error>
|
||||||
|
input.y:10.10-12: <error>error:</error> symbol 'baz' is used, but is not defined as a token and has no rules; did you mean 'bar'?
|
||||||
|
10 | res: QUX <error>baz</error>
|
||||||
|
| <error>^~~</error>
|
||||||
|
| <fixit-insert>bar</fixit-insert>
|
||||||
|
]])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
m4_popdef([AT_TEST])
|
m4_popdef([AT_TEST])
|
||||||
|
|||||||
Reference in New Issue
Block a user