Ping
On June 18, 2016 9:58:47 PM GMT+02:00, Bernhard Reutner-Fischer
<rep.dot....@gmail.com> wrote:
>Hi,
>
>Ok for trunk?
>
>Changes for v4 -> v3:
>
>- rebased
>- Use 4 argument levenshtein_distance() to save multiple strlen(typo)
> calls as suggested by dmalcolm
>
>Changes for v2 -> v3:
>
>- rebased
>
>Changes for v1 -> v2:
>
>- subroutines using interfaces
>- keyword arguments (named parameters)
>
>Rewrite C++ autovec in plain C.
>Factor out levenshtein distance handling into a commonly used
>gfc_closest_fuzzy_match().
>
>gcc/fortran/ChangeLog
>
>2015-12-27 Bernhard Reutner-Fischer <al...@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
>
>2015-12-27 Bernhard Reutner-Fischer <al...@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.
>
>---
>
>David Malcolm's nice Levenshtein distance spelling check helpers
>were used in some parts of other frontends. This proposed patch adds
>some spelling corrections to the fortran frontend.
>
>Suggestions are printed if we can find a suitable name, currently
>perusing a very simple cutoff factor:
>/* If more than half of the letters were misspelled, the suggestion is
> likely to be meaningless. */
>cutoff = MAX (strlen (typo), strlen (best_guess)) / 2;
>which effectively skips names with less than 4 characters.
>For e.g. structures, one could try to be much smarter in an attempt to
>also provide suggestions for single-letter members/components.
>
>This patch covers (at least partly):
>- user-defined operators
>- structures (types and their components)
>- functions
>- symbols (variables)
>
>If anybody has a testcase where a spelling-suggestion would make sense
>then please pass it along so we maybe can add support for GCC-7.
>
>Signed-off-by: Bernhard Reutner-Fischer <rep.dot....@gmail.com>
>---
> gcc/fortran/gfortran.h | 12 +++
>gcc/fortran/interface.c | 72
>+++++++++++++--
> gcc/fortran/misc.c | 41 +++++++++
>gcc/fortran/resolve.c | 100
>++++++++++++++++++++-
>gcc/fortran/symbol.c | 86
>+++++++++++++++++-
> gcc/testsuite/gfortran.dg/spellcheck-operator.f90 | 30 +++++++
> gcc/testsuite/gfortran.dg/spellcheck-parameter.f90 | 15 ++++
> .../gfortran.dg/spellcheck-procedure_1.f90 | 41 +++++++++
> .../gfortran.dg/spellcheck-procedure_2.f90 | 35 ++++++++
> gcc/testsuite/gfortran.dg/spellcheck-structure.f90 | 35 ++++++++
> 10 files changed, 450 insertions(+), 17 deletions(-)
> create mode 100644 gcc/testsuite/gfortran.dg/spellcheck-operator.f90
> create mode 100644 gcc/testsuite/gfortran.dg/spellcheck-parameter.f90
>create mode 100644 gcc/testsuite/gfortran.dg/spellcheck-procedure_1.f90
>create mode 100644 gcc/testsuite/gfortran.dg/spellcheck-procedure_2.f90
> create mode 100644 gcc/testsuite/gfortran.dg/spellcheck-structure.f90
>
>diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
>index 0bb71cb..5d43c2d 100644
>--- a/gcc/fortran/gfortran.h
>+++ b/gcc/fortran/gfortran.h
>@@ -2682,6 +2682,17 @@ void gfc_done_2 (void);
>
> int get_c_kind (const char *, CInteropKind_t *);
>
>+const char *gfc_closest_fuzzy_match (const char *, char **);
>+static inline void
>+vec_push (char **&optr, size_t &osz, const char *elt)
>+{
>+ /* {auto,}vec.safe_push () replacement. Don't ask.. */
>+ // if (strlen (elt) < 4) return; premature optimization: eliminated
>by cutoff
>+ optr = XRESIZEVEC (char *, optr, osz + 2);
>+ optr[osz] = CONST_CAST (char *, elt);
>+ optr[++osz] = NULL;
>+}
>+
> /* options.c */
> unsigned int gfc_option_lang_mask (void);
> void gfc_init_options_struct (struct gcc_options *);
>@@ -3103,6 +3114,7 @@ bool gfc_type_is_extensible (gfc_symbol *);
> bool gfc_resolve_intrinsic (gfc_symbol *, locus *);
> bool gfc_explicit_interface_required (gfc_symbol *, char *, int);
> extern int gfc_do_concurrent_flag;
>+const char* gfc_lookup_function_fuzzy (const char *, gfc_symtree *);
>
>
> /* array.c */
>diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c
>index b012de5..bef514c 100644
>--- a/gcc/fortran/interface.c
>+++ b/gcc/fortran/interface.c
>@@ -1694,13 +1694,27 @@ check_interface0 (gfc_interface *p, const char
>*interface_name)
> || !p->sym->attr.if_source)
> && !gfc_fl_struct (p->sym->attr.flavor))
> {
>+ const char *guessed
>+ = gfc_lookup_function_fuzzy (p->sym->name, p->sym->ns->sym_root);
>+
> if (p->sym->attr.external)
>- gfc_error ("Procedure %qs in %s at %L has no explicit interface",
>- p->sym->name, interface_name, &p->sym->declared_at);
>+ if (guessed)
>+ gfc_error ("Procedure %qs in %s at %L has no explicit
>interface"
>+ "; did you mean %qs?",
>+ p->sym->name, interface_name, &p->sym->declared_at,
>+ guessed);
>+ else
>+ gfc_error ("Procedure %qs in %s at %L has no explicit
>interface",
>+ p->sym->name, interface_name, &p->sym->declared_at);
> else
>- gfc_error ("Procedure %qs in %s at %L is neither function nor "
>- "subroutine", p->sym->name, interface_name,
>- &p->sym->declared_at);
>+ if (guessed)
>+ gfc_error ("Procedure %qs in %s at %L is neither function nor "
>+ "subroutine; did you mean %qs?", p->sym->name,
>+ interface_name, &p->sym->declared_at, guessed);
>+ else
>+ gfc_error ("Procedure %qs in %s at %L is neither function nor "
>+ "subroutine", p->sym->name, interface_name,
>+ &p->sym->declared_at);
> return 1;
> }
>
>@@ -2684,6 +2698,31 @@ is_procptr_result (gfc_expr *expr)
> }
>
>
>+/* Recursively append candidate argument ARG to CANDIDATES. Store the
>+ number of total candidates in CANDIDATES_LEN. */
>+
>+static void
>+lookup_arg_fuzzy_find_candidates (gfc_formal_arglist *arg,
>+ char **&candidates,
>+ size_t &candidates_len)
>+{
>+ for (gfc_formal_arglist *p = arg; p && p->sym; p = p->next)
>+ vec_push (candidates, candidates_len, p->sym->name);
>+}
>+
>+
>+/* Lookup argument ARG fuzzily, taking names in ARGUMENTS into
>account. */
>+
>+static const char*
>+lookup_arg_fuzzy (const char *arg, gfc_formal_arglist *arguments)
>+{
>+ char **candidates = NULL;
>+ size_t candidates_len = 0;
>+ lookup_arg_fuzzy_find_candidates (arguments, candidates,
>candidates_len);
>+ return gfc_closest_fuzzy_match (arg, candidates);
>+}
>+
>+
> /* Given formal and actual argument lists, see if they are compatible.
> If they are compatible, the actual argument list is sorted to
> correspond with the formal list, and elements for missing optional
>@@ -2736,8 +2775,16 @@ compare_actual_formal (gfc_actual_arglist **ap,
>gfc_formal_arglist *formal,
> if (f == NULL)
> {
> if (where)
>- gfc_error ("Keyword argument %qs at %L is not in "
>- "the procedure", a->name, &a->expr->where);
>+ {
>+ const char *guessed = lookup_arg_fuzzy (a->name, formal);
>+ if (guessed)
>+ gfc_error ("Keyword argument %qs at %L is not in "
>+ "the procedure; did you mean %qs?",
>+ a->name, &a->expr->where, guessed);
>+ else
>+ gfc_error ("Keyword argument %qs at %L is not in "
>+ "the procedure", a->name, &a->expr->where);
>+ }
> return 0;
> }
>
>@@ -3436,8 +3483,15 @@ gfc_procedure_use (gfc_symbol *sym,
>gfc_actual_arglist **ap, locus *where)
> {
>if (sym->ns->has_implicit_none_export && sym->attr.proc ==
>PROC_UNKNOWN)
> {
>- gfc_error ("Procedure %qs called at %L is not explicitly declared",
>- sym->name, where);
>+ const char *guessed
>+ = gfc_lookup_function_fuzzy (sym->name, sym->ns->sym_root);
>+ if (guessed)
>+ gfc_error ("Procedure %qs called at %L is not explicitly
>declared"
>+ "; did you mean %qs?",
>+ sym->name, where, guessed);
>+ else
>+ gfc_error ("Procedure %qs called at %L is not explicitly
>declared",
>+ sym->name, where);
> return false;
> }
> if (warn_implicit_interface)
>diff --git a/gcc/fortran/misc.c b/gcc/fortran/misc.c
>index 1747ff2..dd17f46 100644
>--- a/gcc/fortran/misc.c
>+++ b/gcc/fortran/misc.c
>@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see
> #include "system.h"
> #include "coretypes.h"
> #include "gfortran.h"
>+#include "spellcheck.h"
>
>
> /* Initialize a typespec to unknown. */
>@@ -280,3 +281,43 @@ get_c_kind(const char *c_kind_name, CInteropKind_t
>kinds_table[])
>
> return ISOCBINDING_INVALID;
> }
>+
>+
>+/* For a given name TYPO, determine the best candidate from CANDIDATES
>+ perusing Levenshtein distance. Frees CANDIDATES before returning.
>*/
>+
>+const char *
>+gfc_closest_fuzzy_match (const char *typo, char **candidates)
>+{
>+ /* Determine closest match. */
>+ const char *best = NULL;
>+ char **cand = candidates;
>+ edit_distance_t best_distance = MAX_EDIT_DISTANCE;
>+ const size_t tl = strlen (typo);
>+
>+ while (cand && *cand)
>+ {
>+ edit_distance_t dist = levenshtein_distance (typo, tl, *cand,
>+ strlen (*cand));
>+ if (dist < best_distance)
>+ {
>+ best_distance = dist;
>+ best = *cand;
>+ }
>+ cand++;
>+ }
>+ /* If more than half of the letters were misspelled, the suggestion
>is
>+ likely to be meaningless. */
>+ if (best)
>+ {
>+ unsigned int cutoff = MAX (tl, strlen (best)) / 2;
>+
>+ if (best_distance > cutoff)
>+ {
>+ XDELETEVEC (candidates);
>+ return NULL;
>+ }
>+ XDELETEVEC (candidates);
>+ }
>+ return best;
>+}
>diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c
>index 77f8c10..089afa3 100644
>--- a/gcc/fortran/resolve.c
>+++ b/gcc/fortran/resolve.c
>@@ -2693,6 +2693,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. */
>
>@@ -2743,8 +2780,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
>@@ -3516,6 +3560,46 @@ compare_shapes (gfc_expr *op1, gfc_expr *op2)
> }
>
>
>+/* 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. */
>
>@@ -3714,8 +3798,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));
>diff --git a/gcc/fortran/symbol.c b/gcc/fortran/symbol.c
>index 0ee7dec..776610c 100644
>--- a/gcc/fortran/symbol.c
>+++ b/gcc/fortran/symbol.c
>@@ -236,6 +236,44 @@ gfc_get_default_type (const char *name,
>gfc_namespace *ns)
> }
>
>
>+/* Recursively append candidate SYM to CANDIDATES. Store the number
>of
>+ candidates in CANDIDATES_LEN. */
>+
>+static void
>+lookup_symbol_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->ts.type !=
>BT_PROCEDURE)
>+ vec_push (candidates, candidates_len, sym->name);
>+ p = sym->left;
>+ if (p)
>+ lookup_symbol_fuzzy_find_candidates (p, candidates,
>candidates_len);
>+
>+ p = sym->right;
>+ if (p)
>+ lookup_symbol_fuzzy_find_candidates (p, candidates,
>candidates_len);
>+}
>+
>+
>+/* Lookup symbol SYM_NAME fuzzily, taking names in SYMBOL into
>account. */
>+
>+static const char*
>+lookup_symbol_fuzzy (const char *sym_name, gfc_symbol *symbol)
>+{
>+ char **candidates = NULL;
>+ size_t candidates_len = 0;
>+ lookup_symbol_fuzzy_find_candidates (symbol->ns->sym_root,
>candidates,
>+ candidates_len);
>+ return gfc_closest_fuzzy_match (sym_name, candidates);
>+}
>+
>+
> /* Given a pointer to a symbol, set its type according to the first
> letter of its name. Fails if the letter in question has no default
> type. */
>@@ -254,8 +292,14 @@ gfc_set_default_type (gfc_symbol *sym, int
>error_flag, gfc_namespace *ns)
> {
> if (error_flag && !sym->attr.untyped)
> {
>- gfc_error ("Symbol %qs at %L has no IMPLICIT type",
>- sym->name, &sym->declared_at);
>+ const char *guessed = lookup_symbol_fuzzy (sym->name, sym);
>+ if (guessed)
>+ gfc_error ("Symbol %qs at %L has no IMPLICIT type"
>+ "; did you mean %qs?",
>+ sym->name, &sym->declared_at, guessed);
>+ else
>+ gfc_error ("Symbol %qs at %L has no IMPLICIT type",
>+ sym->name, &sym->declared_at);
> sym->attr.untyped = 1; /* Ensure we only give an error once. */
> }
>
>@@ -2233,6 +2277,32 @@ find_union_component (gfc_symbol *un, const char
>*name,
> }
>
>
>+/* Recursively append candidate COMPONENT structures to CANDIDATES.
>Store
>+ the number of total candidates in CANDIDATES_LEN. */
>+
>+static void
>+lookup_component_fuzzy_find_candidates (gfc_component *component,
>+ char **&candidates,
>+ size_t &candidates_len)
>+{
>+ for (gfc_component *p = component; p; p = p->next)
>+ vec_push (candidates, candidates_len, p->name);
>+}
>+
>+
>+/* Lookup component MEMBER fuzzily, taking names in COMPONENT into
>account. */
>+
>+static const char*
>+lookup_component_fuzzy (const char *member, gfc_component *component)
>+{
>+ char **candidates = NULL;
>+ size_t candidates_len = 0;
>+ lookup_component_fuzzy_find_candidates (component, candidates,
>+ candidates_len);
>+ return gfc_closest_fuzzy_match (member, candidates);
>+}
>+
>+
> /* Given a derived type node and a component name, try to locate the
> component structure. Returns the NULL pointer if the component is
>not found or the components are private. If noaccess is set, no access
>@@ -2330,8 +2400,16 @@ gfc_find_component (gfc_symbol *sym, const char
>*name,
> }
>
> if (p == NULL && !silent)
>- gfc_error ("%qs at %C is not a member of the %qs structure",
>- name, sym->name);
>+ {
>+ const char *guessed = lookup_component_fuzzy (name,
>sym->components);
>+ if (guessed)
>+ gfc_error ("%qs at %C is not a member of the %qs structure"
>+ "; did you mean %qs?",
>+ name, sym->name, guessed);
>+ else
>+ gfc_error ("%qs at %C is not a member of the %qs structure",
>+ name, sym->name);
>+ }
>
> /* Component was found; build the ultimate component reference. */
> if (p != NULL && ref)
>diff --git a/gcc/testsuite/gfortran.dg/spellcheck-operator.f90
>b/gcc/testsuite/gfortran.dg/spellcheck-operator.f90
>new file mode 100644
>index 0000000..810a770
>--- /dev/null
>+++ b/gcc/testsuite/gfortran.dg/spellcheck-operator.f90
>@@ -0,0 +1,30 @@
>+! { dg-do compile }
>+! test levenshtein based spelling suggestions
>+
>+module mymod1
>+ implicit none
>+ contains
>+ function something_good (iarg1)
>+ integer :: something_good
>+ integer, intent(in) :: iarg1
>+ something_good = iarg1 + 42
>+ end function something_good
>+end module mymod1
>+
>+program spellchekc
>+ use mymod1
>+ implicit none
>+
>+ interface operator (.mywrong.)
>+ module procedure something_wring ! { dg-error "Procedure
>.something_wring. in operator interface .mywrong. at .1. is neither
>function nor subroutine; did you mean .something_good.\\?|User operator
>procedure .something_wring. at .1. must be a FUNCTION" }
>+ end interface
>+
>+ interface operator (.mygood.)
>+ module procedure something_good
>+ end interface
>+
>+ integer :: i, j, added
>+ i = 0
>+ j = 0
>+ added = .mygoof. j ! { dg-error "Unknown operator .mygoof. at .1.;
>did you mean .mygood.\\?" }
>+end program spellchekc
>diff --git a/gcc/testsuite/gfortran.dg/spellcheck-parameter.f90
>b/gcc/testsuite/gfortran.dg/spellcheck-parameter.f90
>new file mode 100644
>index 0000000..715c5ab
>--- /dev/null
>+++ b/gcc/testsuite/gfortran.dg/spellcheck-parameter.f90
>@@ -0,0 +1,15 @@
>+! { dg-do compile }
>+! Contributed by Joost VandeVondele
>+! test levenshtein based spelling suggestions for keyword arguments
>+
>+module test
>+contains
>+ subroutine mysub(iarg1)
>+ integer :: iarg1
>+ end subroutine
>+end module
>+
>+use test
>+call mysub(iarg=1) ! { dg-error "Keyword argument .iarg. at .1. is not
>in the procedure; did you mean .iarg1.\\?" }
>+
>+end
>diff --git a/gcc/testsuite/gfortran.dg/spellcheck-procedure_1.f90
>b/gcc/testsuite/gfortran.dg/spellcheck-procedure_1.f90
>new file mode 100644
>index 0000000..3b7f716
>--- /dev/null
>+++ b/gcc/testsuite/gfortran.dg/spellcheck-procedure_1.f90
>@@ -0,0 +1,41 @@
>+! { dg-do compile }
>+! test levenshtein based spelling suggestions
>+
>+module mymod1
>+ implicit none
>+ contains
>+ function something_else (iarg1)
>+ integer :: something_else
>+ integer, intent(in) :: iarg1
>+ something_else = iarg1 + 42
>+ end function something_else
>+ function add_fourtytwo (iarg1)
>+ integer :: add_fourtytwo
>+ integer, intent(in) :: iarg1
>+ add_fourtytwo = iarg1 + 42
>+ end function add_fourtytwo
>+end module mymod1
>+
>+function myadd(iarg1, iarg2)
>+ implicit none
>+ integer :: myadd
>+ integer, intent(in) :: iarg1, iarg2
>+ myadd = iarg1 + iarg2
>+end function myadd
>+
>+program spellchekc
>+ use mymod1, something_good => something_else
>+ implicit none
>+
>+ integer :: myadd, i, j, myvar
>+ i = 0
>+ j = 0
>+
>+ j = something_goof(j) ! { dg-error "no IMPLICIT type; did you mean
>.something_good.\\?" }
>+ j = myaddd(i, j) ! { dg-error "no IMPLICIT type; did you mean
>.myadd.\\?" }
>+ if (j /= 42) call abort
>+ j = add_fourtytow(i, j) ! { dg-error "no IMPLICIT type; did you mean
>.add_fourtytwo.\\?" }
>+ myval = myadd(i, j) ! { dg-error "no IMPLICIT type; did you mean
>.myvar.\\?" }
>+ if (j /= 42 * 2) call abort
>+
>+end program spellchekc
>diff --git a/gcc/testsuite/gfortran.dg/spellcheck-procedure_2.f90
>b/gcc/testsuite/gfortran.dg/spellcheck-procedure_2.f90
>new file mode 100644
>index 0000000..a6ea5f9
>--- /dev/null
>+++ b/gcc/testsuite/gfortran.dg/spellcheck-procedure_2.f90
>@@ -0,0 +1,35 @@
>+! { dg-do compile }
>+! test levenshtein based spelling suggestions
>+
>+
>+program spellchekc
>+ implicit none (external) ! { dg-warning "GNU Extension: IMPORT NONE
>with spec list" }
>+
>+ interface
>+ subroutine bark_unless_zero(iarg)
>+ implicit none
>+ integer, intent(in) :: iarg
>+ end subroutine bark_unless_zero
>+ end interface
>+
>+ integer :: i
>+ i = 0
>+
>+ if (i /= 1) call abort
>+ call bark_unless_0(i) ! { dg-error "not explicitly declared; did you
>mean .bark_unless_zero.\\?" }
>+! call complain_about_0(i) ! { -dg-error "not explicitly declared;
>did you mean .complain_about_zero.\\?" }
>+
>+contains
>+! We cannot reliably see this ATM, would need an unambiguous bit
>somewhere
>+ subroutine complain_about_zero(iarg)
>+ integer, intent(in) :: iarg
>+ if (iarg /= 0) call abort
>+ end subroutine complain_about_zero
>+
>+end program spellchekc
>+
>+subroutine bark_unless_zero(iarg)
>+ implicit none
>+ integer, intent(in) :: iarg
>+ if (iarg /= 0) call abort
>+end subroutine bark_unless_zero
>diff --git a/gcc/testsuite/gfortran.dg/spellcheck-structure.f90
>b/gcc/testsuite/gfortran.dg/spellcheck-structure.f90
>new file mode 100644
>index 0000000..929e05f
>--- /dev/null
>+++ b/gcc/testsuite/gfortran.dg/spellcheck-structure.f90
>@@ -0,0 +1,35 @@
>+! { dg-do compile }
>+! test levenshtein based spelling suggestions
>+implicit none
>+
>+!!!!!!!!!!!!!! structure tests !!!!!!!!!!!!!!
>+type type1
>+ real :: radius
>+ integer :: i
>+end type type1
>+
>+type type2
>+ integer :: myint
>+ type(type1) :: mytype
>+end type type2
>+
>+type type3
>+ type(type2) :: type_2
>+end type type3
>+type type4
>+ type(type3) :: type_3
>+end type type4
>+
>+type(type1) :: t1
>+t1%radiuz = .0 ! { dg-error ".radiuz. at .1. is not a member of the
>.type1. structure; did you mean .radius.\\?" }
>+t1%x = .0 ! { dg-error ".x. at .1. is not a member of the .type1.
>structure" }
>+type(type2) :: t2
>+t2%mytape%radius = .0 ! { dg-error ".mytape. at .1. is not a member of
>the .type2. structure; did you mean .mytype.\\?" }
>+t2%mytype%radious = .0 ! { dg-error ".radious. at .1. is not a member
>of the .type1. structure; did you mean .radius.\\?" }
>+type(type4) :: t4
>+t4%type_3%type_2%mytype%radium = 88.0 ! { dg-error ".radium. at .1. is
>not a member of the .type1. structure; did you mean .radius.\\?" }
>+
>+!!!!!!!!!!!!!! symbol tests !!!!!!!!!!!!!!
>+integer :: iarg1
>+iarg2 = 1 ! { dg-error "Symbol .iarg2. at .1. has no IMPLICIT type;
>did you mean .iarg1.\\?" }
>+end