From c79144f8353af3292903c9c8e508f1de986eb6b0 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 6 Dec 2017 20:02:55 +0000 Subject: [PATCH] C/C++: don't suggest implementation names as spelling fixes (PR c/83236) gcc/c-family/ChangeLog: PR c/83236 * c-common.c (selftest::c_family_tests): Call selftest::c_spellcheck_cc_tests. * c-common.h (selftest::c_spellcheck_cc_tests): New decl. * c-spellcheck.cc: Include "selftest.h". (name_reserved_for_implementation_p): New function. (should_suggest_as_macro_p): New function. (find_closest_macro_cpp_cb): Move the check for NT_MACRO to should_suggest_as_macro_p and call it. (selftest::test_name_reserved_for_implementation_p): New function. (selftest::c_spellcheck_cc_tests): New function. * c-spellcheck.h (name_reserved_for_implementation_p): New decl. gcc/c/ChangeLog: PR c/83236 * c-decl.c (lookup_name_fuzzy): Don't suggest names that are reserved for use by the implementation. gcc/cp/ChangeLog: PR c/83236 * name-lookup.c (consider_binding_level): Don't suggest names that are reserved for use by the implementation. gcc/testsuite/ChangeLog: PR c/83236 * c-c++-common/spellcheck-reserved.c: New test case. From-SVN: r255453 --- gcc/c-family/ChangeLog | 15 +++++ gcc/c-family/c-common.c | 1 + gcc/c-family/c-common.h | 1 + gcc/c-family/c-spellcheck.cc | 66 ++++++++++++++++++- gcc/c-family/c-spellcheck.h | 2 + gcc/c/ChangeLog | 6 ++ gcc/c/c-decl.c | 12 ++++ gcc/cp/ChangeLog | 6 ++ gcc/cp/name-lookup.c | 25 +++++-- gcc/testsuite/ChangeLog | 5 ++ .../c-c++-common/spellcheck-reserved.c | 55 ++++++++++++++++ 11 files changed, 189 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/spellcheck-reserved.c diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index ee590ed10a5..a845fbf8966 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,18 @@ +2017-12-06 David Malcolm + + PR c/83236 + * c-common.c (selftest::c_family_tests): Call + selftest::c_spellcheck_cc_tests. + * c-common.h (selftest::c_spellcheck_cc_tests): New decl. + * c-spellcheck.cc: Include "selftest.h". + (name_reserved_for_implementation_p): New function. + (should_suggest_as_macro_p): New function. + (find_closest_macro_cpp_cb): Move the check for NT_MACRO to + should_suggest_as_macro_p and call it. + (selftest::test_name_reserved_for_implementation_p): New function. + (selftest::c_spellcheck_cc_tests): New function. + * c-spellcheck.h (name_reserved_for_implementation_p): New decl. + 2017-12-06 David Malcolm * c-spellcheck.cc: New file, taken from macro-handling code in diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 1d79aee01c8..6a343a31130 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -8177,6 +8177,7 @@ void c_family_tests (void) { c_format_c_tests (); + c_spellcheck_cc_tests (); } } // namespace selftest diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 27b1de91b1c..d9bf8d0e52b 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1450,6 +1450,7 @@ namespace selftest { /* Declarations for specific families of tests within c-family, by source file, in alphabetical order. */ extern void c_format_c_tests (void); + extern void c_spellcheck_cc_tests (void); /* The entrypoint for running all of the above tests. */ extern void c_family_tests (void); diff --git a/gcc/c-family/c-spellcheck.cc b/gcc/c-family/c-spellcheck.cc index db70a64b40c..a6b9e172045 100644 --- a/gcc/c-family/c-spellcheck.cc +++ b/gcc/c-family/c-spellcheck.cc @@ -25,6 +25,37 @@ along with GCC; see the file COPYING3. If not see #include "cpplib.h" #include "spellcheck-tree.h" #include "c-family/c-spellcheck.h" +#include "selftest.h" + +/* Return true iff STR begin with an underscore and either an uppercase + letter or another underscore, and is thus, for C and C++, reserved for + use by the implementation. */ + +bool +name_reserved_for_implementation_p (const char *str) +{ + if (str[0] != '_') + return false; + return (str[1] == '_' || ISUPPER(str[1])); +} + +/* Return true iff HASHNODE is a macro that should be offered as a + suggestion for a misspelling. */ + +static bool +should_suggest_as_macro_p (cpp_hashnode *hashnode) +{ + if (hashnode->type != NT_MACRO) + return false; + + /* Don't suggest names reserved for the implementation, but do suggest the builtin + macros such as __FILE__, __LINE__ etc. */ + if (name_reserved_for_implementation_p ((const char *)hashnode->ident.str) + && !(hashnode->flags & NODE_BUILTIN)) + return false; + + return true; +} /* A callback for cpp_forall_identifiers, for use by best_macro_match's ctor. Process HASHNODE and update the best_macro_match instance pointed to be @@ -34,7 +65,7 @@ static int find_closest_macro_cpp_cb (cpp_reader *, cpp_hashnode *hashnode, void *user_data) { - if (hashnode->type != NT_MACRO) + if (!should_suggest_as_macro_p (hashnode)) return 1; best_macro_match *bmm = (best_macro_match *)user_data; @@ -55,3 +86,36 @@ best_macro_match::best_macro_match (tree goal, { cpp_forall_identifiers (reader, find_closest_macro_cpp_cb, this); } + +#if CHECKING_P + +namespace selftest { + +/* Selftests. */ + +/* Verify that name_reserved_for_implementation_p is sane. */ + +static void +test_name_reserved_for_implementation_p () +{ + ASSERT_FALSE (name_reserved_for_implementation_p ("")); + ASSERT_FALSE (name_reserved_for_implementation_p ("foo")); + ASSERT_FALSE (name_reserved_for_implementation_p ("_")); + ASSERT_FALSE (name_reserved_for_implementation_p ("_foo")); + ASSERT_FALSE (name_reserved_for_implementation_p ("_42")); + ASSERT_TRUE (name_reserved_for_implementation_p ("_Foo")); + ASSERT_TRUE (name_reserved_for_implementation_p ("__")); + ASSERT_TRUE (name_reserved_for_implementation_p ("__foo")); +} + +/* Run all of the selftests within this file. */ + +void +c_spellcheck_cc_tests () +{ + test_name_reserved_for_implementation_p (); +} + +} // namespace selftest + +#endif /* #if CHECKING_P */ diff --git a/gcc/c-family/c-spellcheck.h b/gcc/c-family/c-spellcheck.h index adc539aff1d..838f4f207f3 100644 --- a/gcc/c-family/c-spellcheck.h +++ b/gcc/c-family/c-spellcheck.h @@ -22,6 +22,8 @@ along with GCC; see the file COPYING3. If not see #include "spellcheck.h" +extern bool name_reserved_for_implementation_p (const char *str); + /* Specialization of edit_distance_traits for preprocessor macros. */ template <> diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index b89939e24ad..91267c023c8 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,9 @@ +2017-12-06 David Malcolm + + PR c/83236 + * c-decl.c (lookup_name_fuzzy): Don't suggest names that are + reserved for use by the implementation. + 2017-12-06 David Malcolm * c-decl.c: Include "c-family/c-spellcheck.h". diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index d7dad1a29a5..607c705ff84 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -4027,6 +4027,10 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc) IDENTIFIER_POINTER (name), header_hint)); + /* Only suggest names reserved for the implementation if NAME begins + with an underscore. */ + bool consider_implementation_names = (IDENTIFIER_POINTER (name)[0] == '_'); + best_match bm (name); /* Look within currently valid scopes. */ @@ -4042,6 +4046,14 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc) if (TREE_CODE (binding->decl) == FUNCTION_DECL) if (C_DECL_IMPLICIT (binding->decl)) continue; + /* Don't suggest names that are reserved for use by the + implementation, unless NAME began with an underscore. */ + if (!consider_implementation_names) + { + const char *suggestion_str = IDENTIFIER_POINTER (binding->id); + if (name_reserved_for_implementation_p (suggestion_str)) + continue; + } switch (kind) { case FUZZY_LOOKUP_TYPENAME: diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4cd3917d884..2cfe80b4fbc 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2017-12-06 David Malcolm + + PR c/83236 + * name-lookup.c (consider_binding_level): Don't suggest names that + are reserved for use by the implementation. + 2017-12-06 David Malcolm * name-lookup.c: Include "c-family/c-spellcheck.h". diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 482ddccfaa5..97d0632301d 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -5617,6 +5617,10 @@ consider_binding_level (tree name, best_match &bm, bm.consider (IDENTIFIER_POINTER (best_matching_field)); } + /* Only suggest names reserved for the implementation if NAME begins + with an underscore. */ + bool consider_implementation_names = (IDENTIFIER_POINTER (name)[0] == '_'); + for (tree t = lvl->names; t; t = TREE_CHAIN (t)) { tree d = t; @@ -5637,10 +5641,23 @@ consider_binding_level (tree name, best_match &bm, && DECL_ANTICIPATED (d)) continue; - if (tree name = DECL_NAME (d)) - /* Ignore internal names with spaces in them. */ - if (!strchr (IDENTIFIER_POINTER (name), ' ')) - bm.consider (IDENTIFIER_POINTER (name)); + tree suggestion = DECL_NAME (d); + if (!suggestion) + continue; + + const char *suggestion_str = IDENTIFIER_POINTER (suggestion); + + /* Ignore internal names with spaces in them. */ + if (strchr (suggestion_str, ' ')) + continue; + + /* Don't suggest names that are reserved for use by the + implementation, unless NAME began with an underscore. */ + if (name_reserved_for_implementation_p (suggestion_str) + && !consider_implementation_names) + continue; + + bm.consider (suggestion_str); } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 67bdbbd5b33..176777e9d83 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2017-12-06 David Malcolm + + PR c/83236 + * c-c++-common/spellcheck-reserved.c: New test case. + 2017-12-06 Jakub Jelinek PR tree-optimization/83293 diff --git a/gcc/testsuite/c-c++-common/spellcheck-reserved.c b/gcc/testsuite/c-c++-common/spellcheck-reserved.c new file mode 100644 index 00000000000..79b653241dc --- /dev/null +++ b/gcc/testsuite/c-c++-common/spellcheck-reserved.c @@ -0,0 +1,55 @@ +/* Verify that we don't offer names that are reserved for the + implementation (PR c/83236). */ +/* { dg-options "-nostdinc" } */ + +/* Example of an identifier with a leading double-underscore. + We shouldn't offer '__ino_t' as a suggestion for an unknown 'ino_t'. */ + +typedef unsigned long int __ino_t; +ino_t inode; /* { dg-error "did you mean 'int'" } */ + + +/* Example of a typedef with a leading double-underscore. */ + +typedef unsigned char __u_char; +u_char ch; /* { dg-error "did you mean 'char'" } */ + + +/* Example of a macro with a leading double-underscore. */ + +# define __SOME_MACRO int + +SOME_MACRO foo; /* { dg-bogus "__SOME_MACRO" } */ +/* { dg-error "'SOME_MACRO'" "" { target *-*-* } .-1 } */ + + +/* If the misspelled name itself matches the "reserved" pattern, then + it's OK to suggest such names. */ + +void test (const char *buf, char ch) +{ + __builtin_strtchr (buf, ch); /* { dg-line misspelled_reserved } */ + /* { dg-warning "did you mean '__builtin_strchr'" "" { target c } misspelled_reserved } */ + /* { dg-error "not declared" "" { target c++ } misspelled_reserved } */ + /* { dg-message "'__builtin_strrchr'" "" { target c++ } misspelled_reserved } */ +} + +/* Similarly for a name that begins with a single underscore. */ + +void test_2 (const char *buf, char ch) +{ + _builtin_strchr (buf, ch); /* { dg-line misspelled_one_underscore } */ + /* { dg-warning "did you mean '__builtin_strchr'" "" { target c } misspelled_one_underscore } */ + /* { dg-error "not declared" "" { target c++ } misspelled_one_underscore } */ + /* { dg-message "'__builtin_strchr'" "" { target c++ } misspelled_one_underscore } */ +} + +/* Verify that we can correct "__FILE_" to "__FILE__". */ + +const char * test_3 (void) +{ + return __FILE_; /* { dg-line misspelled__FILE_ } */ + /* { dg-error "did you mean '__FILE__'" "" { target c } misspelled__FILE_ } */ + /* { dg-error "not declared" "" { target c++ } misspelled__FILE_ } */ + /* { dg-message "'__FILE__'" "" { target c++ } misspelled__FILE_ } */ +} -- 2.30.2