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.
This commit is contained in:
parent
0662b6a7c1
commit
8955eb2da3
@ -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,
|
||||
|
534
gdb/testsuite/gdb.linespec/cpcompletion.exp
Normal file
534
gdb/testsuite/gdb.linespec/cpcompletion.exp
Normal file
@ -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
|
33
gdb/testsuite/gdb.linespec/cpls-hyphen.cc
Normal file
33
gdb/testsuite/gdb.linespec/cpls-hyphen.cc
Normal file
@ -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;
|
||||
}
|
||||
}
|
386
gdb/testsuite/gdb.linespec/cpls.cc
Normal file
386
gdb/testsuite/gdb.linespec/cpls.cc
Normal file
@ -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;
|
||||
}
|
46
gdb/testsuite/gdb.linespec/cpls2.cc
Normal file
46
gdb/testsuite/gdb.linespec/cpls2.cc
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -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.
|
||||
|
||||
|
471
gdb/testsuite/lib/completion-support.exp
Normal file
471
gdb/testsuite/lib/completion-support.exp
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user