C/C++: don't suggest implementation names as spelling fixes (PR c/83236)
authorDavid Malcolm <dmalcolm@redhat.com>
Wed, 6 Dec 2017 20:02:55 +0000 (20:02 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Wed, 6 Dec 2017 20:02:55 +0000 (20:02 +0000)
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
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c-family/c-spellcheck.cc
gcc/c-family/c-spellcheck.h
gcc/c/ChangeLog
gcc/c/c-decl.c
gcc/cp/ChangeLog
gcc/cp/name-lookup.c
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/spellcheck-reserved.c [new file with mode: 0644]

index ee590ed10a59cbb4300b5f1b431ba6fdc885afa4..a845fbf896632eaff8b5b6ff997480c0b5d40b7c 100644 (file)
@@ -1,3 +1,18 @@
+2017-12-06  David Malcolm  <dmalcolm@redhat.com>
+
+       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  <dmalcolm@redhat.com>
 
        * c-spellcheck.cc: New file, taken from macro-handling code in
index 1d79aee01c8b140a469e388ee08a287224f37400..6a343a31130b73f73fbf3108f1c25d21f2e217df 100644 (file)
@@ -8177,6 +8177,7 @@ void
 c_family_tests (void)
 {
   c_format_c_tests ();
+  c_spellcheck_cc_tests ();
 }
 
 } // namespace selftest
index 27b1de91b1c41184fa96a8c5d4906f3445cc5421..d9bf8d0e52bc5ad14cbaf3874be736fc3390fa78 100644 (file)
@@ -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);
index db70a64b40ccab7254a783421c6964396f694346..a6b9e172045b3cbc8865d5bb1b35c158c3609195 100644 (file)
@@ -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 */
index adc539aff1da951a799990b57fbd90f656af19f0..838f4f207f38451f09b2c0ba9dedab51936fb261 100644 (file)
@@ -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 <>
index b89939e24ad3cce720f67b1fabb01ae4978fccb7..91267c023c8c1e3de35b4c7a373ff14b80b9f764 100644 (file)
@@ -1,3 +1,9 @@
+2017-12-06  David Malcolm  <dmalcolm@redhat.com>
+
+       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  <dmalcolm@redhat.com>
 
        * c-decl.c: Include "c-family/c-spellcheck.h".
index d7dad1a29a5a2ddde6778c0c34990c6dda7ac7cb..607c705ff843b8e0d4efc38d0068032cda03c4d6 100644 (file)
@@ -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<tree, tree> 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:
index 4cd3917d8844173e976d9465df204df15f2ddf44..2cfe80b4fbc4b11b295ee9d6bb9075321980fd1a 100644 (file)
@@ -1,3 +1,9 @@
+2017-12-06  David Malcolm  <dmalcolm@redhat.com>
+
+       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  <dmalcolm@redhat.com>
 
        * name-lookup.c: Include "c-family/c-spellcheck.h".
index 482ddccfaa56818d9ddc3cee3051f20d2e896851..97d0632301d210b3f877d37732cf73cfdf6832e0 100644 (file)
@@ -5617,6 +5617,10 @@ consider_binding_level (tree name, best_match <tree, const char *> &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 <tree, const char *> &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);
     }
 }
 
index 67bdbbd5b331424f088229304cc728f5b9944a01..176777e9d8326528e52c11ca4e0cbdebc06d8ae3 100644 (file)
@@ -1,3 +1,8 @@
+2017-12-06  David Malcolm  <dmalcolm@redhat.com>
+
+       PR c/83236
+       * c-c++-common/spellcheck-reserved.c: New test case.
+
 2017-12-06  Jakub Jelinek  <jakub@redhat.com>
 
        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 (file)
index 0000000..79b6532
--- /dev/null
@@ -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_ } */
+}