This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[pushed] Comprehensive C++ linespec/completer tests


Now that the "Make strcmp_iw NOT ignore whitespace in the middle of tokens"
patch is in, most of the tests that I had in the 
"C++ debugging improvements: breakpoints, TAB completion, more" series,
in this patch here:
  https://sourceware.org/ml/gdb-patches/2017-06/msg00027.html
started working.  I removed the ones that don't yet (the ones that rely
on C++ wildmatching), and after addressing Keith's review comments, at
<https://sourceware.org/ml/gdb-patches/2017-11/msg00615.html>
I went ahead and checked it in, as below.

>From 8955eb2da31d78690c762748fab3a16832ef1f81 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Fri, 24 Nov 2017 23:41:12 +0000
Subject: [PATCH] Comprehensive C++ linespec/completer tests

Exercises all sorts of aspects fixed by previous patches, going back a
few months.

 - 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.

 - 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           3464

gdb/testsuite/ChangeLog:
2017-11-24  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.
---
 gdb/testsuite/ChangeLog                     |  11 +
 gdb/testsuite/gdb.linespec/cpcompletion.exp | 534 ++++++++++++++++++++++++++++
 gdb/testsuite/gdb.linespec/cpls-hyphen.cc   |  33 ++
 gdb/testsuite/gdb.linespec/cpls.cc          | 386 ++++++++++++++++++++
 gdb/testsuite/gdb.linespec/cpls2.cc         |  46 +++
 gdb/testsuite/gdb.linespec/explicit.exp     | 208 ++++++++++-
 gdb/testsuite/lib/completion-support.exp    | 471 ++++++++++++++++++++++++
 7 files changed, 1682 insertions(+), 7 deletions(-)
 create mode 100644 gdb/testsuite/gdb.linespec/cpcompletion.exp
 create mode 100644 gdb/testsuite/gdb.linespec/cpls-hyphen.cc
 create mode 100644 gdb/testsuite/gdb.linespec/cpls.cc
 create mode 100644 gdb/testsuite/gdb.linespec/cpls2.cc
 create mode 100644 gdb/testsuite/lib/completion-support.exp

diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 8f194c4..469dde1 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,14 @@
+2017-11-24  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.
+
 2017-11-24  Joel Brobecker  <brobecker@adacore.com>
 
 	* gdb.ada/catch_ex.exp, gdb.ada/mi_catch_ex.exp,
diff --git a/gdb/testsuite/gdb.linespec/cpcompletion.exp b/gdb/testsuite/gdb.linespec/cpcompletion.exp
new file mode 100644
index 0000000..873dc78
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/cpcompletion.exp
@@ -0,0 +1,534 @@
+# 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"
+
+# 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 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 {} {
+    foreach cmd_prefix {"b" "b -function"} {
+	foreach qc $completion::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 {} {
+    foreach sqc $completion::maybe_quoted_list {
+	foreach fqc $completion::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 {} {
+    foreach sqc $completion::maybe_quoted_list {
+	foreach fqc $completion::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 {} {
+    # Test with quotes to make sure the end quote char is put at the
+    # right place.
+    foreach qc $completion::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 " "" "" \
+	$completion::keyword_list
+    foreach qc $completion::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} " "" "" \
+	    $completion::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}} {
+	foreach source {"" "cpls.cc"} {
+	    # Test with and without source quoting.
+	    foreach sqc $completion::maybe_quoted_list {
+		if {$source == "" && $sqc != ""} {
+		    # Invalid combination.
+		    continue
+		}
+
+		# Test with and without function quoting.
+		foreach fqc $completion::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
+    }
+}
+
+# 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 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 {} {
+    set explicit_list \
+	[concat $completion::explicit_opts_list $completion::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} " "" "" \
+		$completion::keyword_list
+	} \
+	{
+	    # Explicit locations version.
+	    test_gdb_complete_multiple "b ${location} " "" "" \
+		$explicit_list
+	}
+}
+
+# Same, but after a label.
+
+proc_with_prefix keywords-after-label {} {
+    set explicit_list \
+	[concat $completion::explicit_opts_list $completion::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} " "" "" \
+		$completion::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 {} {
+    # Test with and without quoting.
+    foreach qc $completion::maybe_quoted_list {
+	set line "b ${qc}unknown_file.cc${qc}: "
+	test_gdb_complete_multiple $line "" "" $completion::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
+    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
+    operator<
+    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 0000000..4bd2d9f
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/cpls-hyphen.cc
@@ -0,0 +1,33 @@
+/* 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/>.  */
+
+/* A function in a file whose name has an hyphen.  */
+
+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 0000000..776dd4c
--- /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 0000000..a8f1319
--- /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 65d78ca..9cf0162 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 $completion::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,201 @@ namespace eval $testfile {
 	    }
 	}
 
+	with_test_prefix "complete unique label name" {
+	    foreach qc $completion::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"
+	    "-source"
+	    "if"
+	    "task"
+	    "thread"
+	}
+	foreach what { "-function" "-label" "-line" "-source" } {
+	    with_test_prefix "complete after $what" {
+		if {$what != "-line"} {
+		    set w "$what argument "
+		    test_gdb_complete_multiple \
+			"b $w" "" "" $completions_list
+		    test_gdb_complete_unique \
+			"b $w thr" \
+			"b $w thread"
+		    test_gdb_complete_unique \
+			"b $w -fun" \
+			"b $w -function"
+		} else {
+		    # After -line, we expect a number / offset.
+		    foreach line {"10" "+10" "-10"} {
+			set w "-line $line"
+			test_gdb_complete_multiple \
+			    "b $w " "" "" $completions_list
+			test_gdb_complete_unique \
+			    "b $w thr" \
+			    "b $w thread"
+			test_gdb_complete_unique \
+			    "b $w -fun" \
+			    "b $w -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.
 
+	# The following completion tests 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"
+	    "-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 0000000..70e6aec
--- /dev/null
+++ b/gdb/testsuite/lib/completion-support.exp
@@ -0,0 +1,471 @@
+# 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.
+
+# Any variable or procedure in the namespace whose name starts with
+# "_" is private to the module.  Do not use these.
+
+namespace eval completion {
+    variable bell_re "\\\x07"
+
+    # List of all quote chars.
+    variable all_quotes_list {"'" "\""}
+
+    # List of all quote chars, including no-quote at all.
+    variable maybe_quoted_list {"" "'" "\""}
+
+    variable keyword_list {"if" "task" "thread"}
+
+    variable explicit_opts_list \
+	{"-function" "-label" "-line" "-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 } {
+    set line_re [string_to_regexp $line]
+
+    set test "tab complete \"$line\""
+    send_gdb "$line\t"
+    gdb_test_multiple "" "$test" {
+	-re "^$line_re$completion::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 it displays the completion matches in
+# COMPLETION_LIST.
+
+proc test_gdb_complete_tab_multiple { input_line add_completed_line \
+					  completion_list } {
+    global gdb_prompt
+
+    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}${completion::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
+	}
+    }
+}
+
+# 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_RE.
+#
+# 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.
+#
+# Note: usually it's more convenient to pass a literal string instead
+# of a regular expression (as COMPLETE_LINE_RE).  See
+# test_gdb_complete_unique below.
+
+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
+}
+
+# Like TEST_GDB_COMPLETE_UNIQUE_RE, but COMPLETE_LINE is a string, not
+# a regular expression.
+
+proc test_gdb_complete_unique { input_line complete_line {append_char " "} {max_completions 0}} {
+    set complete_line_re [string_to_regexp $complete_line]
+    test_gdb_complete_unique_re $input_line $complete_line_re $append_char $max_completions
+}
+
+# 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 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}} {
+    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"
+    }
+}
+
+# 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 completion::_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
+}
+
+# Return true if lists A and B have the same elements.  Order of
+# elements does not matter.
+
+proc completion::_leq {a b} {
+    return [expr {[lsort $a] eq [lsort $b]}]
+}
+
+# Check that trying to create a breakpoint using BREAK_COMMAND fails.
+
+proc check_setting_bp_fails {break_command} {
+    with_test_prefix "\"$break_command\" creates no bp locations" {
+	set found_locations [completion::_create_bp $break_command]
+	gdb_assert {$found_locations == 0} "matches"
+	if {$found_locations != 0} {
+	    delete_breakpoints
+	}
+    }
+}
+
+# Check that creating the breakpoint using BREAK_COMMAND finds the
+# same breakpoint locations as completing BREAK_COMMAND.
+# COMPLETION_LIST is the 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 [completion::_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 {[completion::_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 } {
+    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 $completion::maybe_quoted_list {
+	    if {$source == "" && $sqc != ""} {
+		# Invalid combination.
+		continue
+	    }
+
+	    # Test with and without function quoting.
+	    foreach fqc $completion::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 } {
+    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
+	    }
+	}
+}
-- 
2.5.5


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]