summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2017-06-01 17:03:20 +0100
committerPedro Alves <palves@redhat.com>2017-10-19 18:30:30 +0100
commit591ee3fe46ebaf793d09897e8b624809b54abfde (patch)
tree1355313ff7fadea803d0692348c1c116b077dd50
parenta35888f2a1e5edaf8b9e9f8bebb25975049209a5 (diff)
downloadbinutils-gdb-591ee3fe46ebaf793d09897e8b624809b54abfde.tar.gz
Comprehensive C++ linespec/completer tests
Exercises all sorts of aspects fixed by the previous patches. - Exercises label completion, linespecs and explicit locations. - Exercises both quoting vs non-quoting, source filenames, function names, labels, with both linespecs and explicit locations. - Tests corner cases around not-quoting function names, and whitespace and/and completing inside a parameter or template argument list, anonymous namespace awareness, etc. E.g., "break foo<[TAB]" -> "break foo<int>()" "break bar ( int[TAB]" -> "break bar ( int) "break ( anon" -> "break ( anonymous namespace)::func()" "b cfunc() [tab]" -> "b cfunc() const" "b rettype templfunc[tab]" -> "b rettype templfunc<bar>()" ... and others. - Tests the "b source.c[TAB] -> b source.cc:" feature. I.e., colon auto-appending. - Exercises corner cases around C++ "operator<" / "operator<<". (Much more extensive C++ operator completion/linespec handling in a separate patch.) - Exercises both tab completion and "complete" command completion, using routines that handle it automatically, to ensure no test forgets either mode. - Many of the completion tests test completion at at prefix of a given tricky name, to make sure all corner cases are covered. E.g., completing before, at and after ":", "(", "<". - Exercises "keyword" completion. I.e., "b function() [TAB]" displaying "if task thread" as completion match list. Likewise for display explicit location options matches at the appropriate points. - Exercises matching symbols in all scopes (wild matching). Ensures that the completer finds the same breakpoint locations that setting a breakpoint finds. - Tests that linespec/location completion doesn't find data symbols. - Tests that expression completion still kicks in after a linespec/location keyword. I.e., this: "b function () if global1 + global[TAB]" knows that after "if", you're completing on an expression, and thus breaks words after "if" as an expression and matches on "global" as a data symbol. - Adds common routines to help with all the above, to be used by multiple completion and linespec/location test cases. - More... Grows the gdb.linespec/ tests like this: -# of expected passes 573 +# of expected passes 4458 gdb/testsuite/ChangeLog: yyyy-mm-dd Pedro Alves <palves@redhat.com> * gdb.linespec/cpcompletion.exp: New file. * gdb.linespec/cpls-hyphen.cc: New file. * gdb.linespec/cpls.cc: New file. * gdb.linespec/cpls2.cc: New file. * gdb.linespec/explicit.exp: Load completion-support.exp. Adjust test to use test_gdb_complete_unique. Add label completion, keyword completion and explicit location completion tests. * lib/completion-support.exp: New file.
-rw-r--r--gdb/testsuite/gdb.linespec/cpcompletion.exp959
-rw-r--r--gdb/testsuite/gdb.linespec/cpls-hyphen.cc14
-rw-r--r--gdb/testsuite/gdb.linespec/cpls.cc386
-rw-r--r--gdb/testsuite/gdb.linespec/cpls2.cc46
-rw-r--r--gdb/testsuite/gdb.linespec/explicit.exp209
-rw-r--r--gdb/testsuite/lib/completion-support.exp513
6 files changed, 2120 insertions, 7 deletions
diff --git a/gdb/testsuite/gdb.linespec/cpcompletion.exp b/gdb/testsuite/gdb.linespec/cpcompletion.exp
new file mode 100644
index 00000000000..dd9bf709e32
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/cpcompletion.exp
@@ -0,0 +1,959 @@
+# 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.cc cpls2.cc cpls-hyphen.cc
+
+if {[prepare_for_testing "failed to prepare" $testfile \
+ [list $srcfile $srcfile2 $srcfile3] {debug}]} {
+ return -1
+}
+
+# Disable the completion limit for the whole testcase.
+gdb_test_no_output "set max-completions unlimited"
+
+set timeout 5
+
+# Start of tests.
+
+# Test completion of all parameter prefixes, crossing "(" and ")",
+# with and without whitespace.
+
+proc_with_prefix all-param-prefixes {} {
+
+ # Test both linespecs and explicit locations.
+ foreach cmd_prefix {"b" "b -function"} {
+ set line "$cmd_prefix param_prefixes_test_long(long)"
+ set start [index_after "test_long" $line]
+ test_complete_prefix_range $line $start
+
+ # Same, but with extra spaces. Note that the original spaces in
+ # the input line are preserved after completion.
+ test_gdb_complete_unique \
+ "$cmd_prefix param_prefixes_test_long(long " \
+ "$cmd_prefix param_prefixes_test_long(long )"
+ test_gdb_complete_unique \
+ "$cmd_prefix param_prefixes_test_long( long " \
+ "$cmd_prefix param_prefixes_test_long( long )"
+ test_gdb_complete_unique \
+ "$cmd_prefix param_prefixes_test_long ( long " \
+ "$cmd_prefix param_prefixes_test_long ( long )"
+
+ # Complete all parameter prefixes between "(i" and "(int*, int&)".
+ # Note that this exercises completing when the point is at the
+ # space in "param_prefixes_test_intp_intr(int*, ".
+ set line "$cmd_prefix param_prefixes_test_intp_intr(int*, int&)"
+ set start [index_after "intp_intr" $line]
+ test_complete_prefix_range $line $start
+
+ # Similar, but with extra spaces.
+ test_gdb_complete_unique \
+ "$cmd_prefix param_prefixes_test_intp_intr ( int* " \
+ "$cmd_prefix param_prefixes_test_intp_intr ( int* , int&)"
+
+ test_gdb_complete_unique \
+ "$cmd_prefix param_prefixes_test_intp_intr ( int *" \
+ "$cmd_prefix param_prefixes_test_intp_intr ( int *, int&)"
+
+ test_gdb_complete_unique \
+ "$cmd_prefix param_prefixes_test_intp_intr ( int *, int " \
+ "$cmd_prefix param_prefixes_test_intp_intr ( int *, int &)"
+
+ test_gdb_complete_unique \
+ "$cmd_prefix param_prefixes_test_intp_intr ( int *, int & " \
+ "$cmd_prefix param_prefixes_test_intp_intr ( int *, int & )"
+ }
+}
+
+# Test completion of an overloaded function.
+
+proc_with_prefix overload {} {
+ set completion_list {
+ "overload_ambiguous_test(int, int)"
+ "overload_ambiguous_test(int, long)"
+ "overload_ambiguous_test(long)"
+ }
+
+ foreach cmd_prefix {"b" "b -function"} {
+ test_gdb_complete_multiple \
+ "$cmd_prefix " "overload_ambiguous_" "test(" \
+ $completion_list
+ check_bp_locations_match_list \
+ "$cmd_prefix overload_ambiguous_test" \
+ $completion_list
+
+ # Test disambiguating by typing enough to pick the "int" as
+ # first parameter type. This then tests handling ambiguity in
+ # the second parameter, which checks that tab completion when
+ # the point is at the whitespace behaves naturally, by showing
+ # the remaining matching overloads to the user.
+ test_gdb_complete_multiple \
+ "$cmd_prefix " "overload_ambiguous_test(i" "nt, " {
+ "overload_ambiguous_test(int, int)"
+ "overload_ambiguous_test(int, long)"
+ }
+
+ # Add a few more characters to make the completion
+ # unambiguous.
+ test_gdb_complete_unique \
+ "$cmd_prefix overload_ambiguous_test(int, i" \
+ "$cmd_prefix overload_ambiguous_test(int, int)"
+ check_bp_locations_match_list \
+ "$cmd_prefix overload_ambiguous_test(int, int)" {
+ "overload_ambiguous_test(int, int)"
+ }
+ }
+}
+
+# Test completion of a function that is defined in different scopes
+# with different parameters.
+
+proc_with_prefix overload-2 {} {
+ with_test_prefix "all" {
+ set completion_list {
+ "(anonymous namespace)::overload2_function(overload2_arg3)"
+ "(anonymous namespace)::struct_overload2_test::overload2_function(overload2_arg4)"
+ "ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_function(overload2_arg9)"
+ "ns_overload2_test::(anonymous namespace)::ns_overload2_test::struct_overload2_test::overload2_function(overload2_arga)"
+ "ns_overload2_test::(anonymous namespace)::overload2_function(overload2_arg7)"
+ "ns_overload2_test::(anonymous namespace)::struct_overload2_test::overload2_function(overload2_arg8)"
+ "ns_overload2_test::overload2_function(overload2_arg5)"
+ "ns_overload2_test::struct_overload2_test::overload2_function(overload2_arg6)"
+ "overload2_function(overload2_arg1)"
+ "struct_overload2_test::overload2_function(overload2_arg2)"
+ }
+ foreach cmd_prefix {"b" "b -function"} {
+ test_gdb_complete_multiple \
+ "$cmd_prefix " "overload2_func" "tion(overload2_arg" $completion_list
+ check_bp_locations_match_list \
+ "$cmd_prefix overload2_function" $completion_list
+ }
+ }
+
+ # Same, but restrict to functions/methods in some scope.
+ with_test_prefix "restrict scope" {
+ set completion_list {
+ "ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_function(overload2_arg9)"
+ "ns_overload2_test::overload2_function(overload2_arg5)"
+ }
+ foreach cmd_prefix {"b" "b -function"} {
+ test_gdb_complete_multiple \
+ "$cmd_prefix " "ns_overload2_test::overload2_func" "tion(overload2_arg" $completion_list
+ check_bp_locations_match_list \
+ "$cmd_prefix ns_overload2_test::overload2_function" $completion_list
+ }
+ }
+
+ # Restrict to anonymous namespace scopes.
+ with_test_prefix "restrict scope 2" {
+ set completion_list {
+ "(anonymous namespace)::overload2_function(overload2_arg3)"
+ "ns_overload2_test::(anonymous namespace)::overload2_function(overload2_arg7)"
+ }
+ foreach cmd_prefix {"b" "b -function"} {
+ test_gdb_complete_multiple \
+ "$cmd_prefix " "(anonymous namespace)::overload2_func" "tion(overload2_arg" $completion_list
+ check_bp_locations_match_list \
+ "$cmd_prefix (anonymous namespace)::overload2_function" $completion_list
+ }
+ }
+
+ # Add enough scopes, and we get a unique completion.
+ with_test_prefix "unique completion" {
+ foreach cmd_prefix {"b" "b -function"} {
+ test_gdb_complete_unique \
+ "$cmd_prefix ns_overload2_test::(anonymous namespace)::overload2_func" \
+ "$cmd_prefix ns_overload2_test::(anonymous namespace)::overload2_function(overload2_arg7)"
+ check_setting_bp_fails "$cmd_prefix ns_overload2_test::(anonymous namespace)::overload2_func"
+ check_bp_locations_match_list \
+ "$cmd_prefix ns_overload2_test::(anonymous namespace)::overload2_function" \
+ {"ns_overload2_test::(anonymous namespace)::overload2_function(overload2_arg7)"}
+ }
+ }
+}
+
+# Test linespecs / locations using fully-qualified names.
+
+proc_with_prefix fqn {} {
+ set cmd_prefix "b -qualified"
+
+ test_gdb_complete_unique \
+ "$cmd_prefix overload2_func" \
+ "$cmd_prefix overload2_function(overload2_arg1)"
+
+ # Drill down until we find a unique completion.
+ test_gdb_complete_multiple "$cmd_prefix " "ns_overload2_test::" "" {
+ "ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_function(overload2_arg9)"
+ "ns_overload2_test::(anonymous namespace)::ns_overload2_test::struct_overload2_test::overload2_function(overload2_arga)"
+ "ns_overload2_test::(anonymous namespace)::overload2_function(overload2_arg7)"
+ "ns_overload2_test::(anonymous namespace)::struct_overload2_test::overload2_function(overload2_arg8)"
+ "ns_overload2_test::overload2_function(overload2_arg5)"
+ "ns_overload2_test::struct_overload2_test::overload2_function(overload2_arg6)"
+ }
+
+ test_gdb_complete_multiple "$cmd_prefix " "ns_overload2_test::(anonymous namespace)::" "" {
+ "ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_function(overload2_arg9)"
+ "ns_overload2_test::(anonymous namespace)::ns_overload2_test::struct_overload2_test::overload2_function(overload2_arga)"
+ "ns_overload2_test::(anonymous namespace)::overload2_function(overload2_arg7)"
+ "ns_overload2_test::(anonymous namespace)::struct_overload2_test::overload2_function(overload2_arg8)"
+ }
+
+ test_gdb_complete_multiple "$cmd_prefix " "ns_overload2_test::(anonymous namespace)::ns_overload2_test::" "" {
+ "ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_function(overload2_arg9)"
+ "ns_overload2_test::(anonymous namespace)::ns_overload2_test::struct_overload2_test::overload2_function(overload2_arga)"
+ }
+
+ test_gdb_complete_unique \
+ "$cmd_prefix ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_func" \
+ "$cmd_prefix ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_function(overload2_arg9)"
+}
+
+# Check that a fully-qualified looked name don't match symbols in
+# nested scopes.
+
+proc_with_prefix fqn-2 {} {
+ set linespec "struct_overload2_test::overload2_function(overload2_arg6)"
+ set cmd_prefix "b -qualified"
+ check_setting_bp_fails "$cmd_prefix $linespec"
+ test_gdb_complete_none "$cmd_prefix $linespec"
+
+ # Check that using the same name, but not fully-qualifying it,
+ # would find something, just to make sure the test above is
+ # testing what we intend to test.
+ set cmd_prefix "b -function"
+ test_gdb_complete_unique "$cmd_prefix $linespec" "$cmd_prefix $linespec"
+ check_bp_locations_match_list \
+ "$cmd_prefix $linespec" \
+ {"ns_overload2_test::struct_overload2_test::overload2_function(overload2_arg6)"}
+}
+
+# Test completion of functions in different scopes that have the same
+# name and parameters. Restricting the scopes should find fewer and
+# fewer matches.
+
+proc_with_prefix overload-3 {} {
+ with_test_prefix "all overloads" {
+ set completion_list {
+ "(anonymous namespace)::overload3_function(int)"
+ "(anonymous namespace)::overload3_function(long)"
+ "(anonymous namespace)::struct_overload3_test::overload3_function(int)"
+ "(anonymous namespace)::struct_overload3_test::overload3_function(long)"
+ "ns_overload3_test::(anonymous namespace)::ns_overload3_test::overload3_function(int)"
+ "ns_overload3_test::(anonymous namespace)::ns_overload3_test::overload3_function(long)"
+ "ns_overload3_test::(anonymous namespace)::ns_overload3_test::struct_overload3_test::overload3_function(int)"
+ "ns_overload3_test::(anonymous namespace)::ns_overload3_test::struct_overload3_test::overload3_function(long)"
+ "ns_overload3_test::(anonymous namespace)::overload3_function(int)"
+ "ns_overload3_test::(anonymous namespace)::overload3_function(long)"
+ "ns_overload3_test::(anonymous namespace)::struct_overload3_test::overload3_function(int)"
+ "ns_overload3_test::(anonymous namespace)::struct_overload3_test::overload3_function(long)"
+ "ns_overload3_test::overload3_function(int)"
+ "ns_overload3_test::overload3_function(long)"
+ "ns_overload3_test::struct_overload3_test::overload3_function(int)"
+ "ns_overload3_test::struct_overload3_test::overload3_function(long)"
+ "overload3_function(int)"
+ "overload3_function(long)"
+ "struct_overload3_test::overload3_function(int)"
+ "struct_overload3_test::overload3_function(long)"
+ }
+ foreach cmd_prefix {"b" "b -function"} {
+ test_gdb_complete_multiple "$cmd_prefix " "overload3_func" "tion(" $completion_list
+ check_bp_locations_match_list "$cmd_prefix overload3_function" $completion_list
+ }
+ }
+
+ with_test_prefix "restrict overload" {
+ foreach cmd_prefix {"b" "b -function"} {
+ test_gdb_complete_unique \
+ "$cmd_prefix overload3_function(int)" \
+ "$cmd_prefix overload3_function(int)"
+ check_bp_locations_match_list "$cmd_prefix overload3_function(int)" {
+ "(anonymous namespace)::overload3_function(int)"
+ "(anonymous namespace)::struct_overload3_test::overload3_function(int)"
+ "ns_overload3_test::(anonymous namespace)::ns_overload3_test::overload3_function(int)"
+ "ns_overload3_test::(anonymous namespace)::ns_overload3_test::struct_overload3_test::overload3_function(int)"
+ "ns_overload3_test::(anonymous namespace)::overload3_function(int)"
+ "ns_overload3_test::(anonymous namespace)::struct_overload3_test::overload3_function(int)"
+ "ns_overload3_test::overload3_function(int)"
+ "ns_overload3_test::struct_overload3_test::overload3_function(int)"
+ "overload3_function(int)"
+ "struct_overload3_test::overload3_function(int)"
+ }
+ }
+ }
+
+ with_test_prefix "restrict scope" {
+ set completion_list {
+ "(anonymous namespace)::struct_overload3_test::overload3_function(int)"
+ "(anonymous namespace)::struct_overload3_test::overload3_function(long)"
+ "ns_overload3_test::(anonymous namespace)::ns_overload3_test::struct_overload3_test::overload3_function(int)"
+ "ns_overload3_test::(anonymous namespace)::ns_overload3_test::struct_overload3_test::overload3_function(long)"
+ "ns_overload3_test::(anonymous namespace)::struct_overload3_test::overload3_function(int)"
+ "ns_overload3_test::(anonymous namespace)::struct_overload3_test::overload3_function(long)"
+ "ns_overload3_test::struct_overload3_test::overload3_function(int)"
+ "ns_overload3_test::struct_overload3_test::overload3_function(long)"
+ "struct_overload3_test::overload3_function(int)"
+ "struct_overload3_test::overload3_function(long)"
+ }
+ foreach cmd_prefix {"b" "b -function"} {
+ test_gdb_complete_multiple \
+ "$cmd_prefix " "struct_overload3_test::overload3_func" "tion(" \
+ $completion_list
+ check_bp_locations_match_list \
+ "$cmd_prefix struct_overload3_test::overload3_function" \
+ $completion_list
+ }
+ }
+}
+
+# Test completing an overloaded template method.
+
+proc_with_prefix template-overload {} {
+ set completion_list {
+ "template_struct<int>::template_overload_fn(int)"
+ "template_struct<long>::template_overload_fn(long)"
+ }
+ foreach cmd_prefix {"b" "b -function"} {
+ test_gdb_complete_multiple "$cmd_prefix " "template_overload_fn" "(" $completion_list
+ check_bp_locations_match_list "$cmd_prefix template_overload_fn" $completion_list
+ check_bp_locations_match_list \
+ "$cmd_prefix template_struct<int>::template_overload_fn" \
+ "template_struct<int>::template_overload_fn(int)"
+ }
+}
+
+# Test completing template methods with non-void return type.
+
+proc_with_prefix template-ret-type {} {
+ set method_name "template2_fn<int, int>"
+ set param_list "(template2_ret_type<int>, int, int)"
+ set struct_type "template2_struct<template2_ret_type<int> >"
+ set ret_type "template2_ret_type<int>"
+
+ # Templates are listed both with and without return type, making
+ # "template2_<tab>" ambiguous.
+ foreach cmd_prefix {"b" "b -function"} {
+ set completion_list \
+ [list \
+ "${ret_type} ${struct_type}::${method_name}${param_list}" \
+ "${struct_type}::${method_name}${param_list}"]
+ test_gdb_complete_multiple "$cmd_prefix " "template2_" "" $completion_list
+
+ # Add one character more after "2_", and the linespec becomes
+ # unambiguous. Test completing the whole prefix range after that,
+ # thus testing completing either with or without return type.
+ foreach {s t} [list \
+ "template2_r" \
+ "${ret_type} ${struct_type}::${method_name}${param_list}" \
+ "template2_s" \
+ "${struct_type}::${method_name}${param_list}"] {
+ set linespec $t
+ set complete_line "$cmd_prefix $linespec"
+ set start [index_after $s $complete_line]
+ test_complete_prefix_range $complete_line $start
+ }
+
+ # Setting a breakpoint without the template params doesn't work.
+ check_setting_bp_fails "$cmd_prefix template2_fn"
+ # However, setting a breakpoint with template params and without
+ # the method params does work, just like with non-template
+ # functions. It also works with or without return type.
+ foreach linespec [list \
+ "${method_name}" \
+ "${method_name}${param_list}" \
+ "${struct_type}::${method_name}" \
+ "${struct_type}::${method_name}${param_list}" \
+ "${ret_type} ${struct_type}::${method_name}" \
+ "${ret_type} ${struct_type}::${method_name}${param_list}"] {
+ check_bp_locations_match_list \
+ "$cmd_prefix $linespec" \
+ [list "${struct_type}::${method_name}${param_list}"]
+ }
+ }
+}
+
+# Test completion of a const-overloaded funtion (const-overload).
+# Note that "const" appears after the function/method parameters.
+
+proc_with_prefix const-overload {} {
+ set completion_list {
+ "struct_with_const_overload::const_overload_fn()"
+ "struct_with_const_overload::const_overload_fn() const"
+ }
+ foreach cmd_prefix {"b" "b -function"} {
+ test_gdb_complete_multiple \
+ "$cmd_prefix " "const_overload_fn" "()" \
+ $completion_list
+ test_gdb_complete_multiple \
+ "$cmd_prefix " "const_overload_fn ( " ")" \
+ $completion_list
+ test_gdb_complete_multiple \
+ "$cmd_prefix " "const_overload_fn()" "" \
+ $completion_list
+
+ check_bp_locations_match_list \
+ "$cmd_prefix const_overload_fn" \
+ {"struct_with_const_overload::const_overload_fn()"
+ "struct_with_const_overload::const_overload_fn() const"}
+
+ check_setting_bp_fails "$cmd_prefix const_overload_fn("
+ check_bp_locations_match_list \
+ "$cmd_prefix const_overload_fn()" \
+ {"struct_with_const_overload::const_overload_fn()"}
+ check_bp_locations_match_list \
+ "$cmd_prefix const_overload_fn() const" \
+ {"struct_with_const_overload::const_overload_fn() const"}
+ }
+}
+
+# Same but quote-enclose the function name. This makes the overload
+# no longer be ambiguous.
+
+proc_with_prefix const-overload-quoted {} {
+ foreach cmd_prefix {"b" "b -function"} {
+ set linespec "'const_overload_fn()'"
+ test_gdb_complete_unique "$cmd_prefix $linespec" "$cmd_prefix $linespec"
+ check_bp_locations_match_list \
+ "$cmd_prefix $linespec" {
+ "struct_with_const_overload::const_overload_fn()"
+ }
+
+ set linespec "'const_overload_fn() const'"
+ test_gdb_complete_unique "$cmd_prefix $linespec" "$cmd_prefix $linespec"
+ check_bp_locations_match_list \
+ "$cmd_prefix $linespec" {
+ "struct_with_const_overload::const_overload_fn() const"
+ }
+ }
+}
+
+# Test that when the function is unambiguous, linespec completion
+# appends the end quote char automatically, both ' and ".
+
+proc_with_prefix append-end-quote-char-when-unambiguous {} {
+ global all_quotes_list
+
+ foreach cmd_prefix {"b" "b -function"} {
+ foreach qc $all_quotes_list {
+ set linespec "${qc}not_overloaded_fn()${qc}"
+ foreach cmd [list "$cmd_prefix ${qc}not_overloaded_fn()" \
+ "$cmd_prefix ${qc}not_overloaded_fn" \
+ "$cmd_prefix ${qc}not_overloaded_"] {
+ test_gdb_complete_unique $cmd "$cmd_prefix $linespec"
+ }
+ check_bp_locations_match_list \
+ "$cmd_prefix $linespec" {"not_overloaded_fn()"}
+ }
+ }
+}
+
+# Test completing symbols of source files.
+
+proc_with_prefix in-source-file-unconstrained {} {
+ # First test that unconstrained matching picks up functions from
+ # multiple files.
+ test_gdb_complete_multiple "b " "file_constrained_test" "_cpls" {
+ "file_constrained_test_cpls2_function(int)"
+ "file_constrained_test_cpls_function(int)"
+ }
+ check_setting_bp_fails "b file_constrained_test_cpls"
+}
+
+# Test an unambiguous completion that would be ambiguous if it weren't
+# for the source file component, due to
+# "file_constrained_test_cpls_function" in cpls.cc. Test with
+# different components quoted, and with whitespace before the function
+# name.
+
+proc_with_prefix in-source-file-unambiguous {} {
+ global maybe_quoted_list
+
+ foreach sqc $maybe_quoted_list {
+ foreach fqc $maybe_quoted_list {
+ # Linespec.
+ foreach sep {":" ": "} {
+ set linespec "${sqc}cpls2.cc${sqc}${sep}${fqc}file_constrained_test_cpls2_function(int)${fqc}"
+ set complete_line "b $linespec"
+ set start [index_after "constrained_test" $complete_line]
+ set input_line [string range $complete_line 0 $start]
+ test_gdb_complete_unique $input_line ${complete_line}
+ check_bp_locations_match_list "b $linespec" {
+ "file_constrained_test_cpls2_function(int)"
+ }
+ }
+
+ # Explicit location.
+ set source_opt "-source ${sqc}cpls2.cc${sqc}"
+ set function_opt "-function ${fqc}file_constrained_test_cpls2_function(int)${fqc}"
+ set complete_line "b $source_opt $function_opt"
+ set start [index_after "cpls2_functio" $complete_line]
+ set input_line [string range $complete_line 0 $start]
+ test_gdb_complete_unique $input_line ${complete_line}
+ check_bp_locations_match_list "$complete_line" {
+ "file_constrained_test_cpls2_function(int)"
+ }
+ }
+ }
+}
+
+# Test an ambiguous completion constrained by a source file. Test
+# with different components quoted, and with whitespace before the
+# function name.
+
+proc_with_prefix in-source-file-ambiguous {} {
+ global maybe_quoted_list
+
+ foreach sqc $maybe_quoted_list {
+ foreach fqc $maybe_quoted_list {
+ # Linespec.
+ foreach sep {":" ": "} {
+ set cmd_prefix "b ${sqc}cpls2.cc${sqc}${sep}"
+ test_gdb_complete_multiple "${cmd_prefix}" ${fqc} "" {
+ "another_file_constrained_test_cpls2_function(int)"
+ "file_constrained_test_cpls2_function(int)"
+ } ${fqc} ${fqc}
+ }
+
+ # Explicit location.
+ test_gdb_complete_multiple \
+ "b -source ${sqc}cpls2.cc${sqc} -function " ${fqc} "" {
+ "another_file_constrained_test_cpls2_function(int)"
+ "file_constrained_test_cpls2_function(int)"
+ } ${fqc} ${fqc}
+ }
+ }
+}
+
+# Check that completing a file name in a linespec auto-appends a colon
+# instead of a whitespace character.
+
+proc_with_prefix source-complete-appends-colon {} {
+ global maybe_quoted_list
+ global all_quotes_list
+ global keyword_list
+
+ # Test with quotes to make sure the end quote char is put at the
+ # right place.
+ foreach qc $maybe_quoted_list {
+ test_gdb_complete_unique \
+ "b ${qc}cpls2." \
+ "b ${qc}cpls2.cc${qc}" ":"
+ test_gdb_complete_unique \
+ "b ${qc}cpls2.c" \
+ "b ${qc}cpls2.cc${qc}" ":"
+ test_gdb_complete_unique \
+ "b ${qc}cpls2.cc" \
+ "b ${qc}cpls2.cc${qc}" ":"
+
+ # Same, but with a filename with an hyphen (which is normally
+ # a language word break char).
+ test_gdb_complete_unique \
+ "b ${qc}cpls-" \
+ "b ${qc}cpls-hyphen.cc${qc}" ":"
+ test_gdb_complete_unique \
+ "b ${qc}cpls-hyphen" \
+ "b ${qc}cpls-hyphen.cc${qc}" ":"
+ }
+
+ # Test the same, but with the name of a nonexisting file.
+
+ # Cursor at the end of the string.
+ test_gdb_complete_none "b nonexistingfilename.cc"
+ # Cursor past the end of the string.
+ test_gdb_complete_multiple "b nonexistingfilename.cc " "" "" $keyword_list
+ foreach qc $all_quotes_list {
+ # Unterminated quote.
+ test_gdb_complete_none "b ${qc}nonexistingfilename.cc"
+ test_gdb_complete_none "b ${qc}nonexistingfilename.cc "
+ # Terminated quote, cursor at the quote.
+ test_gdb_complete_unique \
+ "b ${qc}nonexistingfilename.cc${qc}" \
+ "b ${qc}nonexistingfilename.cc${qc}"
+ # Terminated quote, cursor past the quote.
+ test_gdb_complete_multiple \
+ "b ${qc}nonexistingfilename.cc${qc} " "" "" $keyword_list
+ }
+}
+
+####################################################################
+
+# Test that a colon at the end of the linespec is understood as an
+# incomplete scope operator (incomplete-scope-colon), instead of a
+# source/function separator.
+
+proc_with_prefix incomplete-scope-colon {} {
+
+ # Helper for the loop below to simplify it. Tests completion of
+ # the range defined by the RANGE_SS found in the constructed line.
+ #
+ # E.g., with:
+ #
+ # source="source.cc"
+ # fqc="'"
+ # prototype="ns::function()"
+ # range_ss="s::f"
+ #
+ # we'd try completing with the cursor set in each of the
+ # underlined range's positions of:
+ #
+ # b source.cc:'ns::function()'"
+ # ^^^^
+ #
+ # Also test that setting a breakpoint at the constructed line
+ # finds the same breakpoint location as completion does.
+ #
+ proc incomplete_scope_colon_helper {prototype range_ss {skip_check_bp 0}} {
+ global maybe_quoted_list
+
+ foreach source {"" "cpls.cc"} {
+ # Test with and without source quoting.
+ foreach sqc $maybe_quoted_list {
+ if {$source == "" && $sqc != ""} {
+ # Invalid combination.
+ continue
+ }
+
+ # Test with and without function quoting.
+ foreach fqc $maybe_quoted_list {
+ if {$source == ""} {
+ set linespec_source ""
+ set explicit_source ""
+ } else {
+ set linespec_source "${sqc}${source}${sqc}:"
+ set explicit_source "-source ${sqc}${source}${sqc}"
+ }
+
+ # Even though this use case is trickier with
+ # linespecs due to the ":" as separator, test both
+ # linespecs and explicit locations for
+ # completeness.
+ foreach location [list \
+ "${linespec_source}${fqc}$prototype${fqc}" \
+ "${explicit_source} -function ${fqc}$prototype${fqc}"] {
+ set complete_line "b $location"
+ set start [string first $range_ss $complete_line]
+ set end [expr ($start + [string length $range_ss])]
+ test_complete_prefix_range $complete_line $start $end
+ if {!$skip_check_bp} {
+ check_bp_locations_match_list "b $location" [list "$prototype"]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ incomplete_scope_colon_helper \
+ "struct_incomplete_scope_colon_test::incomplete_scope_colon_test()" \
+ "t::i"
+
+ incomplete_scope_colon_helper \
+ "ns_incomplete_scope_colon_test::incomplete_scope_colon_test()" \
+ "t::i"
+
+ # Test completing around both "::"s.
+ foreach range_ss {"t::s" "t::i"} skip_check_bp {0 1} {
+ incomplete_scope_colon_helper \
+ "ns2_incomplete_scope_colon_test::struct_in_ns2_incomplete_scope_colon_test::incomplete_scope_colon_test()" \
+ $range_ss $skip_check_bp
+ }
+}
+
+# Test completing functions/methods in anonymous namespaces.
+
+proc_with_prefix anon-ns {} {
+ global maybe_quoted_list
+
+ foreach cmd_prefix {"b" "b -function"} {
+ foreach qc $maybe_quoted_list {
+ test_gdb_complete_unique \
+ "$cmd_prefix ${qc}anon_ns_function" \
+ "$cmd_prefix ${qc}anon_ns_function()${qc}"
+ check_bp_locations_match_list "$cmd_prefix ${qc}anon_ns_function()${qc}" {
+ "(anonymous namespace)::anon_ns_function()"
+ "(anonymous namespace)::anon_ns_struct::anon_ns_function()"
+ "the_anon_ns_wrapper_ns::(anonymous namespace)::anon_ns_function()"
+ "the_anon_ns_wrapper_ns::(anonymous namespace)::anon_ns_struct::anon_ns_function()"
+ }
+ }
+
+ # A "(" finds all anonymous namespace functions/methods in all
+ # scopes.
+ test_gdb_complete_multiple "$cmd_prefix " "(" "anonymous namespace)::" {
+ "(anonymous namespace)::anon_ns_function()"
+ "(anonymous namespace)::anon_ns_struct::anon_ns_function()"
+ "(anonymous namespace)::overload2_function(overload2_arg3)"
+ "(anonymous namespace)::overload3_function(int)"
+ "(anonymous namespace)::overload3_function(long)"
+ "(anonymous namespace)::struct_overload2_test::overload2_function(overload2_arg4)"
+ "(anonymous namespace)::struct_overload3_test::overload3_function(int)"
+ "(anonymous namespace)::struct_overload3_test::overload3_function(long)"
+ "ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_function(overload2_arg9)"
+ "ns_overload2_test::(anonymous namespace)::ns_overload2_test::struct_overload2_test::overload2_function(overload2_arga)"
+ "ns_overload2_test::(anonymous namespace)::overload2_function(overload2_arg7)"
+ "ns_overload2_test::(anonymous namespace)::struct_overload2_test::overload2_function(overload2_arg8)"
+ "ns_overload3_test::(anonymous namespace)::ns_overload3_test::overload3_function(int)"
+ "ns_overload3_test::(anonymous namespace)::ns_overload3_test::overload3_function(long)"
+ "ns_overload3_test::(anonymous namespace)::ns_overload3_test::struct_overload3_test::overload3_function(int)"
+ "ns_overload3_test::(anonymous namespace)::ns_overload3_test::struct_overload3_test::overload3_function(long)"
+ "ns_overload3_test::(anonymous namespace)::overload3_function(int)"
+ "ns_overload3_test::(anonymous namespace)::overload3_function(long)"
+ "ns_overload3_test::(anonymous namespace)::struct_overload3_test::overload3_function(int)"
+ "ns_overload3_test::(anonymous namespace)::struct_overload3_test::overload3_function(long)"
+ "the_anon_ns_wrapper_ns::(anonymous namespace)::anon_ns_function()"
+ "the_anon_ns_wrapper_ns::(anonymous namespace)::anon_ns_struct::anon_ns_function()"
+ }
+
+ set function "the_anon_ns_wrapper_ns::(anonymous namespace)::anon_ns_function()"
+ test_gdb_complete_unique "$cmd_prefix $function" "$cmd_prefix $function"
+ check_bp_locations_match_list "$cmd_prefix $function" [list $function]
+
+ # Test completing after the "(anonymous namespace)" part.
+ test_gdb_complete_unique \
+ "$cmd_prefix the_anon_ns_wrapper_ns::(anonymous namespace)::anon_ns_fu" \
+ "$cmd_prefix $function"
+
+ # Test whitespace in the "(anonymous namespace)" component.
+
+ test_gdb_complete_unique \
+ "$cmd_prefix the_anon_ns_wrapper_ns::( anonymous namespace )::anon_ns_fu" \
+ "$cmd_prefix the_anon_ns_wrapper_ns::( anonymous namespace )::anon_ns_function()"
+ check_setting_bp_fails \
+ "$cmd_prefix the_anon_ns_wrapper_ns::( anonymous namespace )::anon_ns_fu"
+
+ set function_ws \
+ "the_anon_ns_wrapper_ns::( anonymous namespace )::anon_ns_function ( )"
+ test_gdb_complete_unique "$cmd_prefix $function_ws" "$cmd_prefix $function_ws"
+ check_bp_locations_match_list "$cmd_prefix $function_ws" [list $function]
+ }
+}
+
+# Basic test for completing "operator<". More extensive C++ operator
+# tests in cpls-op.exp.
+
+proc_with_prefix operator< {} {
+ # Complete all prefixes between "oper" and the whole prototype.
+ set function "operator<(foo_enum, foo_enum)"
+ foreach cmd_prefix {"b" "b -function"} {
+ set line "$cmd_prefix $function"
+ set start [index_after "oper" $line]
+ test_complete_prefix_range $line $start
+ }
+
+ # There's a label in the function; try completing it. (Exhaustive
+ # label completion tests further below.)
+ foreach location [list \
+ "$function:label1" \
+ "-function $function -label label1"] {
+
+ set cmd "b $location"
+ set input_line [string range $cmd 0 [expr [string length $cmd] - 3]]
+
+ test_gdb_complete_unique $input_line $cmd
+ test_gdb_complete_unique $cmd $cmd
+ check_bp_locations_match_list $cmd [list "$location"]
+ }
+}
+
+# Test completion of scopes with an ambiguous prefix.
+
+proc_with_prefix ambiguous-prefix {} {
+ foreach cmd_prefix {"b" "b -function"} {
+ test_gdb_complete_multiple "$cmd_prefix " "ambiguous_pre" "fix_" {
+ "ambiguous_prefix_global_func()"
+ "the_ambiguous_prefix_ns::ambiguous_prefix_ns_func()"
+ "the_ambiguous_prefix_struct::ambiguous_prefix_method()"
+ }
+ check_setting_bp_fails "$cmd_prefix ambiguous_prefix_"
+ }
+}
+
+# Test completion of function labels.
+
+proc_with_prefix function-labels {} {
+ # Test with and without a source file component.
+ foreach_location_functions \
+ { "" "cpls.cc" } \
+ { "function_with_labels(int)" } \
+ {
+ # Linespec version. Test various spacing around the label
+ # colon separator.
+ foreach label_sep {":" " :" ": " " : "} {
+ set linespec "${location}${label_sep}"
+ test_gdb_complete_multiple "b $linespec" "l" "abel" {
+ "label1"
+ "label2"
+ }
+ check_setting_bp_fails "b ${linespec}label"
+
+ set tsep [string trim ${source_sep}]
+ check_bp_locations_match_list \
+ "b ${linespec}label1" [list "${source}${tsep}${function}:label1"]
+ check_bp_locations_match_list \
+ "b ${linespec}label2" [list "${source}${tsep}${function}:label2"]
+ }
+ } \
+ {
+ # Explicit locations version.
+ append location " -label"
+ test_gdb_complete_multiple "b $location " "l" "abel" {
+ "label1"
+ "label2"
+ }
+ check_setting_bp_fails "b $location label"
+
+ if {$source != ""} {
+ set bp_loc_src "-source ${source} "
+ } else {
+ set bp_loc_src ""
+ }
+ check_bp_locations_match_list \
+ "b ${location} label1" [list "${bp_loc_src}-function $function -label label1"]
+ check_bp_locations_match_list \
+ "b ${location} label2" [list "${bp_loc_src}-function $function -label label2"]
+ }
+}
+
+# Test that completion after a function name offers keyword
+# (if/task/thread) matches in linespec mode, and also the explicit
+# location options in explicit locations mode.
+
+proc_with_prefix keywords-after-function {} {
+ global explicit_opts_list keyword_list
+
+ set explicit_list [concat $explicit_opts_list $keyword_list]
+
+ # Test without a source file, with a known source file, and with
+ # and unknown source file.
+ # Test a known and an unknown function.
+ foreach_location_functions \
+ { "" "cpls.cc" "unknown_file.cc" } \
+ { "function_with_labels(int)" "unknown_function(int)" } \
+ {
+ # Linespec version.
+ test_gdb_complete_multiple "b ${location} " "" "" $keyword_list
+ } \
+ {
+ # Explicit locations version.
+ test_gdb_complete_multiple "b ${location} " "" "" $explicit_list
+ }
+}
+
+# Same, but after a label.
+
+proc_with_prefix keywords-after-label {} {
+ global explicit_opts_list keyword_list
+
+ set explicit_list [concat $explicit_opts_list $keyword_list]
+
+ foreach_location_labels \
+ { "" "cpls.cc" } \
+ { "function_with_labels(int)" "unknown_function(int)" } \
+ { "label1" "non_existing_label" } \
+ {
+ # Linespec version.
+ test_gdb_complete_multiple "b ${location} " "" "" $keyword_list
+ } \
+ {
+ # Explicit locations version.
+ test_gdb_complete_multiple "b ${location} " "" "" $explicit_list
+ }
+}
+
+# Similar, but after an unknown file, and in linespec mode only.
+
+proc_with_prefix keywords-after-unknown-file {} {
+ global maybe_quoted_list
+ global keyword_list
+
+ # Test with and without quoting.
+ foreach qc $maybe_quoted_list {
+ set line "b ${qc}unknown_file.cc${qc}: "
+ test_gdb_complete_multiple $line "" "" $keyword_list
+ }
+}
+
+# Test that linespec / function completion does not match data
+# symbols, only functions/methods.
+
+proc_with_prefix no-data-symbols {} {
+ foreach cmd_prefix {"b" "b -function"} {
+ test_gdb_complete_unique "$cmd_prefix code_" "$cmd_prefix code_function()"
+ }
+}
+
+
+# After "if", we expect an expression, which has a different completer
+# that matches data symbols as well. Check that that works.
+
+proc_with_prefix if-expression {} {
+ foreach cmd_prefix {"b" "b -function"} {
+ test_gdb_complete_multiple "$cmd_prefix function() if " "code_" "" {
+ "code_data"
+ "code_function()"
+ }
+
+ test_gdb_complete_unique \
+ "$cmd_prefix function() if code_data + another_da" \
+ "$cmd_prefix function() if code_data + another_data"
+
+ test_gdb_complete_unique \
+ "$cmd_prefix non_existing_function() if code_data + another_da" \
+ "$cmd_prefix non_existing_function() if code_data + another_data"
+
+ # FIXME: For now, thread and task also use the expression
+ # completer.
+ test_gdb_complete_unique \
+ "$cmd_prefix function() thread code_data + another_da" \
+ "$cmd_prefix function() thread code_data + another_data"
+ test_gdb_complete_unique \
+ "$cmd_prefix function() task code_data + another_da" \
+ "$cmd_prefix function() task code_data + another_data"
+ }
+}
+
+# The testcase driver. Calls all test procedures.
+
+proc test_driver {} {
+ all-param-prefixes
+ overload
+ overload-2
+ fqn
+ fqn-2
+ overload-3
+ template-overload
+ template-ret-type
+ const-overload
+ const-overload-quoted
+ append-end-quote-char-when-unambiguous
+ in-source-file-unconstrained
+ in-source-file-unambiguous
+ in-source-file-ambiguous
+ source-complete-appends-colon
+ incomplete-scope-colon
+ anon-ns
+ operator<
+ ambiguous-prefix
+ function-labels
+ keywords-after-function
+ keywords-after-label
+ keywords-after-unknown-file
+ no-data-symbols
+ if-expression
+}
+
+test_driver
diff --git a/gdb/testsuite/gdb.linespec/cpls-hyphen.cc b/gdb/testsuite/gdb.linespec/cpls-hyphen.cc
new file mode 100644
index 00000000000..fdc063f8b79
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/cpls-hyphen.cc
@@ -0,0 +1,14 @@
+int
+ns_hyphen_function (int i)
+{
+ if (i > 0)
+ {
+ label1:
+ return i + 20;
+ }
+ else
+ {
+ label2:
+ return i + 10;
+ }
+}
diff --git a/gdb/testsuite/gdb.linespec/cpls.cc b/gdb/testsuite/gdb.linespec/cpls.cc
new file mode 100644
index 00000000000..776dd4cfaa1
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/cpls.cc
@@ -0,0 +1,386 @@
+/* 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/>. */
+
+/* Code for the all-param-prefixes test. */
+
+void
+param_prefixes_test_long (long)
+{}
+
+void
+param_prefixes_test_intp_intr (int *, int&)
+{}
+
+/* Code for the overload test. */
+
+void
+overload_ambiguous_test (long)
+{}
+
+void
+overload_ambiguous_test (int, int)
+{}
+
+void
+overload_ambiguous_test (int, long)
+{}
+
+/* Code for the overload-2 test. */
+
+/* Generate functions/methods all with the same name, in different
+ scopes, but all with different parameters. */
+
+struct overload2_arg1 {};
+struct overload2_arg2 {};
+struct overload2_arg3 {};
+struct overload2_arg4 {};
+struct overload2_arg5 {};
+struct overload2_arg6 {};
+struct overload2_arg7 {};
+struct overload2_arg8 {};
+struct overload2_arg9 {};
+struct overload2_arga {};
+
+#define GEN_OVERLOAD2_FUNCTIONS(ARG1, ARG2) \
+ void \
+ overload2_function (ARG1) \
+ {} \
+ \
+ struct struct_overload2_test \
+ { \
+ void overload2_function (ARG2); \
+ }; \
+ \
+ void \
+ struct_overload2_test::overload2_function (ARG2) \
+ {}
+
+/* In the global namespace. */
+GEN_OVERLOAD2_FUNCTIONS( overload2_arg1, overload2_arg2)
+
+namespace
+{
+ /* In an anonymous namespace. */
+ GEN_OVERLOAD2_FUNCTIONS (overload2_arg3, overload2_arg4)
+}
+
+namespace ns_overload2_test
+{
+ /* In a namespace. */
+ GEN_OVERLOAD2_FUNCTIONS (overload2_arg5, overload2_arg6)
+
+ namespace
+ {
+ /* In a nested anonymous namespace. */
+ GEN_OVERLOAD2_FUNCTIONS (overload2_arg7, overload2_arg8)
+
+ namespace ns_overload2_test
+ {
+ /* In a nested namespace. */
+ GEN_OVERLOAD2_FUNCTIONS (overload2_arg9, overload2_arga)
+ }
+ }
+}
+
+/* Code for the overload-3 test. */
+
+#define GEN_OVERLOAD3_FUNCTIONS(ARG1, ARG2) \
+ void \
+ overload3_function (ARG1) \
+ {} \
+ void \
+ overload3_function (ARG2) \
+ {} \
+ \
+ struct struct_overload3_test \
+ { \
+ void overload3_function (ARG1); \
+ void overload3_function (ARG2); \
+ }; \
+ \
+ void \
+ struct_overload3_test::overload3_function (ARG1) \
+ {} \
+ void \
+ struct_overload3_test::overload3_function (ARG2) \
+ {}
+
+/* In the global namespace. */
+GEN_OVERLOAD3_FUNCTIONS (int, long)
+
+namespace
+{
+ /* In an anonymous namespace. */
+ GEN_OVERLOAD3_FUNCTIONS (int, long)
+}
+
+namespace ns_overload3_test
+{
+ /* In a namespace. */
+ GEN_OVERLOAD3_FUNCTIONS (int, long)
+
+ namespace
+ {
+ /* In a nested anonymous namespace. */
+ GEN_OVERLOAD3_FUNCTIONS (int, long)
+
+ namespace ns_overload3_test
+ {
+ /* In a nested namespace. */
+ GEN_OVERLOAD3_FUNCTIONS (int, long)
+ }
+ }
+}
+
+/* Code for the template-overload tests. */
+
+template <typename T>
+struct template_struct
+{
+ T template_overload_fn (T);
+};
+
+template <typename T>
+T template_struct<T>::template_overload_fn (T t)
+{
+ return t;
+}
+
+template_struct<int> template_struct_int;
+template_struct<long> template_struct_long;
+
+/* Code for the template2-ret-type tests. */
+
+template <typename T>
+struct template2_ret_type {};
+
+template <typename T>
+struct template2_struct
+{
+ template <typename T2, typename T3>
+ T template2_fn (T = T (), T2 t2 = T2 (), T3 t3 = T3 ());
+};
+
+template <typename T>
+template <typename T2, typename T3>
+T template2_struct<T>::template2_fn (T t, T2 t2, T3 t3)
+{
+ return T ();
+}
+
+template2_struct<template2_ret_type<int> > template2_struct_inst;
+
+/* Code for the const-overload tests. */
+
+struct struct_with_const_overload
+{
+ void const_overload_fn ();
+ void const_overload_fn () const;
+};
+
+void
+struct_with_const_overload::const_overload_fn ()
+{}
+
+void
+struct_with_const_overload::const_overload_fn () const
+{}
+
+void
+not_overloaded_fn ()
+{}
+
+/* Code for the incomplete-scope-colon tests. */
+
+struct struct_incomplete_scope_colon_test
+{
+ void incomplete_scope_colon_test ();
+};
+
+void
+struct_incomplete_scope_colon_test::incomplete_scope_colon_test ()
+{}
+
+namespace ns_incomplete_scope_colon_test
+{
+ void incomplete_scope_colon_test () {}
+}
+
+namespace ns2_incomplete_scope_colon_test
+{
+ struct struct_in_ns2_incomplete_scope_colon_test
+ {
+ void incomplete_scope_colon_test ();
+ };
+
+ void
+ struct_in_ns2_incomplete_scope_colon_test::incomplete_scope_colon_test ()
+ {}
+}
+
+/* Code for the anon-ns tests. */
+
+namespace
+{
+ void anon_ns_function ()
+ {}
+
+ struct anon_ns_struct
+ {
+ void anon_ns_function ();
+ };
+
+ void
+ anon_ns_struct::anon_ns_function ()
+ {}
+}
+
+namespace the_anon_ns_wrapper_ns
+{
+
+namespace
+{
+ void anon_ns_function ()
+ {}
+
+ struct anon_ns_struct
+ {
+ void anon_ns_function ();
+ };
+
+ void
+ anon_ns_struct::anon_ns_function ()
+ {}
+}
+
+} /* the_anon_ns_wrapper_ns */
+
+/* Code for the global-ns-scope-op tests. */
+
+void global_ns_scope_op_function ()
+{
+}
+
+/* Add a function with the same name to a namespace. We want to test
+ that "b ::global_ns_function" does NOT select it. */
+namespace the_global_ns_scope_op_ns
+{
+ void global_ns_scope_op_function ()
+ {
+ }
+}
+
+/* Code for the ambiguous-prefix tests. */
+
+/* Create a few functions/methods with the same "ambiguous_prefix_"
+ prefix. They in different scopes, but "b ambiguous_prefix_<tab>"
+ should list them all, and figure out the LCD is
+ ambiguous_prefix_. */
+
+void ambiguous_prefix_global_func ()
+{
+}
+
+namespace the_ambiguous_prefix_ns
+{
+ void ambiguous_prefix_ns_func ()
+ {
+ }
+}
+
+struct the_ambiguous_prefix_struct
+{
+ void ambiguous_prefix_method ();
+};
+
+void
+the_ambiguous_prefix_struct::ambiguous_prefix_method ()
+{
+}
+
+/* Code for the function-labels test. */
+
+int
+function_with_labels (int i)
+{
+ if (i > 0)
+ {
+ label1:
+ return i + 20;
+ }
+ else
+ {
+ label2:
+ return i + 10;
+ }
+}
+
+/* Code for the no-data-symbols and if-expression tests. */
+
+int code_data = 0;
+
+int another_data = 0;
+
+/* A function that has a same "code" prefix as the global above. We
+ want to ensure that completing on "b code" doesn't offer the data
+ symbol. */
+void
+code_function ()
+{
+}
+
+/* Code for the operator< tests. */
+
+enum foo_enum
+ {
+ foo_value
+ };
+
+bool operator<(foo_enum lhs, foo_enum rhs)
+{
+ label1:
+ return false;
+}
+
+/* Code for the in-source-file-unconstrained /
+ in-source-file-ambiguous tests. */
+
+int
+file_constrained_test_cpls_function (int i)
+{
+ if (i > 0)
+ {
+ label1:
+ return i + 20;
+ }
+ else
+ {
+ label2:
+ return i + 10;
+ }
+}
+
+
+int
+main ()
+{
+ template2_struct_inst.template2_fn<int, int> ();
+ template_struct_int.template_overload_fn(0);
+ template_struct_long.template_overload_fn(0);
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.linespec/cpls2.cc b/gdb/testsuite/gdb.linespec/cpls2.cc
new file mode 100644
index 00000000000..a8f1319840a
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/cpls2.cc
@@ -0,0 +1,46 @@
+/* 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/>. */
+
+int
+file_constrained_test_cpls2_function (int i)
+{
+ if (i > 0)
+ {
+ label1:
+ return i + 20;
+ }
+ else
+ {
+ label2:
+ return i + 10;
+ }
+}
+
+int
+another_file_constrained_test_cpls2_function (int i)
+{
+ if (i > 0)
+ {
+ label1:
+ return i + 20;
+ }
+ else
+ {
+ label2:
+ return i + 10;
+ }
+}
diff --git a/gdb/testsuite/gdb.linespec/explicit.exp b/gdb/testsuite/gdb.linespec/explicit.exp
index 65d78caddb6..998b70ae8ef 100644
--- a/gdb/testsuite/gdb.linespec/explicit.exp
+++ b/gdb/testsuite/gdb.linespec/explicit.exp
@@ -15,6 +15,8 @@
# Tests for explicit locations
+load_lib completion-support.exp
+
standard_testfile explicit.c explicit2.c 3explicit.c
set exefile $testfile
@@ -222,13 +224,14 @@ namespace eval $testfile {
}
}
- set tst "complete unique file name"
- send_gdb "break -source 3ex\t"
- gdb_test_multiple "" $tst {
- -re "break -source 3explicit.c " {
- send_gdb "\n"
- gdb_test "" \
- {Source filename requires function, label, or line offset.} $tst
+ with_test_prefix "complete unique file name" {
+ foreach qc $maybe_quoted_list {
+ set cmd "break -source ${qc}3explicit.c${qc}"
+ test_gdb_complete_unique \
+ "break -source ${qc}3ex" \
+ $cmd
+ gdb_test $cmd \
+ {Source filename requires function, label, or line offset.}
}
}
@@ -326,10 +329,202 @@ namespace eval $testfile {
}
}
+ global maybe_quoted_list
+
+ with_test_prefix "complete unique label name" {
+ foreach qc $maybe_quoted_list {
+ test_gdb_complete_unique \
+ "break -function myfunction -label ${qc}to" \
+ "break -function myfunction -label ${qc}top${qc}"
+ }
+ }
+
+ with_test_prefix "complete unique label name with source file" {
+ test_gdb_complete_unique \
+ "break -source explicit.c -function myfunction -label to" \
+ "break -source explicit.c -function myfunction -label top"
+ }
+
+ with_test_prefix "complete unique label name reversed" {
+ test_gdb_complete_multiple "b -label top -function " "myfunction" "" {
+ "myfunction"
+ "myfunction2"
+ "myfunction3"
+ "myfunction4"
+ }
+ }
+
+ with_test_prefix "complete non-unique label name" {
+ test_gdb_complete_multiple "b -function myfunction -label " "" "" {
+ "done"
+ "top"
+ }
+ }
+
+ # The program is stopped at myfunction, so gdb is able to
+ # infer the label's function.
+ with_test_prefix "complete label name with no function" {
+ test_gdb_complete_unique \
+ "break -label to" \
+ "break -label top"
+ check_bp_locations_match_list \
+ "break -label top" {
+ "-function myfunction -label top"
+ }
+ }
+
+ # See above.
+ with_test_prefix "complete label name with source file but no function" {
+ test_gdb_complete_unique \
+ "break -source explicit.c -label to" \
+ "break -source explicit.c -label top"
+ check_bp_locations_match_list \
+ "break -source explicit.c -label top" {
+ "-source explicit.c -function myfunction -label top"
+ }
+ }
+
+ with_test_prefix "complete label name with wrong source file" {
+ test_gdb_complete_none \
+ "break -source explicit2.c -function myfunction -label to"
+ check_setting_bp_fails \
+ "break -source explicit2.c -function myfunction -label top"
+ }
+
+ # Get rid of symbols from shared libraries, otherwise
+ # "b -source thr<tab>" could find some system library's
+ # source.
+ gdb_test_no_output "nosharedlibrary"
+
+ # Test that after a seemingly finished option argument,
+ # completion matches both the explicit location options and
+ # the linespec keywords.
+ set completions_list {
+ "-function"
+ "-label"
+ "-line"
+ "-qualified"
+ "-source"
+ "if"
+ "task"
+ "thread"
+ }
+ foreach what { "-function" "-label" "-line" "-qualified" "-source" } {
+ with_test_prefix "complete after $what" {
+ if {$what != "-line"} {
+ test_gdb_complete_multiple \
+ "b $what argument " "" "" $completions_list
+ test_gdb_complete_unique \
+ "b $what argument thr" \
+ "b $what argument thread"
+ test_gdb_complete_unique \
+ "b $what argument -fun" \
+ "b $what argument -function"
+ } else {
+ # After -line, we expect a number / offset.
+ foreach line {"10" "+10" "-10"} {
+ test_gdb_complete_multiple \
+ "b -line $line " "" "" $completions_list
+ test_gdb_complete_unique \
+ "b -line $line thr" \
+ "b -line $line thread"
+ test_gdb_complete_unique \
+ "b -line $line -fun" \
+ "b -line $line -function"
+ }
+
+ # With an invalid -line argument, we don't get any
+ # completions.
+ test_gdb_complete_none "b -line argument "
+ }
+
+ # Don't complete a linespec keyword ("thread") or
+ # another option name when expecting an option
+ # argument.
+ test_gdb_complete_none "b $what thr"
+ test_gdb_complete_none "b $what -fun"
+ }
+ }
+
+ # Tests that ensure that after "if" we complete on expressions
+ # are in cpcompletion.exp.
+
+ # Disable the completion limit for the rest of the testcase.
+ gdb_test_no_output "set max-completions unlimited"
+
+ # Get rid of symbols from shared libraries, otherwise the
+ # completions match list for "break <tab>" is huge and makes
+ # the test below quite long while the gdb_test_multiple loop
+ # below consumes the matches. Not doing this added ~20
+ # seconds at the time of writing. (Actually, already done above.)
+ # gdb_test_no_output "nosharedlibrary"
+
+ # Test completion with no input argument. We should see all
+ # the options, plus all the functions. To keep it simple, as
+ # proxy, we check for presence of one explicit location
+ # option, one probe location, and one function.
+ set saw_opt_function 0
+ set saw_opt_probe_stap 0
+ set saw_function 0
+
+ set tst "complete with no arguments"
+ send_gdb "break \t"
+ gdb_test_multiple "" $tst {
+ "break \\\x07" {
+ send_gdb "\t\t"
+ gdb_test_multiple "" $tst {
+ "Display all" {
+ send_gdb "y"
+ exp_continue
+ }
+ -re "-function" {
+ set saw_opt_function 1
+ exp_continue
+ }
+ -re "-probe-stap" {
+ set saw_opt_probe_stap 1
+ exp_continue
+ }
+ -re "myfunction4" {
+ set saw_function 1
+ exp_continue
+ }
+ -re "\r\n$gdb_prompt " {
+ gdb_assert {$saw_opt_function && $saw_opt_probe_stap && $saw_function} $tst
+ }
+ -re " " {
+ exp_continue
+ }
+ }
+ }
+ }
+ clear_input_line $tst
+
# NOTE: We don't bother testing more elaborate combinations of options,
# such as "-func main -sour 3ex\t" (main is defined in explicit.c).
# The completer cannot handle these yet.
+ # Follows completion tests that require having no symbols
+ # loaded.
+ gdb_exit
+ gdb_start
+
+ # The match list you get when you complete with no options
+ # specified at all.
+ set completion_list {
+ "-function"
+ "-label"
+ "-line"
+ "-probe"
+ "-probe-dtrace"
+ "-probe-stap"
+ "-qualified"
+ "-source"
+ }
+ with_test_prefix "complete with no arguments and no symbols" {
+ test_gdb_complete_multiple "b " "" "-" $completion_list
+ test_gdb_complete_multiple "b " "-" "" $completion_list
+ }
}
# End of completion tests.
diff --git a/gdb/testsuite/lib/completion-support.exp b/gdb/testsuite/lib/completion-support.exp
new file mode 100644
index 00000000000..ef78269ebcc
--- /dev/null
+++ b/gdb/testsuite/lib/completion-support.exp
@@ -0,0 +1,513 @@
+# 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.
+
+set timeout 5
+
+set bell_re "\\\x07"
+
+# List of all quote chars.
+set all_quotes_list {"'" "\""}
+
+# List of all quote chars, including no-quote at all.
+set maybe_quoted_list {"" "'" "\""}
+
+set keyword_list {"if" "task" "thread"}
+set explicit_opts_list {"-function" "-label" "-line" "-qualified" "-source"}
+
+# Make a regular expression that matches a TAB completion list.
+
+proc make_tab_completion_list_re { completion_list } {
+ # readline separates the completion columns that fit on the same
+ # line with whitespace. Since we're testing under "set width
+ # unlimited", all completions will be printed on the same line.
+ # The amount of whitespace depends on the length of the widest
+ # completion. We could compute that here and expect the exact
+ # number of ws characters between each completion match, but to
+ # keep it simple, we accept any number of characters.
+ set ws " +"
+
+ set completion_list_re ""
+ foreach c $completion_list {
+ append completion_list_re [string_to_regexp $c]
+ append completion_list_re $ws
+ }
+ append completion_list_re $ws
+
+ return $completion_list_re
+}
+
+# Make a regular expression that matches a "complete" command
+# completion list. CMD_PREFIX is the command prefix added to each
+# completion match.
+
+proc make_cmd_completion_list_re { cmd_prefix completion_list start_quote_char end_quote_char } {
+
+ set completion_list_re ""
+ foreach c $completion_list {
+ # The command prefix is included in all completion matches.
+ append completion_list_re [string_to_regexp $cmd_prefix$start_quote_char$c$end_quote_char]
+ append completion_list_re "\r\n"
+ }
+
+ return $completion_list_re
+}
+
+# Clear the input line.
+
+proc clear_input_line { test } {
+ global gdb_prompt
+
+ send_gdb "\003"
+ gdb_test_multiple "" "$test (clearing input line)" {
+ -re "Quit\r\n$gdb_prompt $" {
+ }
+ }
+}
+
+# Test that completing LINE with TAB completes to nothing.
+
+proc test_gdb_complete_tab_none { line } {
+ global bell_re
+
+ set line_re [string_to_regexp $line]
+
+ set test "tab complete \"$line\""
+ send_gdb "$line\t"
+ gdb_test_multiple "" "$test" {
+ -re "^$line_re$bell_re$" {
+ pass "$test"
+ }
+ }
+
+ clear_input_line $test
+}
+
+# Test that completing INPUT_LINE with TAB completes to
+# COMPLETE_LINE_RE. APPEND_CHAR_RE is the character expected to be
+# appended after EXPECTED_OUTPUT. Normally that's a whitespace, but
+# in some cases it's some other character, like a colon.
+
+proc test_gdb_complete_tab_unique { input_line complete_line_re append_char_re } {
+
+ set test "tab complete \"$input_line\""
+ send_gdb "$input_line\t"
+ gdb_test_multiple "" "$test" {
+ -re "^$complete_line_re$append_char_re$" {
+ pass "$test"
+ }
+ }
+
+ clear_input_line $test
+}
+
+# Test that completing INPUT_LINE with TAB completes to "INPUT_LINE +
+# ADD_COMPLETED_LINE" and that is displays the completion matches in
+# COMPLETION_LIST.
+
+proc test_gdb_complete_tab_multiple { input_line add_completed_line \
+ completion_list } {
+ global gdb_prompt
+ global bell_re
+
+ set input_line_re [string_to_regexp $input_line]
+ set add_completed_line_re [string_to_regexp $add_completed_line]
+
+ set expected_re [make_tab_completion_list_re $completion_list]
+
+ set test "tab complete \"$input_line\""
+ send_gdb "$input_line\t"
+ gdb_test_multiple "" "$test (first tab)" {
+ -re "^${input_line_re}$bell_re$add_completed_line_re$" {
+ send_gdb "\t"
+ # If we auto-completed to an ambiguous prefix, we need an
+ # extra tab to show the matches list.
+ if {$add_completed_line != ""} {
+ send_gdb "\t"
+ }
+ gdb_test_multiple "" "$test (second tab)" {
+ -re "$expected_re\r\n$gdb_prompt $input_line_re$add_completed_line_re$" {
+ pass "$test"
+ }
+ }
+ }
+ }
+
+ clear_input_line $test
+}
+
+# Test that completing LINE with the complete command completes to
+# nothing.
+
+proc test_gdb_complete_cmd_none { line } {
+ gdb_test_no_output "complete $line" "cmd complete \"$line\""
+}
+
+# Test that completing LINE with the complete command completes to
+# COMPLETE_LINE_RE.
+
+proc test_gdb_complete_cmd_unique { input_line complete_line_re } {
+ global gdb_prompt
+
+ set cmd "complete $input_line"
+ set cmd_re [string_to_regexp $cmd]
+ set test "cmd complete \"$input_line\""
+ gdb_test_multiple $cmd $test {
+ -re "^$cmd_re\r\n$complete_line_re\r\n$gdb_prompt $" {
+ pass $test
+ }
+ }
+}
+
+# Test that completing "CMD_PREFIX + COMPLETION_WORD" with the
+# complete command displays the COMPLETION_LIST completion list. Each
+# entry in the list should be prefixed by CMD_PREFIX.
+
+proc test_gdb_complete_cmd_multiple { cmd_prefix completion_word completion_list start_quote_char end_quote_char } {
+ global gdb_prompt
+
+ set expected_re [make_cmd_completion_list_re $cmd_prefix $completion_list $start_quote_char $end_quote_char]
+ set cmd_re [string_to_regexp "complete $cmd_prefix$completion_word"]
+ set test "cmd complete \"$cmd_prefix$completion_word\""
+ gdb_test_multiple "complete $cmd_prefix$completion_word" $test {
+ -re "^$cmd_re\r\n$expected_re$gdb_prompt $" {
+ pass $test
+ }
+ }
+}
+
+proc test_gdb_complete_menu { line expected_output } {
+
+ set test "menu complete $line"
+# send_gdb "$expr\033?"
+# send_gdb "$expr^\[?"
+ send_gdb "$expr"
+ send_gdb "\x1b"
+ send_gdb "?"
+ gdb_test_multiple "" "$test" {
+ -re "$expected_output" {
+ pass "$test"
+ }
+ }
+}
+
+# Test that completing LINE completes to nothing.
+
+proc test_gdb_complete_none { input_line } {
+ test_gdb_complete_tab_none $input_line
+ test_gdb_complete_cmd_none $input_line
+}
+
+# Test that completing INPUT_LINE completes to COMPLETE_LINE.
+#
+# APPEND_CHAR is the character expected to be appended after
+# EXPECTED_OUTPUT when TAB completing. Normally that's a whitespace,
+# but in some cases it's some other character, like a colon.
+#
+# If MAX_COMPLETIONS is true, then we expect the completion to hit the
+# max-completions limit. Since we're expecting a unique completion
+# match, this will only be visible in the "complete" command output.
+# Tab completion will just auto-complete the only match and won't
+# display a match list.
+
+proc test_gdb_complete_unique { input_line complete_line {append_char " "} {max_completions 0}} {
+ set complete_line_re [string_to_regexp $complete_line]
+ set append_char_re [string_to_regexp $append_char]
+ test_gdb_complete_tab_unique $input_line $complete_line_re $append_char_re
+
+ # Trim INPUT_LINE and COMPLETE LINE, for the case we're completing
+ # a command with leading whitespace. Leading command whitespace
+ # is discarded by GDB.
+ set input_line [string trimleft $input_line]
+ set expected_output_re [string trimleft $complete_line_re]
+ if {$append_char_re != " "} {
+ append expected_output_re $append_char_re
+ }
+ if {$max_completions} {
+ set max_completion_reached_msg \
+ "*** List may be truncated, max-completions reached. ***"
+ set input_line_re \
+ [string_to_regexp $input_line]
+ set max_completion_reached_msg_re \
+ [string_to_regexp $max_completion_reached_msg]
+
+ append expected_output_re \
+ "\r\n$input_line_re $max_completion_reached_msg_re"
+ }
+
+ test_gdb_complete_cmd_unique $input_line $expected_output_re
+}
+
+proc test_gdb_complete_unique_re { input_line complete_line_re {append_char " "} {max_completions 0}} {
+ set append_char_re [string_to_regexp $append_char]
+ test_gdb_complete_tab_unique $input_line $complete_line_re $append_char_re
+
+ # Trim INPUT_LINE and COMPLETE LINE, for the case we're completing
+ # a command with leading whitespace. Leading command whitespace
+ # is discarded by GDB.
+ set input_line [string trimleft $input_line]
+ set expected_output_re [string trimleft $complete_line_re]
+ if {$append_char_re != " "} {
+ append expected_output_re $append_char_re
+ }
+ if {$max_completions} {
+ set max_completion_reached_msg \
+ "*** List may be truncated, max-completions reached. ***"
+ set input_line_re \
+ [string_to_regexp $input_line]
+ set max_completion_reached_msg_re \
+ [string_to_regexp $max_completion_reached_msg]
+
+ append expected_output_re \
+ "\r\n$input_line_re $max_completion_reached_msg_re"
+ }
+
+ test_gdb_complete_cmd_unique $input_line $expected_output_re
+}
+
+# Test that completing "CMD_PREFIX + COMPLETION_WORD" adds
+# ADD_COMPLETED_LINE to the input line, and that it displays
+# COMPLETION_LIST as completion match list. COMPLETION_WORD is the
+# completion word.
+
+proc test_gdb_complete_multiple { cmd_prefix completion_word add_completed_line completion_list {start_quote_char ""} {end_quote_char ""}} {
+ test_gdb_complete_tab_multiple "$cmd_prefix$completion_word" $add_completed_line $completion_list
+ test_gdb_complete_cmd_multiple $cmd_prefix $completion_word $completion_list $start_quote_char $end_quote_char
+}
+
+# Test completing 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}} {
+ if {$end == -1} {
+ set end [string length $completion]
+ }
+
+ for {set i $start} {$i < $end} {incr i} {
+ set line [string range $completion 0 $i]
+ test_gdb_complete_unique "$line" "$completion"
+ }
+}
+
+proc test_complete_prefix_range_input {input completion_re start {end -1}} {
+ if {$end == -1} {
+ set end [string length $input]
+ }
+
+ for {set i $start} {$i < $end} {incr i} {
+ set line [string range $input 0 $i]
+ test_gdb_complete_unique_re "$line" $completion_re
+ }
+}
+
+# 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(".
+
+proc index_after {needle haystack} {
+ set start [string first $needle $haystack]
+ if {$start == -1} {
+ error "could not find \"$needle\" in \"$haystack\""
+ }
+ return [expr $start + [string length $needle]]
+}
+
+# Create a breakpoint using BREAK_COMMAND, and return the number of
+# locations found.
+
+proc create_bp {break_command} {
+ global gdb_prompt
+ global decimal hex
+
+ set found_locations -1
+
+ set test "set breakpoint"
+ gdb_test_multiple "$break_command" $test {
+ -re "\\\(\($decimal\) locations\\\)\r\n$gdb_prompt $" {
+ set found_locations "$expect_out(1,string)"
+ }
+ -re "Breakpoint $decimal at $hex: file .*, line .*$gdb_prompt $" {
+ set found_locations 1
+ }
+ -re "Make breakpoint pending on future shared library load.*y or .n.. $" {
+ send_gdb "n\n"
+ gdb_test_multiple "" "$test (prompt)" {
+ -re "$gdb_prompt $" {
+ }
+ }
+ set found_locations 0
+ }
+ -re "invalid explicit location argument, \[^\r\n\]*\r\n$gdb_prompt $" {
+ set found_locations 0
+ }
+ -re "Function \[^\r\n\]* not defined in \[^\r\n\]*\r\n$gdb_prompt $" {
+ set found_locations 0
+ }
+ }
+ return $found_locations
+}
+
+# Check that trying to create a breakpoint from linespec fails.
+
+proc check_setting_bp_fails {break_command} {
+ with_test_prefix "\"$break_command\" creates no bp locations" {
+ set found_locations [create_bp $break_command]
+ gdb_assert {$found_locations == 0} "matches"
+ if {$found_locations != 0} {
+ delete_breakpoints
+ }
+ }
+}
+
+# Return true if lists A and B have the same elements. Order of
+# elements does not matter.
+
+proc gdb_leq {a b} {
+ return [expr {[lsort $a] eq [lsort $b]}]
+}
+
+# Check that creating the breakpoint at LINESPEC finds the same
+# breakpoint locations as completing LINESPEC. COMPLETION_LIST is
+# expected completion match list.
+
+proc check_bp_locations_match_list {break_command completion_list} {
+ global gdb_prompt
+ global hex
+
+ with_test_prefix "compare \"$break_command\" completion list with bp location list" {
+ set num_locations [create_bp $break_command]
+
+ set found_list ""
+
+ set any "\[^\r\n\]*"
+
+ gdb_test_multiple "info breakpoint \$bpnum" "info breakpoint" {
+ -re "in \(\[^\r\n\]*\) at " {
+ # A function location.
+ set found_location "$expect_out(1,string)"
+ lappend found_list $found_location
+ exp_continue
+ }
+ -re "breakpoint${any}keep${any}y${any}$hex\[ \t]*\(${any}\)\r\n" {
+ # A label location.
+ set found_location "$expect_out(1,string)"
+ lappend found_list $found_location
+ exp_continue
+ }
+ -re "$gdb_prompt $" {
+ }
+ }
+
+ gdb_assert {[gdb_leq $found_list $completion_list]} "matches"
+
+ delete_breakpoints
+ }
+}
+
+# Build linespec and explicit locations out of all the combinations of
+# SOURCES, FUNCTIONS and LABELS, with all combinations of possible
+# quoting and whitespace around separators, and run BODY_LINESPEC and
+# BODY_EXPLICIT in the context of the caller for each combination. A
+# variable named "location" is set in the callers context with the
+# currently iterated location.
+
+proc foreach_location_functions { sources functions body_linespec body_explicit } {
+ global maybe_quoted_list
+ upvar source source
+ upvar function function
+ upvar source_sep source_sep
+ upvar location location
+
+ foreach source $sources {
+ # Test with and without source quoting.
+ foreach sqc $maybe_quoted_list {
+ if {$source == "" && $sqc != ""} {
+ # Invalid combination.
+ continue
+ }
+
+ # Test with and without function quoting.
+ foreach fqc $maybe_quoted_list {
+ # Test known and unknown functions.
+ foreach function $functions {
+ # Linespec version. Test with and without spacing
+ # after the source/colon colon separator.
+ foreach source_sep {"" ":" ": "} {
+ # Skip invalid combinations.
+ if {$source == "" && $source_sep != ""} {
+ continue
+ }
+ if {$source != "" && $source_sep == ""} {
+ continue
+ }
+
+ set location "${sqc}${source}${sqc}${source_sep}${fqc}$function${fqc}"
+ uplevel 1 $body_linespec
+ }
+
+ # Explicit locations version.
+ if {$source != ""} {
+ set loc_src "-source ${sqc}${source}${sqc} "
+ } else {
+ set loc_src ""
+ }
+
+ set location "${loc_src}-function ${fqc}$function${fqc}"
+ uplevel 1 $body_explicit
+ }
+ }
+ }
+ }
+}
+
+# Same as foreach_locations_functions, but also iterate over
+# combinations of labels.
+proc foreach_location_labels { sources functions labels body_linespec body_explicit } {
+ global maybe_quoted_list
+ upvar source source
+ upvar function function
+ upvar label label
+ upvar source_sep source_sep
+ upvar label_sep label_sep
+ upvar location location
+
+ # Test both with a known source file and without a source file
+ # component.
+ foreach_location_functions \
+ $sources \
+ $functions \
+ {
+ # Linespec version. Test various spacing around the label
+ # colon separator.
+ set saved_location ${location}
+ foreach label_sep {":" " :" ": " " : "} {
+ # Test both known and unknown label.
+ foreach label $labels {
+ set location "${saved_location}${label_sep}$label"
+ uplevel 1 $body_linespec
+ }
+ }
+ } \
+ {
+ # Explicit locations version.
+ set saved_location ${location}
+ foreach label $labels {
+ set location "${saved_location} -label $label"
+ uplevel 1 $body_explicit
+ }
+ }
+}