mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-25 19:11:21 +08:00
Spelling suggestions for misspelled preprocessor directives
This patch allows the preprocessor to offer suggestions for misspelled directives, taking us from e.g.: test.c:5:2: error: invalid preprocessing directive #endfi #endfi ^~~~~ to: test.c:5:2: error: invalid preprocessing directive #endfi; did you mean #endif? #endfi ^~~~~ endif gcc/c-family/ChangeLog: * c-common.c: Include "spellcheck.h". (cb_get_suggestion): New function. * c-common.h (cb_get_suggestion): New decl. * c-lex.c (init_c_lex): Initialize cb->get_suggestion to cb_get_suggestion. gcc/testsuite/ChangeLog: * gcc.dg/cpp/misspelled-directive-1.c: New testcase. * gcc.dg/cpp/misspelled-directive-2.c: New testcase. libcpp/ChangeLog: * directives.c (directive_names): New array. (_cpp_handle_directive): Offer spelling suggestions for misspelled directives. * errors.c (cpp_diagnostic_at_richloc): New function. (cpp_error_at_richloc): New function. * include/cpplib.h (struct cpp_callbacks): Add field "get_suggestion". (cpp_error_at_richloc): New decl. From-SVN: r239585
This commit is contained in:
parent
a76989dc7c
commit
cb18fd07f2
@ -1,3 +1,11 @@
|
||||
2016-08-18 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* c-common.c: Include "spellcheck.h".
|
||||
(cb_get_suggestion): New function.
|
||||
* c-common.h (cb_get_suggestion): New decl.
|
||||
* c-lex.c (init_c_lex): Initialize cb->get_suggestion to
|
||||
cb_get_suggestion.
|
||||
|
||||
2016-08-18 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c/71514
|
||||
|
@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "opts.h"
|
||||
#include "gimplify.h"
|
||||
#include "substring-locations.h"
|
||||
#include "spellcheck.h"
|
||||
|
||||
cpp_reader *parse_in; /* Declared in c-pragma.h. */
|
||||
|
||||
@ -12948,6 +12949,22 @@ cb_get_source_date_epoch (cpp_reader *pfile ATTRIBUTE_UNUSED)
|
||||
return (time_t) epoch;
|
||||
}
|
||||
|
||||
/* Callback for libcpp for offering spelling suggestions for misspelled
|
||||
directives. GOAL is an unrecognized string; CANDIDATES is a
|
||||
NULL-terminated array of candidate strings. Return the closest
|
||||
match to GOAL within CANDIDATES, or NULL if none are good
|
||||
suggestions. */
|
||||
|
||||
const char *
|
||||
cb_get_suggestion (cpp_reader *, const char *goal,
|
||||
const char *const *candidates)
|
||||
{
|
||||
best_match<const char *, const char *> bm (goal);
|
||||
while (*candidates)
|
||||
bm.consider (*candidates++);
|
||||
return bm.get_best_meaningful_candidate ();
|
||||
}
|
||||
|
||||
/* Check and possibly warn if two declarations have contradictory
|
||||
attributes, such as always_inline vs. noinline. */
|
||||
|
||||
|
@ -1110,6 +1110,11 @@ extern time_t cb_get_source_date_epoch (cpp_reader *pfile);
|
||||
__TIME__ can store. */
|
||||
#define MAX_SOURCE_DATE_EPOCH HOST_WIDE_INT_C (253402300799)
|
||||
|
||||
/* Callback for libcpp for offering spelling suggestions for misspelled
|
||||
directives. */
|
||||
extern const char *cb_get_suggestion (cpp_reader *, const char *,
|
||||
const char *const *);
|
||||
|
||||
extern GTY(()) string_concat_db *g_string_concat_db;
|
||||
|
||||
/* libcpp can calculate location information about a range of characters
|
||||
|
@ -81,6 +81,7 @@ init_c_lex (void)
|
||||
cb->read_pch = c_common_read_pch;
|
||||
cb->has_attribute = c_common_has_attribute;
|
||||
cb->get_source_date_epoch = cb_get_source_date_epoch;
|
||||
cb->get_suggestion = cb_get_suggestion;
|
||||
|
||||
/* Set the debug callbacks if we can use them. */
|
||||
if ((debug_info_level == DINFO_LEVEL_VERBOSE
|
||||
|
@ -1,3 +1,8 @@
|
||||
2016-08-18 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* gcc.dg/cpp/misspelled-directive-1.c: New testcase.
|
||||
* gcc.dg/cpp/misspelled-directive-2.c: New testcase.
|
||||
|
||||
2016-08-18 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c/71514
|
||||
|
12
gcc/testsuite/gcc.dg/cpp/misspelled-directive-1.c
Normal file
12
gcc/testsuite/gcc.dg/cpp/misspelled-directive-1.c
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef SOME_GUARD /* { dg-error "unterminated" } */
|
||||
|
||||
#if 1
|
||||
/* Typo here: "endfi" should have been "endif". */
|
||||
#endfi /* { dg-error "invalid preprocessing directive #endfi; did you mean #endif?" } */
|
||||
|
||||
int make_non_empty;
|
||||
|
||||
/* Another transposition typo: */
|
||||
#deifne FOO /* { dg-error "invalid preprocessing directive #deifne; did you mean #define?" } */
|
||||
|
||||
#endif /* #ifndef SOME_GUARD */
|
21
gcc/testsuite/gcc.dg/cpp/misspelled-directive-2.c
Normal file
21
gcc/testsuite/gcc.dg/cpp/misspelled-directive-2.c
Normal file
@ -0,0 +1,21 @@
|
||||
/* { dg-options "-fdiagnostics-show-caret" } */
|
||||
|
||||
#endfi /* { dg-error "invalid preprocessing directive #endfi; did you mean #endif?" } */
|
||||
|
||||
/* Verify that we offer fix-it hints. */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
#endfi
|
||||
^~~~~
|
||||
endif
|
||||
{ dg-end-multiline-output "" } */
|
||||
|
||||
/* Test coverage for the case of an unrecognized directive where no suggestion
|
||||
is offered. */
|
||||
|
||||
#this_does_not_match_anything /* { dg-error "invalid preprocessing directive #this_does_not_match_anything" } */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
#this_does_not_match_anything
|
||||
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
{ dg-end-multiline-output "" } */
|
||||
|
||||
int make_non_empty;
|
@ -1,3 +1,14 @@
|
||||
2016-08-18 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* directives.c (directive_names): New array.
|
||||
(_cpp_handle_directive): Offer spelling suggestions for misspelled
|
||||
directives.
|
||||
* errors.c (cpp_diagnostic_at_richloc): New function.
|
||||
(cpp_error_at_richloc): New function.
|
||||
* include/cpplib.h (struct cpp_callbacks): Add field
|
||||
"get_suggestion".
|
||||
(cpp_error_at_richloc): New decl.
|
||||
|
||||
2016-08-18 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c/7652
|
||||
|
@ -188,6 +188,16 @@ static const directive dtable[] =
|
||||
DIRECTIVE_TABLE
|
||||
};
|
||||
#undef D
|
||||
|
||||
/* A NULL-terminated array of directive names for use
|
||||
when suggesting corrections for misspelled directives. */
|
||||
#define D(name, t, origin, flags) #name,
|
||||
static const char * const directive_names[] = {
|
||||
DIRECTIVE_TABLE
|
||||
NULL
|
||||
};
|
||||
#undef D
|
||||
|
||||
#undef DIRECTIVE_TABLE
|
||||
|
||||
/* Wrapper struct directive for linemarkers.
|
||||
@ -498,8 +508,35 @@ _cpp_handle_directive (cpp_reader *pfile, int indented)
|
||||
if (CPP_OPTION (pfile, lang) == CLK_ASM)
|
||||
skip = 0;
|
||||
else if (!pfile->state.skipping)
|
||||
cpp_error (pfile, CPP_DL_ERROR, "invalid preprocessing directive #%s",
|
||||
cpp_token_as_text (pfile, dname));
|
||||
{
|
||||
const char *unrecognized
|
||||
= (const char *)cpp_token_as_text (pfile, dname);
|
||||
const char *hint = NULL;
|
||||
|
||||
/* Call back into gcc to get a spelling suggestion. Ideally
|
||||
we'd just use best_match from gcc/spellcheck.h (and filter
|
||||
out the uncommon directives), but that requires moving it
|
||||
to a support library. */
|
||||
if (pfile->cb.get_suggestion)
|
||||
hint = pfile->cb.get_suggestion (pfile, unrecognized,
|
||||
directive_names);
|
||||
|
||||
if (hint)
|
||||
{
|
||||
rich_location richloc (pfile->line_table, dname->src_loc);
|
||||
source_range misspelled_token_range
|
||||
= get_range_from_loc (pfile->line_table, dname->src_loc);
|
||||
richloc.add_fixit_replace (misspelled_token_range, hint);
|
||||
cpp_error_at_richloc (pfile, CPP_DL_ERROR, &richloc,
|
||||
"invalid preprocessing directive #%s;"
|
||||
" did you mean #%s?",
|
||||
unrecognized, hint);
|
||||
}
|
||||
else
|
||||
cpp_error (pfile, CPP_DL_ERROR,
|
||||
"invalid preprocessing directive #%s",
|
||||
unrecognized);
|
||||
}
|
||||
}
|
||||
|
||||
pfile->directive = dir;
|
||||
|
@ -29,6 +29,23 @@ along with this program; see the file COPYING3. If not see
|
||||
|
||||
/* Print a diagnostic at the given location. */
|
||||
|
||||
ATTRIBUTE_FPTR_PRINTF(5,0)
|
||||
static bool
|
||||
cpp_diagnostic_at_richloc (cpp_reader * pfile, int level, int reason,
|
||||
rich_location *richloc,
|
||||
const char *msgid, va_list *ap)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
if (!pfile->cb.error)
|
||||
abort ();
|
||||
ret = pfile->cb.error (pfile, level, reason, richloc, _(msgid), ap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Print a diagnostic at the given location. */
|
||||
|
||||
ATTRIBUTE_FPTR_PRINTF(5,0)
|
||||
static bool
|
||||
cpp_diagnostic_at (cpp_reader * pfile, int level, int reason,
|
||||
@ -255,6 +272,25 @@ cpp_error_at (cpp_reader * pfile, int level, source_location src_loc,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* As cpp_error, but use RICHLOC as the location of the error, without
|
||||
a column override. */
|
||||
|
||||
bool
|
||||
cpp_error_at_richloc (cpp_reader * pfile, int level, rich_location *richloc,
|
||||
const char *msgid, ...)
|
||||
{
|
||||
va_list ap;
|
||||
bool ret;
|
||||
|
||||
va_start (ap, msgid);
|
||||
|
||||
ret = cpp_diagnostic_at_richloc (pfile, level, CPP_W_NONE, richloc,
|
||||
msgid, &ap);
|
||||
|
||||
va_end (ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Print a warning or error, depending on the value of LEVEL. Include
|
||||
information from errno. */
|
||||
|
||||
|
@ -597,6 +597,9 @@ struct cpp_callbacks
|
||||
|
||||
/* Callback to parse SOURCE_DATE_EPOCH from environment. */
|
||||
time_t (*get_source_date_epoch) (cpp_reader *);
|
||||
|
||||
/* Callback for providing suggestions for misspelled directives. */
|
||||
const char *(*get_suggestion) (cpp_reader *, const char *, const char *const *);
|
||||
};
|
||||
|
||||
#ifdef VMS
|
||||
@ -1066,6 +1069,11 @@ extern bool cpp_error_at (cpp_reader * pfile, int level,
|
||||
source_location src_loc, const char *msgid, ...)
|
||||
ATTRIBUTE_PRINTF_4;
|
||||
|
||||
extern bool cpp_error_at_richloc (cpp_reader * pfile, int level,
|
||||
rich_location *richloc, const char *msgid,
|
||||
...)
|
||||
ATTRIBUTE_PRINTF_4;
|
||||
|
||||
/* In lex.c */
|
||||
extern int cpp_ideq (const cpp_token *, const char *);
|
||||
extern void cpp_output_line (cpp_reader *, FILE *);
|
||||
|
Loading…
x
Reference in New Issue
Block a user