Add comprehensive C++ operator linespec/location/completion tests
authorPedro Alves <palves@redhat.com>
Sat, 25 Nov 2017 00:09:25 +0000 (00:09 +0000)
committerPedro Alves <palves@redhat.com>
Sat, 25 Nov 2017 00:09:25 +0000 (00:09 +0000)
This exercises the special handling C++ operators require in several
places in the linespec parser, both the linespec and explicit location
completers, symbol lookup, etc.  Particularly, makes sure all that
works without quoting.

Note that despite the apparent smallish size, this adds thousands of
tests to the testsuite, due to combination explosion (linespecs,
explicit locations, tab completion, complete command, completion at
different points in each function, etc.)

Grows the gdb.linespec/ tests like this:

 -# of expected passes           3464
 +# of expected passes           7823

gdb/testsuite/ChangeLog:
2017-11-25  Pedro Alves  <palves@redhat.com>

* gdb.linespec/cpls-ops.cc: New file.
* gdb.linespec/cpls-ops.exp: New file.
* lib/completion-support.exp (test_complete_prefix_range_re): New,
factored out from ...
(test_complete_prefix_range): ... this.

gdb/testsuite/ChangeLog
gdb/testsuite/gdb.linespec/cpls-ops.cc [new file with mode: 0644]
gdb/testsuite/gdb.linespec/cpls-ops.exp [new file with mode: 0644]
gdb/testsuite/lib/completion-support.exp

index 469dde1f2adcb6abb7c5934da877cb819a4b8073..b45ff7b76989c126bf0f25ca316cd7ab62d6718d 100644 (file)
@@ -1,3 +1,11 @@
+2017-11-25  Pedro Alves  <palves@redhat.com>
+
+       * gdb.linespec/cpls-ops.cc: New file.
+       * gdb.linespec/cpls-ops.exp: New file.
+       * lib/completion-support.exp (test_complete_prefix_range_re): New,
+       factored out from ...
+       (test_complete_prefix_range): ... this.
+
 2017-11-24  Pedro Alves  <palves@redhat.com>
 
        * gdb.linespec/cpcompletion.exp: New file.
diff --git a/gdb/testsuite/gdb.linespec/cpls-ops.cc b/gdb/testsuite/gdb.linespec/cpls-ops.cc
new file mode 100644 (file)
index 0000000..c9b034d
--- /dev/null
@@ -0,0 +1,254 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2017 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <cstddef>
+
+/* Code for operator() tests.  */
+
+struct test_unique_op_call
+{
+  void operator() (int);
+};
+
+void
+test_unique_op_call::operator() (int)
+{}
+
+struct test_op_call
+{
+  void operator() ();
+  void operator() (int);
+  void operator() (long);
+
+  template<typename T>
+  void operator() (T *);
+};
+
+void
+test_op_call::operator() (int)
+{}
+
+void
+test_op_call::operator() ()
+{}
+
+void
+test_op_call::operator() (long)
+{}
+
+template<typename T>
+void
+test_op_call::operator() (T *t)
+{
+}
+
+/* Code for operator[] tests.  */
+
+struct test_unique_op_array
+{
+  void operator[] (int);
+};
+
+void
+test_unique_op_array::operator[] (int)
+{}
+
+struct test_op_array
+{
+  void operator[] (int);
+  void operator[] (long);
+
+  template<typename T>
+  void operator[] (T *);
+};
+
+void
+test_op_array::operator[] (int)
+{}
+
+void
+test_op_array::operator[] (long)
+{}
+
+template<typename T>
+void
+test_op_array::operator[] (T *t)
+{}
+
+/* Code for operator new tests.  */
+
+struct test_op_new
+{
+  void *operator new (size_t);
+};
+
+void *
+test_op_new::operator new (size_t)
+{
+  return NULL;
+}
+
+/* Code for operator delete tests.  */
+
+struct test_op_delete
+{
+  void operator delete (void *);
+};
+
+void
+test_op_delete::operator delete (void *)
+{
+}
+
+/* Code for operator new[] tests.  */
+
+struct test_op_new_array
+{
+  void *operator new[] (size_t);
+};
+
+void *
+test_op_new_array::operator new[] (size_t)
+{
+  return NULL;
+}
+
+/* Code for operator delete[] tests.  */
+
+struct test_op_delete_array
+{
+  void operator delete[] (void *);
+};
+
+void
+test_op_delete_array::operator delete[] (void *)
+{
+}
+
+/* Code for user-defined conversion tests.  */
+
+struct test_op_conversion_res;
+
+struct test_op_conversion
+{
+  operator const volatile test_op_conversion_res **() const volatile;
+};
+
+test_op_conversion::operator const volatile test_op_conversion_res **()
+  const volatile
+{
+  return NULL;
+}
+
+/* Code for the assignment operator tests.  */
+
+struct test_op_assign
+{
+  test_op_assign operator= (const test_op_assign &);
+};
+
+test_op_assign
+test_op_assign::operator= (const test_op_assign &)
+{
+  return test_op_assign ();
+}
+
+/* Code for the arrow operator tests.  */
+
+struct test_op_arrow
+{
+  test_op_arrow operator-> ();
+};
+
+test_op_arrow
+test_op_arrow::operator-> ()
+{
+  return test_op_arrow ();
+}
+
+/* Code for the logical/arithmetic operators tests.  */
+
+struct E
+{
+};
+
+#define GEN_OP(NS, ...)                                \
+  namespace test_ops {                         \
+    void operator __VA_ARGS__ {}               \
+  }                                            \
+  namespace test_op_ ## NS {                   \
+    void operator __VA_ARGS__ {}               \
+  }
+
+GEN_OP (PLUS_A,    +=  (E, E)  )
+GEN_OP (PLUS,      +   (E, E)  )
+GEN_OP (MINUS_A,   -=  (E, E)  )
+GEN_OP (MINUS,     -   (E, E)  )
+GEN_OP (MOD_A,     %=  (E, E)  )
+GEN_OP (MOD,       %   (E, E)  )
+GEN_OP (EQ,        ==  (E, E)  )
+GEN_OP (NEQ,       !=  (E, E)  )
+GEN_OP (LAND,      &&  (E, E)  )
+GEN_OP (LOR,       ||  (E, E)  )
+GEN_OP (SL_A,      <<= (E, E)  )
+GEN_OP (SR_A,      >>= (E, E)  )
+GEN_OP (SL,        <<  (E, E)  )
+GEN_OP (SR,        >>  (E, E)  )
+GEN_OP (OE,        |=  (E, E)  )
+GEN_OP (BIT_O,     |   (E, E)  )
+GEN_OP (XOR_A,     ^=  (E, E)  )
+GEN_OP (XOR,       ^   (E, E)  )
+GEN_OP (BIT_AND_A, &=  (E, E)  )
+GEN_OP (BIT_AND,   &   (E, E)  )
+GEN_OP (LT,        <   (E, E)  )
+GEN_OP (LTE,       <=  (E, E)  )
+GEN_OP (GTE,       >=  (E, E)  )
+GEN_OP (GT,        >   (E, E)  )
+GEN_OP (MUL_A,     *=  (E, E)  )
+GEN_OP (MUL,       *   (E, E)  )
+GEN_OP (DIV_A,     /=  (E, E)  )
+GEN_OP (DIV,       /   (E, E)  )
+GEN_OP (NEG,       ~   (E)      )
+GEN_OP (NOT,       !   (E)      )
+GEN_OP (PRE_INC,   ++  (E)      )
+GEN_OP (POST_INC,  ++  (E, int) )
+GEN_OP (PRE_DEC,   --  (E)      )
+GEN_OP (POST_DEC,  --  (E, int) )
+GEN_OP (COMMA,     ,   (E, E)  )
+
+int
+main ()
+{
+  test_op_call opcall;
+  opcall ();
+  opcall (1);
+  opcall (1l);
+  opcall ((int *) 0);
+
+  test_unique_op_call opcall2;
+  opcall2 (1);
+
+  test_op_array op_array;
+  op_array[1];
+  op_array[1l];
+  op_array[(int *) 0];
+
+  test_unique_op_array unique_op_array;
+  unique_op_array[1];
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.linespec/cpls-ops.exp b/gdb/testsuite/gdb.linespec/cpls-ops.exp
new file mode 100644 (file)
index 0000000..c1b6c33
--- /dev/null
@@ -0,0 +1,565 @@
+# Copyright 2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the gdb testsuite.
+
+load_lib completion-support.exp
+
+standard_testfile cpls-ops.cc
+
+if {[prepare_for_testing "failed to prepare" $testfile \
+        [list $srcfile] {debug}]} {
+    return -1
+}
+
+gdb_test_no_output "set max-completions unlimited"
+
+# Check that the explicit location completer manages to find the next
+# option name after a "-function function" option.  A useful test when
+# the -function options's argument is a C++ operator, which can
+# include characters like '-'.
+
+proc check_explicit_skips_function_argument {function} {
+    test_gdb_complete_unique \
+       "b -function $function -sour" \
+       "b -function $function -source"
+}
+
+# Helper function for the operator new/new[] tests.  CLASS_NAME is the
+# name of the class that contains the operator we're testing.
+# BRACKETS is set to [] if testing operator new[], and to empty if
+# testing operator new.
+
+proc test_operator_new {class_name brackets} {
+    # The type size_t is typedef-ed to.
+    set size_t "unsigned long"
+
+    # Complete all prefixes between "operato" and the full prototype.
+    foreach cmd_prefix {"b" "b -function"} {
+       set location "${class_name}::operator new${brackets}($size_t)"
+       set line "$cmd_prefix $location"
+       set start [index_after "operato" $line]
+       test_complete_prefix_range $line $start
+       check_bp_locations_match_list "$cmd_prefix $location" [list $location]
+
+       # Same, but with extra spaces.  Note that the original spaces in
+       # the input line are preserved after completion.
+
+       test_gdb_complete_unique \
+           "$cmd_prefix ${class_name}::operator new " \
+           "$cmd_prefix ${class_name}::operator new ${brackets}($size_t)"
+       test_gdb_complete_unique \
+           "$cmd_prefix ${class_name}::operator new ${brackets} (" \
+           "$cmd_prefix ${class_name}::operator new ${brackets} ($size_t)"
+       test_gdb_complete_unique \
+           "$cmd_prefix ${class_name}::operator new ${brackets} ( $size_t " \
+           "$cmd_prefix ${class_name}::operator new ${brackets} ( $size_t )"
+
+       check_setting_bp_fails "$cmd_prefix ${class_name}::operator"
+
+       set location_list \
+           [list \
+                "${class_name}::operator new${brackets}" \
+                "${class_name}::operator new${brackets} ($size_t)" \
+                "${class_name}::operator new ${brackets} ( $size_t )"]
+       foreach linespec $location_list {
+           check_bp_locations_match_list \
+               "$cmd_prefix $linespec" [list $location]
+       }
+    }
+
+    # Check that the explicit location completer manages to find the
+    # option name after -function, when the -function's argument is a
+    # C++ operator new / new[].
+    check_explicit_skips_function_argument \
+       "${class_name}::operator new ${brackets} ( $size_t )"
+}
+
+proc_with_prefix operator-new {} {
+    test_operator_new test_op_new ""
+}
+
+proc_with_prefix operator-new\[\] {} {
+    test_operator_new test_op_new_array "\[\]"
+}
+
+# Helper function for the operator delete/delete[] tests.  CLASS_NAME
+# is the name of the class that contains the operator we're testing.
+# BRACKETS is set to "[]" if testing operator delete[], and to empty
+# if testing operator delete.
+
+proc test_operator_delete {class_name brackets} {
+    # Complete all prefixes between "operato" and the full prototype.
+    foreach cmd_prefix {"b" "b -function"} {
+       set location "${class_name}::operator delete${brackets}(void*)"
+       set line "$cmd_prefix $location"
+       set start [index_after "operato" $line]
+       test_complete_prefix_range $line $start
+       check_bp_locations_match_list "$cmd_prefix $location" [list $location]
+
+       # Same, but with extra spaces.  Note that the original spaces in
+       # the input line are preserved after completion.
+
+       test_gdb_complete_unique \
+           "$cmd_prefix ${class_name}::operator delete " \
+           "$cmd_prefix ${class_name}::operator delete ${brackets}(void*)"
+       test_gdb_complete_unique \
+           "$cmd_prefix ${class_name}::operator delete ${brackets} (" \
+           "$cmd_prefix ${class_name}::operator delete ${brackets} (void*)"
+       test_gdb_complete_unique \
+           "$cmd_prefix ${class_name}::operator delete ${brackets} ( void* " \
+           "$cmd_prefix ${class_name}::operator delete ${brackets} ( void* )"
+       test_gdb_complete_unique \
+           "$cmd_prefix ${class_name}::operator delete ${brackets} ( void * " \
+           "$cmd_prefix ${class_name}::operator delete ${brackets} ( void * )"
+
+       check_setting_bp_fails "$cmd_prefix ${class_name}::operator"
+
+       set location_list \
+           [list \
+                "${class_name}::operator delete${brackets}" \
+                "${class_name}::operator delete${brackets}(void *)" \
+                "${class_name}::operator delete ${brackets} ( void * )"]
+       foreach linespec $location_list {
+           check_bp_locations_match_list \
+               "$cmd_prefix $linespec" [list $location]
+       }
+    }
+
+    # Check that the explicit location completer manages to find the
+    # option name after -function, when the -function's argument is a
+    # C++ operator delete / delete[].
+    check_explicit_skips_function_argument \
+       "${class_name}::operator delete ${brackets} ( void * )"
+}
+
+proc_with_prefix operator-delete {} {
+    test_operator_delete test_op_delete ""
+}
+
+proc_with_prefix operator-delete\[\] {} {
+    test_operator_delete test_op_delete_array "\[\]"
+}
+
+# Helper for testing both operator() and operator[].  Tests completion
+# when the operator match is unique.  CLASS_NAME is the class that
+# holds the operator to test.  OPN and CLS are the open and close
+# characters ("()" or "[]").
+
+proc test_operator_unique {class_name opn cls} {
+    # Complete all prefixes between "oper" and the full prototype.
+    foreach cmd_prefix {"b" "b -function"} {
+       set location "${class_name}::operator${opn}${cls}(int)"
+       set line "$cmd_prefix $location"
+       set start [index_after "${class_name}" $line]
+       test_complete_prefix_range $line $start
+       check_bp_locations_match_list "$cmd_prefix $location" [list $location]
+
+       # Same, but with extra spaces.  Note that the original spaces in
+       # the input line are preserved after completion.
+
+       test_gdb_complete_unique \
+           "$cmd_prefix ${class_name}::operator ${opn} ${cls} ( int " \
+           "$cmd_prefix ${class_name}::operator ${opn} ${cls} ( int )"
+       test_gdb_complete_unique \
+           "$cmd_prefix ${class_name}::operator ${opn} ${cls}" \
+           "$cmd_prefix ${class_name}::operator ${opn} ${cls}(int)"
+       test_gdb_complete_unique \
+           "$cmd_prefix ${class_name}::operator ${opn}${cls}" \
+           "$cmd_prefix ${class_name}::operator ${opn}${cls}(int)"
+       test_gdb_complete_unique \
+           "$cmd_prefix ${class_name}::operator ${opn}" \
+           "$cmd_prefix ${class_name}::operator ${opn}${cls}(int)"
+
+       check_setting_bp_fails "$cmd_prefix ${class_name}::operator"
+
+       set location_list \
+           [list \
+                "${class_name}::operator${opn}${cls}" \
+                "${class_name}::operator ${opn}${cls}" \
+                "${class_name}::operator ${opn}${cls}(int)" \
+                "${class_name}::operator ${opn} ${cls} ( int )"]
+       foreach linespec $location_list {
+           check_bp_locations_match_list \
+               "$cmd_prefix $linespec" [list $location]
+       }
+    }
+
+    # Check that the explicit location completer manages to find the
+    # option name after -function, when the -function's argument is a
+    # C++ operator().
+    check_explicit_skips_function_argument \
+       "${class_name}::operator ${opn} ${cls} ( int )"
+}
+
+# Helper for testing both operator() and operator[].  Tests completion
+# when the operator match is ambiguous.  CLASS_NAME is the class that
+# holds the operator to test.  OPN and CLS are the open and close
+# characters ("()" or "[]").
+
+proc test_operator_ambiguous {class_name opn cls} {
+    foreach cmd_prefix {"b" "b -function"} {
+       check_setting_bp_fails "$cmd_prefix ${class_name}::operator"
+
+       set linespec_noparams "${class_name}::operator${opn}${cls}"
+
+       set location_list \
+           [list \
+                "${class_name}::operator${opn}${cls}(int)" \
+                "${class_name}::operator${opn}${cls}(long)" \
+                "${class_name}::operator${opn}${cls}<int>(int*)"]
+       # The operator[] test can't have a "()" overload, since that
+       # wouldn't compile.
+       if {$opn == "("} {
+           set location_list \
+               [concat \
+                    [list "${class_name}::operator${opn}${cls}()"] \
+                    $location_list]
+       }
+       test_gdb_complete_multiple \
+           "$cmd_prefix " "$linespec_noparams" "" $location_list
+
+       # Setting the breakpoint doesn't create a breakpoint location
+       # for the template, because immediately after
+       # "operator()/operator[]" we have the template parameters, not
+       # the parameter list.
+       set location_list \
+           [list \
+                "${class_name}::operator${opn}${cls}(int)" \
+                "${class_name}::operator${opn}${cls}(long)"]
+       if {$opn == "("} {
+           set location_list \
+               [concat \
+                    [list "${class_name}::operator${opn}${cls}()"] \
+                    $location_list]
+       }
+       check_bp_locations_match_list "$cmd_prefix $linespec_noparams" \
+           $location_list
+       check_bp_locations_match_list "$cmd_prefix $linespec_noparams<int>" \
+           [list "${class_name}::operator${opn}${cls}<int>(int*)"]
+
+       # Test the template version.  Test both with and without
+       # return type.
+       test_gdb_complete_unique \
+           "$cmd_prefix ${class_name}::operator${opn}${cls}<int>(in" \
+           "$cmd_prefix ${class_name}::operator${opn}${cls}<int>(int*)"
+       check_bp_locations_match_list \
+           "$cmd_prefix ${class_name}::operator${opn}${cls}<int>(int*)" \
+           [list "${class_name}::operator${opn}${cls}<int>(int*)"]
+       test_gdb_complete_unique \
+           "$cmd_prefix void ${class_name}::operator${opn}${cls}<int>(in" \
+           "$cmd_prefix void ${class_name}::operator${opn}${cls}<int>(int*)"
+       check_bp_locations_match_list \
+           "$cmd_prefix void ${class_name}::operator${opn}${cls}<int>(int*)" \
+           [list "${class_name}::operator${opn}${cls}<int>(int*)"]
+
+       # Add extra spaces.
+       test_gdb_complete_unique \
+           "$cmd_prefix ${class_name}::operator ${opn} ${cls} ( in" \
+           "$cmd_prefix ${class_name}::operator ${opn} ${cls} ( int)"
+       check_bp_locations_match_list \
+           "$cmd_prefix ${class_name}::operator ${opn} ${cls} ( int )" \
+           [list "${class_name}::operator${opn}${cls}(int)"]
+    }
+}
+
+proc_with_prefix operator()-unique {} {
+    test_operator_unique test_unique_op_call "(" ")"
+}
+
+proc_with_prefix operator\[\]-unique {} {
+    test_operator_unique test_unique_op_array "\[" "\]"
+}
+
+proc_with_prefix operator()-ambiguous {} {
+    test_operator_ambiguous test_op_call "(" ")"
+}
+
+proc_with_prefix operator\[\]-ambiguous {} {
+    test_operator_ambiguous test_op_array "\[" "\]"
+}
+
+# Test arithmetic/logical operators.  Test completing all C++
+# arithmetic/logical operators, when all the operators are in the same
+# class.
+
+proc_with_prefix ops-valid-ambiguous {} {
+    set locations {
+       "test_ops::operator!(E)"
+       "test_ops::operator!=(E, E)"
+       "test_ops::operator%(E, E)"
+       "test_ops::operator%=(E, E)"
+       "test_ops::operator&&(E, E)"
+       "test_ops::operator&(E, E)"
+       "test_ops::operator&=(E, E)"
+       "test_ops::operator*(E, E)"
+       "test_ops::operator*=(E, E)"
+       "test_ops::operator+(E, E)"
+       "test_ops::operator++(E)"
+       "test_ops::operator++(E, int)"
+       "test_ops::operator+=(E, E)"
+       "test_ops::operator,(E, E)"
+       "test_ops::operator-(E, E)"
+       "test_ops::operator--(E)"
+       "test_ops::operator--(E, int)"
+       "test_ops::operator-=(E, E)"
+       "test_ops::operator/(E, E)"
+       "test_ops::operator/=(E, E)"
+       "test_ops::operator<(E, E)"
+       "test_ops::operator<<(E, E)"
+       "test_ops::operator<<=(E, E)"
+       "test_ops::operator<=(E, E)"
+       "test_ops::operator==(E, E)"
+       "test_ops::operator>(E, E)"
+       "test_ops::operator>=(E, E)"
+       "test_ops::operator>>(E, E)"
+       "test_ops::operator>>=(E, E)"
+       "test_ops::operator^(E, E)"
+       "test_ops::operator^=(E, E)"
+       "test_ops::operator|(E, E)"
+       "test_ops::operator|=(E, E)"
+       "test_ops::operator||(E, E)"
+       "test_ops::operator~(E)"
+    }
+    foreach linespec $locations {
+       foreach cmd_prefix {"b" "b -function"} {
+           test_gdb_complete_unique \
+               "$cmd_prefix $linespec" \
+               "$cmd_prefix $linespec"
+
+       }
+
+       check_explicit_skips_function_argument "$linespec"
+    }
+
+    foreach cmd_prefix {"b" "b -function"} {
+       test_gdb_complete_multiple \
+           "$cmd_prefix " "test_ops::operator" "" $locations
+    }
+}
+
+# Test completing all C++ operators, with and without spaces.  The
+# test without spaces makes sure the completion matches exactly the
+# expected prototype.  The version with whitespace is a bit more lax
+# for simplicity.  In that case, we only make sure we get back the
+# terminating ')'.  Each operator is defined in a separate class so
+# that we can exercise unique completion matches.
+
+proc_with_prefix ops-valid-unique {} {
+    set locations {
+       "test_op_BIT_AND::operator&(E, E)"
+       "test_op_BIT_AND_A::operator&=(E, E)"
+       "test_op_BIT_O::operator|(E, E)"
+       "test_op_COMMA::operator,(E, E)"
+       "test_op_DIV::operator/(E, E)"
+       "test_op_DIV_A::operator/=(E, E)"
+       "test_op_EQ::operator==(E, E)"
+       "test_op_GT::operator>(E, E)"
+       "test_op_GTE::operator>=(E, E)"
+       "test_op_LAND::operator&&(E, E)"
+       "test_op_LOR::operator||(E, E)"
+       "test_op_LT::operator<(E, E)"
+       "test_op_LTE::operator<=(E, E)"
+       "test_op_MINUS::operator-(E, E)"
+       "test_op_MINUS_A::operator-=(E, E)"
+       "test_op_MOD::operator%(E, E)"
+       "test_op_MOD_A::operator%=(E, E)"
+       "test_op_MUL::operator*(E, E)"
+       "test_op_MUL_A::operator*=(E, E)"
+       "test_op_NEG::operator~(E)"
+       "test_op_NEQ::operator!=(E, E)"
+       "test_op_NOT::operator!(E)"
+       "test_op_OE::operator|=(E, E)"
+       "test_op_PLUS::operator+(E, E)"
+       "test_op_PLUS_A::operator+=(E, E)"
+       "test_op_POST_DEC::operator--(E, int)"
+       "test_op_POST_INC::operator++(E, int)"
+       "test_op_PRE_DEC::operator--(E)"
+       "test_op_PRE_INC::operator++(E)"
+       "test_op_SL::operator<<(E, E)"
+       "test_op_SL_A::operator<<=(E, E)"
+       "test_op_SR::operator>>(E, E)"
+       "test_op_SR_A::operator>>=(E, E)"
+       "test_op_XOR::operator^(E, E)"
+       "test_op_XOR_A::operator^=(E, E)"
+    }
+    set linespecs_ws {
+       "test_op_BIT_AND::operator & ( E , E )"
+       "test_op_BIT_AND_A::operator &= ( E , E )"
+       "test_op_BIT_O::operator | (E , E )"
+       "test_op_COMMA::operator , ( E , E )"
+       "test_op_DIV::operator / (E , E )"
+       "test_op_DIV_A::operator /= ( E , E )"
+       "test_op_EQ::operator == ( E , E )"
+       "test_op_GT::operator > ( E , E )"
+       "test_op_GTE::operator >= ( E , E )"
+       "test_op_LAND::operator && ( E , E )"
+       "test_op_LOR::operator || ( E , E )"
+       "test_op_LT::operator < ( E , E )"
+       "test_op_LTE::operator <= ( E , E )"
+       "test_op_MINUS::operator - ( E , E )"
+       "test_op_MINUS_A::operator -= ( E , E )"
+       "test_op_MOD::operator % ( E , E )"
+       "test_op_MOD_A::operator %= ( E , E )"
+       "test_op_MUL::operator * ( E , E )"
+       "test_op_MUL_A::operator *= ( E , E )"
+       "test_op_NEG::operator ~ ( E )"
+       "test_op_NEQ::operator != ( E , E )"
+       "test_op_NOT::operator ! ( E )"
+       "test_op_OE::operator |= ( E , E )"
+       "test_op_PLUS::operator + ( E , E )"
+       "test_op_PLUS_A::operator += ( E , E )"
+       "test_op_POST_DEC::operator -- ( E , int )"
+       "test_op_POST_INC::operator ++ ( E , int )"
+       "test_op_PRE_DEC::operator -- ( E )"
+       "test_op_PRE_INC::operator ++ ( E )"
+       "test_op_SL::operator << ( E , E )"
+       "test_op_SL_A::operator <<= ( E , E )"
+       "test_op_SR::operator >> ( E , E )"
+       "test_op_SR_A::operator >>= ( E , E )"
+       "test_op_XOR::operator ^ ( E , E )"
+       "test_op_XOR_A::operator ^= ( E , E )"
+    }
+    foreach linespec $locations linespec_ws $linespecs_ws {
+       foreach cmd_prefix {"b" "b -function"} {
+           with_test_prefix "no-whitespace" {
+               set line "$cmd_prefix $linespec"
+               set start [index_after "::operato" $line]
+               test_complete_prefix_range $line $start
+           }
+
+           with_test_prefix "whitespace" {
+               set line_ws "$cmd_prefix $linespec_ws"
+               set start_ws [index_after "::operator " $line_ws]
+               test_complete_prefix_range_re \
+                   $line_ws "$cmd_prefix test_op_.*::operator .*\\\)" $start_ws
+           }
+       }
+
+       check_explicit_skips_function_argument "$linespec"
+       check_explicit_skips_function_argument "$linespec_ws"
+    }
+}
+
+# Test completing an invalid (whitespace at the wrong place) operator
+# name.
+
+proc_with_prefix ops-invalid {} {
+    foreach linespec {
+       "test_op_BIT_AND_A::operator& =(E, E)"
+       "test_op_DIV_A::operator/ =(E, E)"
+       "test_op_EQ::operator= =(E, E)"
+       "test_op_GTE::operator> =(E, E)"
+       "test_op_LAND::operator& &(E, E)"
+       "test_op_LOR::operator| |(E, E)"
+       "test_op_LTE::operator< =(E, E)"
+       "test_op_MINUS_A::operator- =(E, E)"
+       "test_op_MOD_A::operator% =(E, E)"
+       "test_op_MUL_A::operator* =(E, E)"
+       "test_op_NEQ::operator! =(E, E)"
+       "test_op_OE::operator| =(E, E)"
+       "test_op_PLUS_A::operator+ =(E, E)"
+       "test_op_POST_DEC::operator- -(E, int)"
+       "test_op_POST_INC::operator+ +(E, int)"
+       "test_op_PRE_DEC::operator- -(E)"
+       "test_op_PRE_INC::operator+ +(E)"
+       "test_op_SL::operator< <(E, E)"
+       "test_op_SL_A::operator< < =(E, E)"
+       "test_op_SR::operator> >(E, E)"
+       "test_op_SR_A::operator> > =(E, E)"
+       "test_op_XOR_A::operator^ =(E, E)"
+    } {
+       foreach cmd_prefix {"b" "b -function"} {
+           test_gdb_complete_tab_none "$cmd_prefix $linespec"
+           check_setting_bp_fails "$cmd_prefix $linespec"
+       }
+    }
+}
+
+# Test completing function/method FUNCTION.  Completion is tested at
+# every point starting after START_AFTER.  FUNCTION_WS is a version of
+# FUNCTION with extra (but valid) whitespace.  FUNCTION_INVALID is a
+# version of FUNCTION with invalid whitespace.  Tests that completion
+# of FUNCTION_WS completes to self, and that a completion of
+# FUNCTION_INVALID fails.
+
+proc test_function {function start_after function_ws {function_invalid ""}} {
+    foreach cmd_prefix {"b" "b -function"} {
+       set line "$cmd_prefix $function"
+       set start [index_after $start_after $line]
+       test_complete_prefix_range $line $start
+    }
+
+    check_explicit_skips_function_argument $function
+    check_explicit_skips_function_argument $function_ws
+
+    foreach cmd_prefix {"b" "b -function"} {
+       test_gdb_complete_unique \
+           "$cmd_prefix $function_ws" \
+           "$cmd_prefix $function_ws"
+       if {$function_invalid != ""} {
+           test_gdb_complete_tab_none "$cmd_prefix $function_invalid"
+           check_setting_bp_fails "$cmd_prefix $function_invalid"
+       }
+    }
+}
+
+# Test completing a user-defined conversion operator.
+
+proc_with_prefix conversion-operator {} {
+    test_function \
+       "test_op_conversion::operator test_op_conversion_res const volatile**() const volatile" \
+       "test_op_conversio" \
+       "test_op_conversion::operator test_op_conversion_res const volatile * * ( ) const volatile"}
+
+# Test completing an assignment operator.
+
+proc_with_prefix assignment-operator {} {
+    test_function \
+       "test_op_assign::operator=(test_op_assign const&)" \
+       "test_op_assig" \
+       "test_op_assign::operator = ( test_op_assign const & )" \
+}
+
+# Test completing an arrow operator.
+
+proc_with_prefix arrow-operator {} {
+    test_function \
+       "test_op_arrow::operator->()" \
+       "test_op_arro" \
+       "test_op_arrow::operator -> ( )" \
+       "test_op_arrow::operator - > ( )"
+}
+
+# The testcase driver.  Calls all test procedures.
+
+proc test_driver {} {
+    operator-delete
+    operator-delete\[\]
+    operator-new
+    operator-new\[\]
+    operator()-unique
+    operator()-ambiguous
+    operator\[\]-unique
+    operator\[\]-ambiguous
+    ops-valid-ambiguous
+    ops-valid-unique
+    ops-invalid
+    conversion-operator
+    assignment-operator
+    arrow-operator
+}
+
+test_driver
index 70e6aec895b37833e39403007f28194f8db7c8bf..25332cc0a49fcc8198951b3991a131069c6883b6 100644 (file)
@@ -259,21 +259,30 @@ proc test_gdb_complete_multiple { cmd_prefix completion_word add_completed_line
     test_gdb_complete_cmd_multiple $cmd_prefix $completion_word $completion_list $start_quote_char $end_quote_char
 }
 
-# Test that all the substring prefixes of COMPLETION from [0..START)
-# to [0..END) complete to COMPLETION.  If END is ommitted, default to
-# the length of COMPLETION.
+# Test that all the substring prefixes of INPUT from [0..START) to
+# [0..END) complete to COMPLETION_RE (a regular expression).  If END
+# is ommitted, default to the length of INPUT.
 
-proc test_complete_prefix_range {completion start {end -1}} {
+proc test_complete_prefix_range_re {input completion_re start {end -1}} {
     if {$end == -1} {
-       set end [string length $completion]
+       set end [string length $input]
     }
 
     for {set i $start} {$i < $end} {incr i} {
-       set line [string range $completion 0 $i]
-       test_gdb_complete_unique "$line" "$completion"
+       set line [string range $input 0 $i]
+       test_gdb_complete_unique_re "$line" $completion_re
     }
 }
 
+# Test that all the substring prefixes of COMPLETION from [0..START)
+# to [0..END) complete to COMPLETION.  If END is ommitted, default to
+# the length of COMPLETION.
+
+proc test_complete_prefix_range {completion start {end -1}} {
+    set completion_re [string_to_regexp $completion]
+    test_complete_prefix_range_re $completion $completion_re $start $end
+}
+
 # Find NEEDLE in HAYSTACK and return the index _after_ NEEDLE.  E.g.,
 # searching for "(" in "foo(int)" returns 4, which would be useful if
 # you want to find the "(" to try completing "foo(".