diff options
author | Bernhard Reutner-Fischer <aldot@gcc.gnu.org> | 2017-10-19 09:24:33 +0200 |
---|---|---|
committer | Bernhard Reutner-Fischer <aldot@gcc.gnu.org> | 2017-10-19 09:24:33 +0200 |
commit | bcc478b9647e2af4b715fda6676d98f1e129d16b (patch) | |
tree | 78eb982a4151306d46381aacdf1b5298544bdac2 /gcc/fortran/resolve.c | |
parent | fba832054d9467a296d126754cc3a5efca707bdf (diff) | |
download | gcc-bcc478b9647e2af4b715fda6676d98f1e129d16b.zip gcc-bcc478b9647e2af4b715fda6676d98f1e129d16b.tar.gz gcc-bcc478b9647e2af4b715fda6676d98f1e129d16b.tar.bz2 |
Use Levenshtein spelling suggestions in Fortran FE
gcc/fortran/ChangeLog
2017-10-19 Bernhard Reutner-Fischer <aldot@gcc.gnu.org>
* gfortran.h (gfc_lookup_function_fuzzy): New declaration.
(gfc_closest_fuzzy_match): New declaration.
(vec_push): New definition.
* misc.c (gfc_closest_fuzzy_match): New definition.
* resolve.c: Include spellcheck.h.
(lookup_function_fuzzy_find_candidates): New static function.
(lookup_uop_fuzzy_find_candidates): Likewise.
(lookup_uop_fuzzy): Likewise.
(resolve_operator) <INTRINSIC_USER>: Call lookup_uop_fuzzy.
(gfc_lookup_function_fuzzy): New definition.
(resolve_unknown_f): Call gfc_lookup_function_fuzzy.
* interface.c (check_interface0): Likewise.
(lookup_arg_fuzzy_find_candidates): New static function.
(lookup_arg_fuzzy ): Likewise.
(compare_actual_formal): Call lookup_arg_fuzzy.
* symbol.c: Include spellcheck.h.
(lookup_symbol_fuzzy_find_candidates): New static function.
(lookup_symbol_fuzzy): Likewise.
(gfc_set_default_type): Call lookup_symbol_fuzzy.
(lookup_component_fuzzy_find_candidates): New static function.
(lookup_component_fuzzy): Likewise.
(gfc_find_component): Call lookup_component_fuzzy.
gcc/testsuite/ChangeLog
2017-10-19 Bernhard Reutner-Fischer <aldot@gcc.gnu.org>
* gfortran.dg/spellcheck-operator.f90: New testcase.
* gfortran.dg/spellcheck-procedure_1.f90: New testcase.
* gfortran.dg/spellcheck-procedure_2.f90: New testcase.
* gfortran.dg/spellcheck-structure.f90: New testcase.
* gfortran.dg/spellcheck-parameter.f90: New testcase.
From-SVN: r253877
Diffstat (limited to 'gcc/fortran/resolve.c')
-rw-r--r-- | gcc/fortran/resolve.c | 100 |
1 files changed, 96 insertions, 4 deletions
diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index 178854b..0188bdd 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -2801,6 +2801,43 @@ resolve_specific_f (gfc_expr *expr) return true; } +/* Recursively append candidate SYM to CANDIDATES. Store the number of + candidates in CANDIDATES_LEN. */ + +static void +lookup_function_fuzzy_find_candidates (gfc_symtree *sym, + char **&candidates, + size_t &candidates_len) +{ + gfc_symtree *p; + + if (sym == NULL) + return; + if ((sym->n.sym->ts.type != BT_UNKNOWN || sym->n.sym->attr.external) + && sym->n.sym->attr.flavor == FL_PROCEDURE) + vec_push (candidates, candidates_len, sym->name); + + p = sym->left; + if (p) + lookup_function_fuzzy_find_candidates (p, candidates, candidates_len); + + p = sym->right; + if (p) + lookup_function_fuzzy_find_candidates (p, candidates, candidates_len); +} + + +/* Lookup function FN fuzzily, taking names in SYMROOT into account. */ + +const char* +gfc_lookup_function_fuzzy (const char *fn, gfc_symtree *symroot) +{ + char **candidates = NULL; + size_t candidates_len = 0; + lookup_function_fuzzy_find_candidates (symroot, candidates, candidates_len); + return gfc_closest_fuzzy_match (fn, candidates); +} + /* Resolve a procedure call not known to be generic nor specific. */ @@ -2851,8 +2888,15 @@ set_type: if (ts->type == BT_UNKNOWN) { - gfc_error ("Function %qs at %L has no IMPLICIT type", - sym->name, &expr->where); + const char *guessed + = gfc_lookup_function_fuzzy (sym->name, sym->ns->sym_root); + if (guessed) + gfc_error ("Function %qs at %L has no IMPLICIT type" + "; did you mean %qs?", + sym->name, &expr->where, guessed); + else + gfc_error ("Function %qs at %L has no IMPLICIT type", + sym->name, &expr->where); return false; } else @@ -3713,6 +3757,46 @@ logical_to_bitwise (gfc_expr *e) return e; } +/* Recursively append candidate UOP to CANDIDATES. Store the number of + candidates in CANDIDATES_LEN. */ +static void +lookup_uop_fuzzy_find_candidates (gfc_symtree *uop, + char **&candidates, + size_t &candidates_len) +{ + gfc_symtree *p; + + if (uop == NULL) + return; + + /* Not sure how to properly filter here. Use all for a start. + n.uop.op is NULL for empty interface operators (is that legal?) disregard + these as i suppose they don't make terribly sense. */ + + if (uop->n.uop->op != NULL) + vec_push (candidates, candidates_len, uop->name); + + p = uop->left; + if (p) + lookup_uop_fuzzy_find_candidates (p, candidates, candidates_len); + + p = uop->right; + if (p) + lookup_uop_fuzzy_find_candidates (p, candidates, candidates_len); +} + +/* Lookup user-operator OP fuzzily, taking names in UOP into account. */ + +static const char* +lookup_uop_fuzzy (const char *op, gfc_symtree *uop) +{ + char **candidates = NULL; + size_t candidates_len = 0; + lookup_uop_fuzzy_find_candidates (uop, candidates, candidates_len); + return gfc_closest_fuzzy_match (op, candidates); +} + + /* Resolve an operator expression node. This can involve replacing the operation with a user defined function call. */ @@ -3935,8 +4019,16 @@ resolve_operator (gfc_expr *e) case INTRINSIC_USER: if (e->value.op.uop->op == NULL) - sprintf (msg, _("Unknown operator %%<%s%%> at %%L"), - e->value.op.uop->name); + { + const char *name = e->value.op.uop->name; + const char *guessed; + guessed = lookup_uop_fuzzy (name, e->value.op.uop->ns->uop_root); + if (guessed) + sprintf (msg, _("Unknown operator %%<%s%%> at %%L; did you mean '%s'?"), + name, guessed); + else + sprintf (msg, _("Unknown operator %%<%s%%> at %%L"), name); + } else if (op2 == NULL) sprintf (msg, _("Operand of user operator %%<%s%%> at %%L is %s"), e->value.op.uop->name, gfc_typename (&op1->ts)); |